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