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 "base/message_loop/message_loop.h" 11 #include "third_party/mesa/src/include/GL/osmesa.h" 12 #include "ui/gl/gl_bindings.h" 13 #include "ui/gl/gl_implementation.h" 14 #include "ui/gl/gl_surface_egl.h" 15 #include "ui/gl/gl_surface_glx.h" 16 #include "ui/gl/gl_surface_osmesa.h" 17 #include "ui/gl/gl_surface_stub.h" 18 19 namespace gfx { 20 21 namespace { 22 Display* g_osmesa_display; 23 } // namespace 24 25 // This OSMesa GL surface can use XLib to swap the contents of the buffer to a 26 // view. 27 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { 28 public: 29 explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window); 30 31 static bool InitializeOneOff(); 32 33 // Implement a subset of GLSurface. 34 virtual bool Initialize() OVERRIDE; 35 virtual void Destroy() OVERRIDE; 36 virtual bool Resize(const gfx::Size& new_size) OVERRIDE; 37 virtual bool IsOffscreen() OVERRIDE; 38 virtual bool SwapBuffers() OVERRIDE; 39 virtual std::string GetExtensions() OVERRIDE; 40 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; 41 42 protected: 43 virtual ~NativeViewGLSurfaceOSMesa(); 44 45 private: 46 GC window_graphics_context_; 47 gfx::AcceleratedWidget window_; 48 GC pixmap_graphics_context_; 49 Pixmap pixmap_; 50 51 DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); 52 }; 53 54 bool GLSurface::InitializeOneOffInternal() { 55 switch (GetGLImplementation()) { 56 case kGLImplementationDesktopGL: 57 if (!GLSurfaceGLX::InitializeOneOff()) { 58 LOG(ERROR) << "GLSurfaceGLX::InitializeOneOff failed."; 59 return false; 60 } 61 break; 62 case kGLImplementationOSMesaGL: 63 if (!NativeViewGLSurfaceOSMesa::InitializeOneOff()) { 64 LOG(ERROR) << "NativeViewGLSurfaceOSMesa::InitializeOneOff failed."; 65 return false; 66 } 67 break; 68 case kGLImplementationEGLGLES2: 69 if (!GLSurfaceEGL::InitializeOneOff()) { 70 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; 71 return false; 72 } 73 break; 74 default: 75 break; 76 } 77 78 return true; 79 } 80 81 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( 82 gfx::AcceleratedWidget window) 83 : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)), 84 window_graphics_context_(0), 85 window_(window), 86 pixmap_graphics_context_(0), 87 pixmap_(0) { 88 DCHECK(window); 89 } 90 91 bool NativeViewGLSurfaceOSMesa::InitializeOneOff() { 92 static bool initialized = false; 93 if (initialized) 94 return true; 95 96 g_osmesa_display = base::MessagePumpForUI::GetDefaultXDisplay(); 97 if (!g_osmesa_display) { 98 LOG(ERROR) << "XOpenDisplay failed."; 99 return false; 100 } 101 102 initialized = true; 103 return true; 104 } 105 106 bool NativeViewGLSurfaceOSMesa::Initialize() { 107 if (!GLSurfaceOSMesa::Initialize()) 108 return false; 109 110 window_graphics_context_ = XCreateGC(g_osmesa_display, 111 window_, 112 0, 113 NULL); 114 if (!window_graphics_context_) { 115 LOG(ERROR) << "XCreateGC failed."; 116 Destroy(); 117 return false; 118 } 119 120 return true; 121 } 122 123 void NativeViewGLSurfaceOSMesa::Destroy() { 124 if (pixmap_graphics_context_) { 125 XFreeGC(g_osmesa_display, pixmap_graphics_context_); 126 pixmap_graphics_context_ = NULL; 127 } 128 129 if (pixmap_) { 130 XFreePixmap(g_osmesa_display, pixmap_); 131 pixmap_ = 0; 132 } 133 134 if (window_graphics_context_) { 135 XFreeGC(g_osmesa_display, window_graphics_context_); 136 window_graphics_context_ = NULL; 137 } 138 139 XSync(g_osmesa_display, False); 140 } 141 142 bool NativeViewGLSurfaceOSMesa::Resize(const gfx::Size& new_size) { 143 if (!GLSurfaceOSMesa::Resize(new_size)) 144 return false; 145 146 XWindowAttributes attributes; 147 if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) { 148 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; 149 return false; 150 } 151 152 // Destroy the previous pixmap and graphics context. 153 if (pixmap_graphics_context_) { 154 XFreeGC(g_osmesa_display, pixmap_graphics_context_); 155 pixmap_graphics_context_ = NULL; 156 } 157 if (pixmap_) { 158 XFreePixmap(g_osmesa_display, pixmap_); 159 pixmap_ = 0; 160 } 161 162 // Recreate a pixmap to hold the frame. 163 pixmap_ = XCreatePixmap(g_osmesa_display, 164 window_, 165 new_size.width(), 166 new_size.height(), 167 attributes.depth); 168 if (!pixmap_) { 169 LOG(ERROR) << "XCreatePixmap failed."; 170 return false; 171 } 172 173 // Recreate a graphics context for the pixmap. 174 pixmap_graphics_context_ = XCreateGC(g_osmesa_display, pixmap_, 0, NULL); 175 if (!pixmap_graphics_context_) { 176 LOG(ERROR) << "XCreateGC failed"; 177 return false; 178 } 179 180 return true; 181 } 182 183 bool NativeViewGLSurfaceOSMesa::IsOffscreen() { 184 return false; 185 } 186 187 bool NativeViewGLSurfaceOSMesa::SwapBuffers() { 188 gfx::Size size = GetSize(); 189 190 XWindowAttributes attributes; 191 if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) { 192 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; 193 return false; 194 } 195 196 // Copy the frame into the pixmap. 197 gfx::PutARGBImage(g_osmesa_display, 198 attributes.visual, 199 attributes.depth, 200 pixmap_, 201 pixmap_graphics_context_, 202 static_cast<const uint8*>(GetHandle()), 203 size.width(), 204 size.height()); 205 206 // Copy the pixmap to the window. 207 XCopyArea(g_osmesa_display, 208 pixmap_, 209 window_, 210 window_graphics_context_, 211 0, 0, 212 size.width(), size.height(), 213 0, 0); 214 215 return true; 216 } 217 218 std::string NativeViewGLSurfaceOSMesa::GetExtensions() { 219 std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions(); 220 extensions += extensions.empty() ? "" : " "; 221 extensions += "GL_CHROMIUM_post_sub_buffer"; 222 return extensions; 223 } 224 225 bool NativeViewGLSurfaceOSMesa::PostSubBuffer( 226 int x, int y, int width, int height) { 227 gfx::Size size = GetSize(); 228 229 // Move (0,0) from lower-left to upper-left 230 y = size.height() - y - height; 231 232 XWindowAttributes attributes; 233 if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) { 234 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; 235 return false; 236 } 237 238 // Copy the frame into the pixmap. 239 gfx::PutARGBImage(g_osmesa_display, 240 attributes.visual, 241 attributes.depth, 242 pixmap_, 243 pixmap_graphics_context_, 244 static_cast<const uint8*>(GetHandle()), 245 size.width(), 246 size.height(), 247 x, y, 248 x, y, 249 width, 250 height); 251 252 // Copy the pixmap to the window. 253 XCopyArea(g_osmesa_display, 254 pixmap_, 255 window_, 256 window_graphics_context_, 257 x, y, 258 width, height, 259 x, y); 260 261 return true; 262 } 263 264 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { 265 Destroy(); 266 } 267 268 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface( 269 gfx::AcceleratedWidget window) { 270 TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface"); 271 switch (GetGLImplementation()) { 272 case kGLImplementationOSMesaGL: { 273 scoped_refptr<GLSurface> surface( 274 new NativeViewGLSurfaceOSMesa(window)); 275 if (!surface->Initialize()) 276 return NULL; 277 278 return surface; 279 } 280 case kGLImplementationDesktopGL: { 281 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceGLX(window)); 282 if (!surface->Initialize()) 283 return NULL; 284 285 return surface; 286 } 287 case kGLImplementationEGLGLES2: { 288 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceEGL(window)); 289 if (!surface->Initialize()) 290 return NULL; 291 292 return surface; 293 } 294 case kGLImplementationMockGL: 295 return new GLSurfaceStub; 296 default: 297 NOTREACHED(); 298 return NULL; 299 } 300 } 301 302 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface( 303 const gfx::Size& size) { 304 TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface"); 305 switch (GetGLImplementation()) { 306 case kGLImplementationOSMesaGL: { 307 scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA, 308 size)); 309 if (!surface->Initialize()) 310 return NULL; 311 312 return surface; 313 } 314 case kGLImplementationDesktopGL: { 315 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceGLX(size)); 316 if (!surface->Initialize()) 317 return NULL; 318 319 return surface; 320 } 321 case kGLImplementationEGLGLES2: { 322 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size)); 323 if (!surface->Initialize()) 324 return NULL; 325 326 return surface; 327 } 328 case kGLImplementationMockGL: 329 return new GLSurfaceStub; 330 default: 331 NOTREACHED(); 332 return NULL; 333 } 334 } 335 336 } // namespace gfx 337