Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / gl / gl_surface_win.cc
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.
4
5 #include "ui/gl/gl_surface.h"
6
7 #include <dwmapi.h>
8
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"
23
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
29
30 namespace gfx {
31
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();
38
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;
46
47  private:
48   gfx::AcceleratedWidget window_;
49   HDC device_context_;
50
51   DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
52 };
53
54 class DWMVSyncProvider : public VSyncProvider {
55  public:
56   explicit DWMVSyncProvider() {}
57
58   virtual ~DWMVSyncProvider() {}
59
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;
67
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));
76     }
77
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);
86     }
87   }
88
89  private:
90   DISALLOW_COPY_AND_ASSIGN(DWMVSyncProvider);
91 };
92
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;
101       }
102       break;
103     case kGLImplementationEGLGLES2:
104       if (!GLSurfaceEGL::InitializeOneOff()) {
105         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
106         return false;
107       }
108       break;
109   }
110   return true;
111 }
112
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);
119 }
120
121 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
122   Destroy();
123 }
124
125 bool NativeViewGLSurfaceOSMesa::Initialize() {
126   if (!GLSurfaceOSMesa::Initialize())
127     return false;
128
129   device_context_ = GetDC(window_);
130   return true;
131 }
132
133 void NativeViewGLSurfaceOSMesa::Destroy() {
134   if (window_ && device_context_)
135     ReleaseDC(window_, device_context_);
136
137   device_context_ = NULL;
138
139   GLSurfaceOSMesa::Destroy();
140 }
141
142 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
143   return false;
144 }
145
146 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
147   DCHECK(device_context_);
148
149   gfx::Size size = GetSize();
150
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;
163
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);
178
179   return true;
180 }
181
182 bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
183   return true;
184 }
185
186 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
187     int x, int y, int width, int height) {
188   DCHECK(device_context_);
189
190   gfx::Size size = GetSize();
191
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;
204
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);
219
220   return true;
221 }
222
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;
232
233       return surface;
234     }
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;
244
245       return surface;
246     }
247     case kGLImplementationDesktopGL: {
248       scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
249           window));
250       if (!surface->Initialize())
251         return NULL;
252
253       return surface;
254     }
255     case kGLImplementationMockGL:
256       return new GLSurfaceStub;
257     default:
258       NOTREACHED();
259       return NULL;
260   }
261 }
262
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;
272
273       return surface;
274     }
275     case kGLImplementationEGLGLES2: {
276       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
277       if (!surface->Initialize())
278         return NULL;
279
280       return surface;
281     }
282     case kGLImplementationDesktopGL: {
283       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
284       if (!surface->Initialize())
285         return NULL;
286
287       return surface;
288     }
289     case kGLImplementationMockGL:
290       return new GLSurfaceStub;
291     default:
292       NOTREACHED();
293       return NULL;
294   }
295 }
296
297 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
298   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11))
299     return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
300
301   return EGL_DEFAULT_DISPLAY;
302 }
303
304 }  // namespace gfx