Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / gl / gl_surface_win.cc
blob8d55009a0efc0662c4d4c43d2254fa307c1b2f2e
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/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/trace_event/trace_event.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
29 namespace gfx {
31 // This OSMesa GL surface can use GDI to swap the contents of the buffer to a
32 // view.
33 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
34 public:
35 explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
36 ~NativeViewGLSurfaceOSMesa() override;
38 // Implement subset of GLSurface.
39 bool Initialize() override;
40 void Destroy() override;
41 bool IsOffscreen() override;
42 bool SwapBuffers() override;
43 bool SupportsPostSubBuffer() override;
44 bool PostSubBuffer(int x, int y, int width, int height) override;
46 private:
47 gfx::AcceleratedWidget window_;
48 HDC device_context_;
50 DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
53 class WinVSyncProvider : public VSyncProvider {
54 public:
55 explicit WinVSyncProvider(gfx::AcceleratedWidget window) :
56 window_(window)
58 use_dwm_ = (base::win::GetVersion() >= base::win::VERSION_WIN7);
61 ~WinVSyncProvider() override {}
63 void GetVSyncParameters(const UpdateVSyncCallback& callback) override {
64 TRACE_EVENT0("gpu", "WinVSyncProvider::GetVSyncParameters");
66 base::TimeTicks timebase;
67 base::TimeDelta interval;
68 bool dwm_active = false;
70 // Query the DWM timing info first if available. This will provide the most
71 // precise values.
72 if (use_dwm_) {
73 DWM_TIMING_INFO timing_info;
74 timing_info.cbSize = sizeof(timing_info);
75 HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
76 if (result == S_OK) {
77 dwm_active = true;
78 if (gfx::FrameTime::TimestampsAreHighRes()) {
79 // qpcRefreshPeriod is very accurate but noisy, and must be used with
80 // a high resolution timebase to avoid frequently missing Vsync.
81 timebase = gfx::FrameTime::FromQPCValue(
82 static_cast<LONGLONG>(timing_info.qpcVBlank));
83 interval = base::TimeDelta::FromQPCValue(
84 static_cast<LONGLONG>(timing_info.qpcRefreshPeriod));
85 } else if (timing_info.rateRefresh.uiDenominator > 0 &&
86 timing_info.rateRefresh.uiNumerator > 0) {
87 // If FrameTime is not high resolution, we do not want to translate
88 // the QPC value provided by DWM into the low-resolution timebase,
89 // which would be error prone and jittery. As a fallback, we assume
90 // the timebase is zero and use rateRefresh, which may be rounded but
91 // isn't noisy like qpcRefreshPeriod, instead. The fact that we don't
92 // have a timebase here may lead to brief periods of jank when our
93 // scheduling becomes offset from the hardware vsync.
95 // Swap the numerator/denominator to convert frequency to period.
96 interval = base::TimeDelta::FromMicroseconds(
97 timing_info.rateRefresh.uiDenominator *
98 base::Time::kMicrosecondsPerSecond /
99 timing_info.rateRefresh.uiNumerator);
104 if (!dwm_active) {
105 // When DWM compositing is active all displays are normalized to the
106 // refresh rate of the primary display, and won't composite any faster.
107 // If DWM compositing is disabled, though, we can use the refresh rates
108 // reported by each display, which will help systems that have mis-matched
109 // displays that run at different frequencies.
110 HMONITOR monitor = MonitorFromWindow(window_, MONITOR_DEFAULTTONEAREST);
111 MONITORINFOEX monitor_info;
112 monitor_info.cbSize = sizeof(MONITORINFOEX);
113 BOOL result = GetMonitorInfo(monitor, &monitor_info);
114 if (result) {
115 DEVMODE display_info;
116 display_info.dmSize = sizeof(DEVMODE);
117 display_info.dmDriverExtra = 0;
118 result = EnumDisplaySettings(monitor_info.szDevice,
119 ENUM_CURRENT_SETTINGS, &display_info);
120 if (result && display_info.dmDisplayFrequency > 1) {
121 interval = base::TimeDelta::FromMicroseconds(
122 (1.0 / static_cast<double>(display_info.dmDisplayFrequency)) *
123 base::Time::kMicrosecondsPerSecond);
128 if (interval.ToInternalValue() != 0) {
129 callback.Run(timebase, interval);
133 private:
134 DISALLOW_COPY_AND_ASSIGN(WinVSyncProvider);
136 gfx::AcceleratedWidget window_;
137 bool use_dwm_;
140 // Helper routine that does one-off initialization like determining the
141 // pixel format.
142 bool GLSurface::InitializeOneOffInternal() {
143 switch (GetGLImplementation()) {
144 case kGLImplementationDesktopGL:
145 if (!GLSurfaceWGL::InitializeOneOff()) {
146 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
147 return false;
149 break;
150 case kGLImplementationEGLGLES2:
151 if (!GLSurfaceEGL::InitializeOneOff()) {
152 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
153 return false;
155 break;
157 return true;
160 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
161 gfx::AcceleratedWidget window)
162 : GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, gfx::Size(1, 1)),
163 window_(window),
164 device_context_(NULL) {
165 DCHECK(window);
168 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
169 Destroy();
172 bool NativeViewGLSurfaceOSMesa::Initialize() {
173 if (!GLSurfaceOSMesa::Initialize())
174 return false;
176 device_context_ = GetDC(window_);
177 return true;
180 void NativeViewGLSurfaceOSMesa::Destroy() {
181 if (window_ && device_context_)
182 ReleaseDC(window_, device_context_);
184 device_context_ = NULL;
186 GLSurfaceOSMesa::Destroy();
189 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
190 return false;
193 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
194 DCHECK(device_context_);
196 gfx::Size size = GetSize();
198 // Note: negating the height below causes GDI to treat the bitmap data as row
199 // 0 being at the top.
200 BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
201 info.bV4Width = size.width();
202 info.bV4Height = -size.height();
203 info.bV4Planes = 1;
204 info.bV4BitCount = 32;
205 info.bV4V4Compression = BI_BITFIELDS;
206 info.bV4RedMask = 0x000000FF;
207 info.bV4GreenMask = 0x0000FF00;
208 info.bV4BlueMask = 0x00FF0000;
209 info.bV4AlphaMask = 0xFF000000;
211 // Copy the back buffer to the window's device context. Do not check whether
212 // StretchDIBits succeeds or not. It will fail if the window has been
213 // destroyed but it is preferable to allow rendering to silently fail if the
214 // window is destroyed. This is because the primary application of this
215 // class of GLContext is for testing and we do not want every GL related ui /
216 // browser test to become flaky if there is a race condition between GL
217 // context destruction and window destruction.
218 StretchDIBits(device_context_,
219 0, 0, size.width(), size.height(),
220 0, 0, size.width(), size.height(),
221 GetHandle(),
222 reinterpret_cast<BITMAPINFO*>(&info),
223 DIB_RGB_COLORS,
224 SRCCOPY);
226 return true;
229 bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
230 return true;
233 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
234 int x, int y, int width, int height) {
235 DCHECK(device_context_);
237 gfx::Size size = GetSize();
239 // Note: negating the height below causes GDI to treat the bitmap data as row
240 // 0 being at the top.
241 BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
242 info.bV4Width = size.width();
243 info.bV4Height = -size.height();
244 info.bV4Planes = 1;
245 info.bV4BitCount = 32;
246 info.bV4V4Compression = BI_BITFIELDS;
247 info.bV4RedMask = 0x000000FF;
248 info.bV4GreenMask = 0x0000FF00;
249 info.bV4BlueMask = 0x00FF0000;
250 info.bV4AlphaMask = 0xFF000000;
252 // Copy the back buffer to the window's device context. Do not check whether
253 // StretchDIBits succeeds or not. It will fail if the window has been
254 // destroyed but it is preferable to allow rendering to silently fail if the
255 // window is destroyed. This is because the primary application of this
256 // class of GLContext is for testing and we do not want every GL related ui /
257 // browser test to become flaky if there is a race condition between GL
258 // context destruction and window destruction.
259 StretchDIBits(device_context_,
260 x, size.height() - y - height, width, height,
261 x, y, width, height,
262 GetHandle(),
263 reinterpret_cast<BITMAPINFO*>(&info),
264 DIB_RGB_COLORS,
265 SRCCOPY);
267 return true;
270 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
271 gfx::AcceleratedWidget window) {
272 TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
273 switch (GetGLImplementation()) {
274 case kGLImplementationOSMesaGL: {
275 scoped_refptr<GLSurface> surface(
276 new NativeViewGLSurfaceOSMesa(window));
277 if (!surface->Initialize())
278 return NULL;
280 return surface;
282 case kGLImplementationEGLGLES2: {
283 DCHECK(window != gfx::kNullAcceleratedWidget);
284 scoped_refptr<NativeViewGLSurfaceEGL> surface(
285 new NativeViewGLSurfaceEGL(window));
286 scoped_ptr<VSyncProvider> sync_provider;
287 sync_provider.reset(new WinVSyncProvider(window));
288 if (!surface->Initialize(sync_provider.Pass()))
289 return NULL;
291 return surface;
293 case kGLImplementationDesktopGL: {
294 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
295 window));
296 if (!surface->Initialize())
297 return NULL;
299 return surface;
301 case kGLImplementationMockGL:
302 return new GLSurfaceStub;
303 default:
304 NOTREACHED();
305 return NULL;
309 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
310 const gfx::Size& size) {
311 TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
312 switch (GetGLImplementation()) {
313 case kGLImplementationOSMesaGL: {
314 scoped_refptr<GLSurface> surface(
315 new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
316 if (!surface->Initialize())
317 return NULL;
319 return surface;
321 case kGLImplementationEGLGLES2: {
322 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
323 if (!surface->Initialize())
324 return NULL;
326 return surface;
328 case kGLImplementationDesktopGL: {
329 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
330 if (!surface->Initialize())
331 return NULL;
333 return surface;
335 case kGLImplementationMockGL:
336 return new GLSurfaceStub;
337 default:
338 NOTREACHED();
339 return NULL;
343 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
344 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
345 switches::kDisableD3D11) ||
346 base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp))
347 return GetDC(NULL);
348 return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
351 } // namespace gfx