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"
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"
24 // This OSMesa GL surface can use GDI to swap the contents of the buffer to a
26 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
28 explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
29 virtual ~NativeViewGLSurfaceOSMesa();
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;
40 gfx::AcceleratedWidget window_;
43 DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
46 class DWMVSyncProvider : public VSyncProvider {
48 explicit DWMVSyncProvider() {}
50 virtual ~DWMVSyncProvider() {}
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);
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
65 if (gfx::FrameTime::TimestampsAreHighRes()) {
66 timebase = gfx::FrameTime::FromQPCValue(
67 static_cast<LONGLONG>(timing_info.qpcVBlank));
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);
82 DISALLOW_COPY_AND_ASSIGN(DWMVSyncProvider);
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.";
95 case kGLImplementationEGLGLES2:
96 if (!GLSurfaceEGL::InitializeOneOff()) {
97 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
105 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
106 gfx::AcceleratedWidget window)
107 : GLSurfaceOSMesa(OSMESA_RGBA, gfx::Size(1, 1)),
109 device_context_(NULL) {
113 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
117 bool NativeViewGLSurfaceOSMesa::Initialize() {
118 if (!GLSurfaceOSMesa::Initialize())
121 device_context_ = GetDC(window_);
125 void NativeViewGLSurfaceOSMesa::Destroy() {
126 if (window_ && device_context_)
127 ReleaseDC(window_, device_context_);
129 device_context_ = NULL;
131 GLSurfaceOSMesa::Destroy();
134 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
138 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
139 DCHECK(device_context_);
141 gfx::Size size = GetSize();
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();
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;
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(),
167 reinterpret_cast<BITMAPINFO*>(&info),
174 std::string NativeViewGLSurfaceOSMesa::GetExtensions() {
175 std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions();
176 extensions += extensions.empty() ? "" : " ";
177 extensions += "GL_CHROMIUM_post_sub_buffer";
181 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
182 int x, int y, int width, int height) {
183 DCHECK(device_context_);
185 gfx::Size size = GetSize();
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();
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;
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,
211 reinterpret_cast<BITMAPINFO*>(&info),
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())
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))
241 case kGLImplementationDesktopGL: {
242 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
244 if (!surface->Initialize())
249 case kGLImplementationMockGL:
250 return new GLSurfaceStub;
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,
264 if (!surface->Initialize())
269 case kGLImplementationEGLGLES2: {
270 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
271 if (!surface->Initialize())
276 case kGLImplementationDesktopGL: {
277 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
278 if (!surface->Initialize())
283 case kGLImplementationMockGL:
284 return new GLSurfaceStub;