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