Update metrics verification for dev-proxy.
[chromium-blink-merge.git] / ui / gl / gl_surface_win.cc
blob3cde3ea9c7645ffd1dd9d20cf5ae19f603ccd9be
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 "ui/gfx/frame_time.h"
15 #include "ui/gfx/native_widget_types.h"
16 #include "ui/gl/gl_bindings.h"
17 #include "ui/gl/gl_implementation.h"
18 #include "ui/gl/gl_surface_egl.h"
19 #include "ui/gl/gl_surface_osmesa.h"
20 #include "ui/gl/gl_surface_stub.h"
21 #include "ui/gl/gl_surface_wgl.h"
23 // From ANGLE's egl/eglext.h.
24 #if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
25 #define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
26 reinterpret_cast<EGLNativeDisplayType>(-2)
27 #endif
28 #if !defined(EGL_PLATFORM_ANGLE_ANGLE)
29 #define EGL_PLATFORM_ANGLE_ANGLE 0x3201
30 #endif
31 #if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
32 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
33 #endif
34 #if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
35 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
36 #endif
38 namespace gfx {
40 // This OSMesa GL surface can use GDI to swap the contents of the buffer to a
41 // view.
42 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
43 public:
44 explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
45 virtual ~NativeViewGLSurfaceOSMesa();
47 // Implement subset of GLSurface.
48 virtual bool Initialize() OVERRIDE;
49 virtual void Destroy() OVERRIDE;
50 virtual bool IsOffscreen() OVERRIDE;
51 virtual bool SwapBuffers() OVERRIDE;
52 virtual bool SupportsPostSubBuffer() OVERRIDE;
53 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
55 private:
56 gfx::AcceleratedWidget window_;
57 HDC device_context_;
59 DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
62 class DWMVSyncProvider : public VSyncProvider {
63 public:
64 explicit DWMVSyncProvider() {}
66 virtual ~DWMVSyncProvider() {}
68 virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) {
69 TRACE_EVENT0("gpu", "DWMVSyncProvider::GetVSyncParameters");
70 DWM_TIMING_INFO timing_info;
71 timing_info.cbSize = sizeof(timing_info);
72 HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
73 if (result != S_OK)
74 return;
76 base::TimeTicks timebase;
77 // If FrameTime is not high resolution, we do not want to translate the
78 // QPC value provided by DWM into the low-resolution timebase, which
79 // would be error prone and jittery. As a fallback, we assume the timebase
80 // is zero.
81 if (gfx::FrameTime::TimestampsAreHighRes()) {
82 timebase = gfx::FrameTime::FromQPCValue(
83 static_cast<LONGLONG>(timing_info.qpcVBlank));
86 // Swap the numerator/denominator to convert frequency to period.
87 if (timing_info.rateRefresh.uiDenominator > 0 &&
88 timing_info.rateRefresh.uiNumerator > 0) {
89 base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
90 timing_info.rateRefresh.uiDenominator *
91 base::Time::kMicrosecondsPerSecond /
92 timing_info.rateRefresh.uiNumerator);
93 callback.Run(timebase, interval);
97 private:
98 DISALLOW_COPY_AND_ASSIGN(DWMVSyncProvider);
101 // Helper routine that does one-off initialization like determining the
102 // pixel format.
103 bool GLSurface::InitializeOneOffInternal() {
104 switch (GetGLImplementation()) {
105 case kGLImplementationDesktopGL:
106 if (!GLSurfaceWGL::InitializeOneOff()) {
107 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
108 return false;
110 break;
111 case kGLImplementationEGLGLES2:
112 if (!GLSurfaceEGL::InitializeOneOff()) {
113 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
114 return false;
116 break;
118 return true;
121 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
122 gfx::AcceleratedWidget window)
123 : GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, gfx::Size(1, 1)),
124 window_(window),
125 device_context_(NULL) {
126 DCHECK(window);
129 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
130 Destroy();
133 bool NativeViewGLSurfaceOSMesa::Initialize() {
134 if (!GLSurfaceOSMesa::Initialize())
135 return false;
137 device_context_ = GetDC(window_);
138 return true;
141 void NativeViewGLSurfaceOSMesa::Destroy() {
142 if (window_ && device_context_)
143 ReleaseDC(window_, device_context_);
145 device_context_ = NULL;
147 GLSurfaceOSMesa::Destroy();
150 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
151 return false;
154 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
155 DCHECK(device_context_);
157 gfx::Size size = GetSize();
159 // Note: negating the height below causes GDI to treat the bitmap data as row
160 // 0 being at the top.
161 BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
162 info.bV4Width = size.width();
163 info.bV4Height = -size.height();
164 info.bV4Planes = 1;
165 info.bV4BitCount = 32;
166 info.bV4V4Compression = BI_BITFIELDS;
167 info.bV4RedMask = 0x000000FF;
168 info.bV4GreenMask = 0x0000FF00;
169 info.bV4BlueMask = 0x00FF0000;
170 info.bV4AlphaMask = 0xFF000000;
172 // Copy the back buffer to the window's device context. Do not check whether
173 // StretchDIBits succeeds or not. It will fail if the window has been
174 // destroyed but it is preferable to allow rendering to silently fail if the
175 // window is destroyed. This is because the primary application of this
176 // class of GLContext is for testing and we do not want every GL related ui /
177 // browser test to become flaky if there is a race condition between GL
178 // context destruction and window destruction.
179 StretchDIBits(device_context_,
180 0, 0, size.width(), size.height(),
181 0, 0, size.width(), size.height(),
182 GetHandle(),
183 reinterpret_cast<BITMAPINFO*>(&info),
184 DIB_RGB_COLORS,
185 SRCCOPY);
187 return true;
190 bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
191 return true;
194 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
195 int x, int y, int width, int height) {
196 DCHECK(device_context_);
198 gfx::Size size = GetSize();
200 // Note: negating the height below causes GDI to treat the bitmap data as row
201 // 0 being at the top.
202 BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
203 info.bV4Width = size.width();
204 info.bV4Height = -size.height();
205 info.bV4Planes = 1;
206 info.bV4BitCount = 32;
207 info.bV4V4Compression = BI_BITFIELDS;
208 info.bV4RedMask = 0x000000FF;
209 info.bV4GreenMask = 0x0000FF00;
210 info.bV4BlueMask = 0x00FF0000;
211 info.bV4AlphaMask = 0xFF000000;
213 // Copy the back buffer to the window's device context. Do not check whether
214 // StretchDIBits succeeds or not. It will fail if the window has been
215 // destroyed but it is preferable to allow rendering to silently fail if the
216 // window is destroyed. This is because the primary application of this
217 // class of GLContext is for testing and we do not want every GL related ui /
218 // browser test to become flaky if there is a race condition between GL
219 // context destruction and window destruction.
220 StretchDIBits(device_context_,
221 x, size.height() - y - height, width, height,
222 x, y, width, height,
223 GetHandle(),
224 reinterpret_cast<BITMAPINFO*>(&info),
225 DIB_RGB_COLORS,
226 SRCCOPY);
228 return true;
231 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
232 gfx::AcceleratedWidget window) {
233 TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
234 switch (GetGLImplementation()) {
235 case kGLImplementationOSMesaGL: {
236 scoped_refptr<GLSurface> surface(
237 new NativeViewGLSurfaceOSMesa(window));
238 if (!surface->Initialize())
239 return NULL;
241 return surface;
243 case kGLImplementationEGLGLES2: {
244 DCHECK(window != gfx::kNullAcceleratedWidget);
245 scoped_refptr<NativeViewGLSurfaceEGL> surface(
246 new NativeViewGLSurfaceEGL(window));
247 scoped_ptr<VSyncProvider> sync_provider;
248 if (base::win::GetVersion() >= base::win::VERSION_VISTA)
249 sync_provider.reset(new DWMVSyncProvider);
250 if (!surface->Initialize(sync_provider.Pass()))
251 return NULL;
253 return surface;
255 case kGLImplementationDesktopGL: {
256 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
257 window));
258 if (!surface->Initialize())
259 return NULL;
261 return surface;
263 case kGLImplementationMockGL:
264 return new GLSurfaceStub;
265 default:
266 NOTREACHED();
267 return NULL;
271 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
272 const gfx::Size& size) {
273 TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
274 switch (GetGLImplementation()) {
275 case kGLImplementationOSMesaGL: {
276 scoped_refptr<GLSurface> surface(
277 new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
278 if (!surface->Initialize())
279 return NULL;
281 return surface;
283 case kGLImplementationEGLGLES2: {
284 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
285 if (!surface->Initialize())
286 return NULL;
288 return surface;
290 case kGLImplementationDesktopGL: {
291 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
292 if (!surface->Initialize())
293 return NULL;
295 return surface;
297 case kGLImplementationMockGL:
298 return new GLSurfaceStub;
299 default:
300 NOTREACHED();
301 return NULL;
305 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
306 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11) ||
307 CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp))
308 return GetDC(NULL);
309 return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
312 } // namespace gfx