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