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/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