Home | History | Annotate | Download | only in gl
      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