- add sources.
[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/debug/trace_event.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/win/windows_version.h"
13 #include "third_party/mesa/src/include/GL/osmesa.h"
14 #include "ui/gfx/frame_time.h"
15 #include "ui/gl/gl_bindings.h"
16 #include "ui/gl/gl_implementation.h"
17 #include "ui/gl/gl_surface_egl.h"
18 #include "ui/gl/gl_surface_osmesa.h"
19 #include "ui/gl/gl_surface_stub.h"
20 #include "ui/gl/gl_surface_wgl.h"
21
22 namespace gfx {
23
24 // This OSMesa GL surface can use GDI to swap the contents of the buffer to a
25 // view.
26 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
27  public:
28   explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
29   virtual ~NativeViewGLSurfaceOSMesa();
30
31   // Implement subset of GLSurface.
32   virtual bool Initialize() OVERRIDE;
33   virtual void Destroy() OVERRIDE;
34   virtual bool IsOffscreen() OVERRIDE;
35   virtual bool SwapBuffers() OVERRIDE;
36   virtual std::string GetExtensions() OVERRIDE;
37   virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
38
39  private:
40   gfx::AcceleratedWidget window_;
41   HDC device_context_;
42
43   DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
44 };
45
46 class DWMVSyncProvider : public VSyncProvider {
47  public:
48   explicit DWMVSyncProvider() {}
49
50   virtual ~DWMVSyncProvider() {}
51
52   virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) {
53     TRACE_EVENT0("gpu", "DWMVSyncProvider::GetVSyncParameters");
54     DWM_TIMING_INFO timing_info;
55     timing_info.cbSize = sizeof(timing_info);
56     HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
57     if (result != S_OK)
58       return;
59
60     base::TimeTicks timebase;
61     // If FrameTime is not high resolution, we do not want to translate the
62     // QPC value provided by DWM into the low-resolution timebase, which
63     // would be error prone and jittery. As a fallback, we assume the timebase
64     // is zero.
65     if (gfx::FrameTime::TimestampsAreHighRes()) {
66       timebase = gfx::FrameTime::FromQPCValue(
67           static_cast<LONGLONG>(timing_info.qpcVBlank));
68     }
69
70     // Swap the numerator/denominator to convert frequency to period.
71     if (timing_info.rateRefresh.uiDenominator > 0 &&
72         timing_info.rateRefresh.uiNumerator > 0) {
73       base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
74           timing_info.rateRefresh.uiDenominator *
75           base::Time::kMicrosecondsPerSecond /
76           timing_info.rateRefresh.uiNumerator);
77       callback.Run(timebase, interval);
78     }
79   }
80
81  private:
82   DISALLOW_COPY_AND_ASSIGN(DWMVSyncProvider);
83 };
84
85 // Helper routine that does one-off initialization like determining the
86 // pixel format and initializing the GL bindings.
87 bool GLSurface::InitializeOneOffInternal() {
88   switch (GetGLImplementation()) {
89     case kGLImplementationDesktopGL:
90       if (!GLSurfaceWGL::InitializeOneOff()) {
91         LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
92         return false;
93       }
94       break;
95     case kGLImplementationEGLGLES2:
96       if (!GLSurfaceEGL::InitializeOneOff()) {
97         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
98         return false;
99       }
100       break;
101   }
102   return true;
103 }
104
105 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
106     gfx::AcceleratedWidget window)
107   : GLSurfaceOSMesa(OSMESA_RGBA, gfx::Size(1, 1)),
108     window_(window),
109     device_context_(NULL) {
110   DCHECK(window);
111 }
112
113 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
114   Destroy();
115 }
116
117 bool NativeViewGLSurfaceOSMesa::Initialize() {
118   if (!GLSurfaceOSMesa::Initialize())
119     return false;
120
121   device_context_ = GetDC(window_);
122   return true;
123 }
124
125 void NativeViewGLSurfaceOSMesa::Destroy() {
126   if (window_ && device_context_)
127     ReleaseDC(window_, device_context_);
128
129   device_context_ = NULL;
130
131   GLSurfaceOSMesa::Destroy();
132 }
133
134 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
135   return false;
136 }
137
138 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
139   DCHECK(device_context_);
140
141   gfx::Size size = GetSize();
142
143   // Note: negating the height below causes GDI to treat the bitmap data as row
144   // 0 being at the top.
145   BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
146   info.bV4Width = size.width();
147   info.bV4Height = -size.height();
148   info.bV4Planes = 1;
149   info.bV4BitCount = 32;
150   info.bV4V4Compression = BI_BITFIELDS;
151   info.bV4RedMask = 0x000000FF;
152   info.bV4GreenMask = 0x0000FF00;
153   info.bV4BlueMask = 0x00FF0000;
154   info.bV4AlphaMask = 0xFF000000;
155
156   // Copy the back buffer to the window's device context. Do not check whether
157   // StretchDIBits succeeds or not. It will fail if the window has been
158   // destroyed but it is preferable to allow rendering to silently fail if the
159   // window is destroyed. This is because the primary application of this
160   // class of GLContext is for testing and we do not want every GL related ui /
161   // browser test to become flaky if there is a race condition between GL
162   // context destruction and window destruction.
163   StretchDIBits(device_context_,
164                 0, 0, size.width(), size.height(),
165                 0, 0, size.width(), size.height(),
166                 GetHandle(),
167                 reinterpret_cast<BITMAPINFO*>(&info),
168                 DIB_RGB_COLORS,
169                 SRCCOPY);
170
171   return true;
172 }
173
174 std::string NativeViewGLSurfaceOSMesa::GetExtensions() {
175   std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions();
176   extensions += extensions.empty() ? "" : " ";
177   extensions += "GL_CHROMIUM_post_sub_buffer";
178   return extensions;
179 }
180
181 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
182     int x, int y, int width, int height) {
183   DCHECK(device_context_);
184
185   gfx::Size size = GetSize();
186
187   // Note: negating the height below causes GDI to treat the bitmap data as row
188   // 0 being at the top.
189   BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
190   info.bV4Width = size.width();
191   info.bV4Height = -size.height();
192   info.bV4Planes = 1;
193   info.bV4BitCount = 32;
194   info.bV4V4Compression = BI_BITFIELDS;
195   info.bV4RedMask = 0x000000FF;
196   info.bV4GreenMask = 0x0000FF00;
197   info.bV4BlueMask = 0x00FF0000;
198   info.bV4AlphaMask = 0xFF000000;
199
200   // Copy the back buffer to the window's device context. Do not check whether
201   // StretchDIBits succeeds or not. It will fail if the window has been
202   // destroyed but it is preferable to allow rendering to silently fail if the
203   // window is destroyed. This is because the primary application of this
204   // class of GLContext is for testing and we do not want every GL related ui /
205   // browser test to become flaky if there is a race condition between GL
206   // context destruction and window destruction.
207   StretchDIBits(device_context_,
208                 x, size.height() - y - height, width, height,
209                 x, y, width, height,
210                 GetHandle(),
211                 reinterpret_cast<BITMAPINFO*>(&info),
212                 DIB_RGB_COLORS,
213                 SRCCOPY);
214
215   return true;
216 }
217
218 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
219     gfx::AcceleratedWidget window) {
220   TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
221   switch (GetGLImplementation()) {
222     case kGLImplementationOSMesaGL: {
223       scoped_refptr<GLSurface> surface(
224           new NativeViewGLSurfaceOSMesa(window));
225       if (!surface->Initialize())
226         return NULL;
227
228       return surface;
229     }
230     case kGLImplementationEGLGLES2: {
231       scoped_refptr<NativeViewGLSurfaceEGL> surface(
232           new NativeViewGLSurfaceEGL(window));
233       DWMVSyncProvider* sync_provider = NULL;
234       if (base::win::GetVersion() >= base::win::VERSION_VISTA)
235         sync_provider = new DWMVSyncProvider;
236       if (!surface->Initialize(sync_provider))
237         return NULL;
238
239       return surface;
240     }
241     case kGLImplementationDesktopGL: {
242       scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
243           window));
244       if (!surface->Initialize())
245         return NULL;
246
247       return surface;
248     }
249     case kGLImplementationMockGL:
250       return new GLSurfaceStub;
251     default:
252       NOTREACHED();
253       return NULL;
254   }
255 }
256
257 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
258     const gfx::Size& size) {
259   TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
260   switch (GetGLImplementation()) {
261     case kGLImplementationOSMesaGL: {
262       scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA,
263                                                            size));
264       if (!surface->Initialize())
265         return NULL;
266
267       return surface;
268     }
269     case kGLImplementationEGLGLES2: {
270       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
271       if (!surface->Initialize())
272         return NULL;
273
274       return surface;
275     }
276     case kGLImplementationDesktopGL: {
277       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
278       if (!surface->Initialize())
279         return NULL;
280
281       return surface;
282     }
283     case kGLImplementationMockGL:
284       return new GLSurfaceStub;
285     default:
286       NOTREACHED();
287       return NULL;
288   }
289 }
290
291 }  // namespace gfx