Fix crash on key events in touchview.
[chromium-blink-merge.git] / ui / gl / gl_surface_win.cc
blobc0a223b76082056c42a2175ce8254ac90d1a0e35
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gl/gl_surface.h"
7 #include <dwmapi.h>
9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/win/windows_version.h"
14 #include "third_party/mesa/src/include/GL/osmesa.h"
15 #include "ui/gfx/frame_time.h"
16 #include "ui/gfx/native_widget_types.h"
17 #include "ui/gl/gl_bindings.h"
18 #include "ui/gl/gl_implementation.h"
19 #include "ui/gl/gl_surface_egl.h"
20 #include "ui/gl/gl_surface_osmesa.h"
21 #include "ui/gl/gl_surface_stub.h"
22 #include "ui/gl/gl_surface_wgl.h"
24 // From ANGLE's egl/eglext.h.
25 #if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
26 #define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
27 reinterpret_cast<EGLNativeDisplayType>(-2)
28 #endif
30 namespace gfx {
32 // This OSMesa GL surface can use GDI to swap the contents of the buffer to a
33 // view.
34 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
35 public:
36 explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
37 virtual ~NativeViewGLSurfaceOSMesa();
39 // Implement subset of GLSurface.
40 virtual bool Initialize() OVERRIDE;
41 virtual void Destroy() OVERRIDE;
42 virtual bool IsOffscreen() OVERRIDE;
43 virtual bool SwapBuffers() OVERRIDE;
44 virtual bool SupportsPostSubBuffer() OVERRIDE;
45 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
47 private:
48 gfx::AcceleratedWidget window_;
49 HDC device_context_;
51 DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
54 class DWMVSyncProvider : public VSyncProvider {
55 public:
56 explicit DWMVSyncProvider() {}
58 virtual ~DWMVSyncProvider() {}
60 virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) {
61 TRACE_EVENT0("gpu", "DWMVSyncProvider::GetVSyncParameters");
62 DWM_TIMING_INFO timing_info;
63 timing_info.cbSize = sizeof(timing_info);
64 HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
65 if (result != S_OK)
66 return;
68 base::TimeTicks timebase;
69 // If FrameTime is not high resolution, we do not want to translate the
70 // QPC value provided by DWM into the low-resolution timebase, which
71 // would be error prone and jittery. As a fallback, we assume the timebase
72 // is zero.
73 if (gfx::FrameTime::TimestampsAreHighRes()) {
74 timebase = gfx::FrameTime::FromQPCValue(
75 static_cast<LONGLONG>(timing_info.qpcVBlank));
78 // Swap the numerator/denominator to convert frequency to period.
79 if (timing_info.rateRefresh.uiDenominator > 0 &&
80 timing_info.rateRefresh.uiNumerator > 0) {
81 base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
82 timing_info.rateRefresh.uiDenominator *
83 base::Time::kMicrosecondsPerSecond /
84 timing_info.rateRefresh.uiNumerator);
85 callback.Run(timebase, interval);
89 private:
90 DISALLOW_COPY_AND_ASSIGN(DWMVSyncProvider);
93 // Helper routine that does one-off initialization like determining the
94 // pixel format.
95 bool GLSurface::InitializeOneOffInternal() {
96 switch (GetGLImplementation()) {
97 case kGLImplementationDesktopGL:
98 if (!GLSurfaceWGL::InitializeOneOff()) {
99 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
100 return false;
102 break;
103 case kGLImplementationEGLGLES2:
104 if (!GLSurfaceEGL::InitializeOneOff()) {
105 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
106 return false;
108 break;
110 return true;
113 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
114 gfx::AcceleratedWidget window)
115 : GLSurfaceOSMesa(OSMESA_RGBA, gfx::Size(1, 1)),
116 window_(window),
117 device_context_(NULL) {
118 DCHECK(window);
121 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
122 Destroy();
125 bool NativeViewGLSurfaceOSMesa::Initialize() {
126 if (!GLSurfaceOSMesa::Initialize())
127 return false;
129 device_context_ = GetDC(window_);
130 return true;
133 void NativeViewGLSurfaceOSMesa::Destroy() {
134 if (window_ && device_context_)
135 ReleaseDC(window_, device_context_);
137 device_context_ = NULL;
139 GLSurfaceOSMesa::Destroy();
142 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
143 return false;
146 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
147 DCHECK(device_context_);
149 gfx::Size size = GetSize();
151 // Note: negating the height below causes GDI to treat the bitmap data as row
152 // 0 being at the top.
153 BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
154 info.bV4Width = size.width();
155 info.bV4Height = -size.height();
156 info.bV4Planes = 1;
157 info.bV4BitCount = 32;
158 info.bV4V4Compression = BI_BITFIELDS;
159 info.bV4RedMask = 0x000000FF;
160 info.bV4GreenMask = 0x0000FF00;
161 info.bV4BlueMask = 0x00FF0000;
162 info.bV4AlphaMask = 0xFF000000;
164 // Copy the back buffer to the window's device context. Do not check whether
165 // StretchDIBits succeeds or not. It will fail if the window has been
166 // destroyed but it is preferable to allow rendering to silently fail if the
167 // window is destroyed. This is because the primary application of this
168 // class of GLContext is for testing and we do not want every GL related ui /
169 // browser test to become flaky if there is a race condition between GL
170 // context destruction and window destruction.
171 StretchDIBits(device_context_,
172 0, 0, size.width(), size.height(),
173 0, 0, size.width(), size.height(),
174 GetHandle(),
175 reinterpret_cast<BITMAPINFO*>(&info),
176 DIB_RGB_COLORS,
177 SRCCOPY);
179 return true;
182 bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
183 return true;
186 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
187 int x, int y, int width, int height) {
188 DCHECK(device_context_);
190 gfx::Size size = GetSize();
192 // Note: negating the height below causes GDI to treat the bitmap data as row
193 // 0 being at the top.
194 BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
195 info.bV4Width = size.width();
196 info.bV4Height = -size.height();
197 info.bV4Planes = 1;
198 info.bV4BitCount = 32;
199 info.bV4V4Compression = BI_BITFIELDS;
200 info.bV4RedMask = 0x000000FF;
201 info.bV4GreenMask = 0x0000FF00;
202 info.bV4BlueMask = 0x00FF0000;
203 info.bV4AlphaMask = 0xFF000000;
205 // Copy the back buffer to the window's device context. Do not check whether
206 // StretchDIBits succeeds or not. It will fail if the window has been
207 // destroyed but it is preferable to allow rendering to silently fail if the
208 // window is destroyed. This is because the primary application of this
209 // class of GLContext is for testing and we do not want every GL related ui /
210 // browser test to become flaky if there is a race condition between GL
211 // context destruction and window destruction.
212 StretchDIBits(device_context_,
213 x, size.height() - y - height, width, height,
214 x, y, width, height,
215 GetHandle(),
216 reinterpret_cast<BITMAPINFO*>(&info),
217 DIB_RGB_COLORS,
218 SRCCOPY);
220 return true;
223 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
224 gfx::AcceleratedWidget window) {
225 TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
226 switch (GetGLImplementation()) {
227 case kGLImplementationOSMesaGL: {
228 scoped_refptr<GLSurface> surface(
229 new NativeViewGLSurfaceOSMesa(window));
230 if (!surface->Initialize())
231 return NULL;
233 return surface;
235 case kGLImplementationEGLGLES2: {
236 DCHECK(window != gfx::kNullAcceleratedWidget);
237 scoped_refptr<NativeViewGLSurfaceEGL> surface(
238 new NativeViewGLSurfaceEGL(window));
239 scoped_ptr<VSyncProvider> sync_provider;
240 if (base::win::GetVersion() >= base::win::VERSION_VISTA)
241 sync_provider.reset(new DWMVSyncProvider);
242 if (!surface->Initialize(sync_provider.Pass()))
243 return NULL;
245 return surface;
247 case kGLImplementationDesktopGL: {
248 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
249 window));
250 if (!surface->Initialize())
251 return NULL;
253 return surface;
255 case kGLImplementationMockGL:
256 return new GLSurfaceStub;
257 default:
258 NOTREACHED();
259 return NULL;
263 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
264 const gfx::Size& size) {
265 TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
266 switch (GetGLImplementation()) {
267 case kGLImplementationOSMesaGL: {
268 scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA,
269 size));
270 if (!surface->Initialize())
271 return NULL;
273 return surface;
275 case kGLImplementationEGLGLES2: {
276 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
277 if (!surface->Initialize())
278 return NULL;
280 return surface;
282 case kGLImplementationDesktopGL: {
283 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
284 if (!surface->Initialize())
285 return NULL;
287 return surface;
289 case kGLImplementationMockGL:
290 return new GLSurfaceStub;
291 default:
292 NOTREACHED();
293 return NULL;
297 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
298 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11))
299 return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
301 return EGL_DEFAULT_DISPLAY;
304 } // namespace gfx