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 <dwmapi.h>
      8 
      9 #include "base/command_line.h"
     10 #include "base/debug/trace_event.h"
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/win/windows_version.h"
     14 #include "third_party/mesa/src/include/GL/osmesa.h"
     15 #include "ui/gfx/frame_time.h"
     16 #include "ui/gfx/native_widget_types.h"
     17 #include "ui/gl/gl_bindings.h"
     18 #include "ui/gl/gl_implementation.h"
     19 #include "ui/gl/gl_surface_egl.h"
     20 #include "ui/gl/gl_surface_osmesa.h"
     21 #include "ui/gl/gl_surface_stub.h"
     22 #include "ui/gl/gl_surface_wgl.h"
     23 
     24 // From ANGLE's egl/eglext.h.
     25 #if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
     26 #define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
     27   reinterpret_cast<EGLNativeDisplayType>(-2)
     28 #endif
     29 
     30 namespace gfx {
     31 
     32 // This OSMesa GL surface can use GDI to swap the contents of the buffer to a
     33 // view.
     34 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
     35  public:
     36   explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
     37   virtual ~NativeViewGLSurfaceOSMesa();
     38 
     39   // Implement subset of GLSurface.
     40   virtual bool Initialize() OVERRIDE;
     41   virtual void Destroy() OVERRIDE;
     42   virtual bool IsOffscreen() OVERRIDE;
     43   virtual bool SwapBuffers() OVERRIDE;
     44   virtual bool SupportsPostSubBuffer() OVERRIDE;
     45   virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
     46 
     47  private:
     48   gfx::AcceleratedWidget window_;
     49   HDC device_context_;
     50 
     51   DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
     52 };
     53 
     54 class DWMVSyncProvider : public VSyncProvider {
     55  public:
     56   explicit DWMVSyncProvider() {}
     57 
     58   virtual ~DWMVSyncProvider() {}
     59 
     60   virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) {
     61     TRACE_EVENT0("gpu", "DWMVSyncProvider::GetVSyncParameters");
     62     DWM_TIMING_INFO timing_info;
     63     timing_info.cbSize = sizeof(timing_info);
     64     HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
     65     if (result != S_OK)
     66       return;
     67 
     68     base::TimeTicks timebase;
     69     // If FrameTime is not high resolution, we do not want to translate the
     70     // QPC value provided by DWM into the low-resolution timebase, which
     71     // would be error prone and jittery. As a fallback, we assume the timebase
     72     // is zero.
     73     if (gfx::FrameTime::TimestampsAreHighRes()) {
     74       timebase = gfx::FrameTime::FromQPCValue(
     75           static_cast<LONGLONG>(timing_info.qpcVBlank));
     76     }
     77 
     78     // Swap the numerator/denominator to convert frequency to period.
     79     if (timing_info.rateRefresh.uiDenominator > 0 &&
     80         timing_info.rateRefresh.uiNumerator > 0) {
     81       base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
     82           timing_info.rateRefresh.uiDenominator *
     83           base::Time::kMicrosecondsPerSecond /
     84           timing_info.rateRefresh.uiNumerator);
     85       callback.Run(timebase, interval);
     86     }
     87   }
     88 
     89  private:
     90   DISALLOW_COPY_AND_ASSIGN(DWMVSyncProvider);
     91 };
     92 
     93 // Helper routine that does one-off initialization like determining the
     94 // pixel format.
     95 bool GLSurface::InitializeOneOffInternal() {
     96   switch (GetGLImplementation()) {
     97     case kGLImplementationDesktopGL:
     98       if (!GLSurfaceWGL::InitializeOneOff()) {
     99         LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
    100         return false;
    101       }
    102       break;
    103     case kGLImplementationEGLGLES2:
    104       if (!GLSurfaceEGL::InitializeOneOff()) {
    105         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
    106         return false;
    107       }
    108       break;
    109   }
    110   return true;
    111 }
    112 
    113 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
    114     gfx::AcceleratedWidget window)
    115   : GLSurfaceOSMesa(OSMESA_RGBA, gfx::Size(1, 1)),
    116     window_(window),
    117     device_context_(NULL) {
    118   DCHECK(window);
    119 }
    120 
    121 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
    122   Destroy();
    123 }
    124 
    125 bool NativeViewGLSurfaceOSMesa::Initialize() {
    126   if (!GLSurfaceOSMesa::Initialize())
    127     return false;
    128 
    129   device_context_ = GetDC(window_);
    130   return true;
    131 }
    132 
    133 void NativeViewGLSurfaceOSMesa::Destroy() {
    134   if (window_ && device_context_)
    135     ReleaseDC(window_, device_context_);
    136 
    137   device_context_ = NULL;
    138 
    139   GLSurfaceOSMesa::Destroy();
    140 }
    141 
    142 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
    143   return false;
    144 }
    145 
    146 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
    147   DCHECK(device_context_);
    148 
    149   gfx::Size size = GetSize();
    150 
    151   // Note: negating the height below causes GDI to treat the bitmap data as row
    152   // 0 being at the top.
    153   BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
    154   info.bV4Width = size.width();
    155   info.bV4Height = -size.height();
    156   info.bV4Planes = 1;
    157   info.bV4BitCount = 32;
    158   info.bV4V4Compression = BI_BITFIELDS;
    159   info.bV4RedMask = 0x000000FF;
    160   info.bV4GreenMask = 0x0000FF00;
    161   info.bV4BlueMask = 0x00FF0000;
    162   info.bV4AlphaMask = 0xFF000000;
    163 
    164   // Copy the back buffer to the window's device context. Do not check whether
    165   // StretchDIBits succeeds or not. It will fail if the window has been
    166   // destroyed but it is preferable to allow rendering to silently fail if the
    167   // window is destroyed. This is because the primary application of this
    168   // class of GLContext is for testing and we do not want every GL related ui /
    169   // browser test to become flaky if there is a race condition between GL
    170   // context destruction and window destruction.
    171   StretchDIBits(device_context_,
    172                 0, 0, size.width(), size.height(),
    173                 0, 0, size.width(), size.height(),
    174                 GetHandle(),
    175                 reinterpret_cast<BITMAPINFO*>(&info),
    176                 DIB_RGB_COLORS,
    177                 SRCCOPY);
    178 
    179   return true;
    180 }
    181 
    182 bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
    183   return true;
    184 }
    185 
    186 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
    187     int x, int y, int width, int height) {
    188   DCHECK(device_context_);
    189 
    190   gfx::Size size = GetSize();
    191 
    192   // Note: negating the height below causes GDI to treat the bitmap data as row
    193   // 0 being at the top.
    194   BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
    195   info.bV4Width = size.width();
    196   info.bV4Height = -size.height();
    197   info.bV4Planes = 1;
    198   info.bV4BitCount = 32;
    199   info.bV4V4Compression = BI_BITFIELDS;
    200   info.bV4RedMask = 0x000000FF;
    201   info.bV4GreenMask = 0x0000FF00;
    202   info.bV4BlueMask = 0x00FF0000;
    203   info.bV4AlphaMask = 0xFF000000;
    204 
    205   // Copy the back buffer to the window's device context. Do not check whether
    206   // StretchDIBits succeeds or not. It will fail if the window has been
    207   // destroyed but it is preferable to allow rendering to silently fail if the
    208   // window is destroyed. This is because the primary application of this
    209   // class of GLContext is for testing and we do not want every GL related ui /
    210   // browser test to become flaky if there is a race condition between GL
    211   // context destruction and window destruction.
    212   StretchDIBits(device_context_,
    213                 x, size.height() - y - height, width, height,
    214                 x, y, width, height,
    215                 GetHandle(),
    216                 reinterpret_cast<BITMAPINFO*>(&info),
    217                 DIB_RGB_COLORS,
    218                 SRCCOPY);
    219 
    220   return true;
    221 }
    222 
    223 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
    224     gfx::AcceleratedWidget window) {
    225   TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
    226   switch (GetGLImplementation()) {
    227     case kGLImplementationOSMesaGL: {
    228       scoped_refptr<GLSurface> surface(
    229           new NativeViewGLSurfaceOSMesa(window));
    230       if (!surface->Initialize())
    231         return NULL;
    232 
    233       return surface;
    234     }
    235     case kGLImplementationEGLGLES2: {
    236       DCHECK(window != gfx::kNullAcceleratedWidget);
    237       scoped_refptr<NativeViewGLSurfaceEGL> surface(
    238           new NativeViewGLSurfaceEGL(window));
    239       scoped_ptr<VSyncProvider> sync_provider;
    240       if (base::win::GetVersion() >= base::win::VERSION_VISTA)
    241         sync_provider.reset(new DWMVSyncProvider);
    242       if (!surface->Initialize(sync_provider.Pass()))
    243         return NULL;
    244 
    245       return surface;
    246     }
    247     case kGLImplementationDesktopGL: {
    248       scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
    249           window));
    250       if (!surface->Initialize())
    251         return NULL;
    252 
    253       return surface;
    254     }
    255     case kGLImplementationMockGL:
    256       return new GLSurfaceStub;
    257     default:
    258       NOTREACHED();
    259       return NULL;
    260   }
    261 }
    262 
    263 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
    264     const gfx::Size& size) {
    265   TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
    266   switch (GetGLImplementation()) {
    267     case kGLImplementationOSMesaGL: {
    268       scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA,
    269                                                            size));
    270       if (!surface->Initialize())
    271         return NULL;
    272 
    273       return surface;
    274     }
    275     case kGLImplementationEGLGLES2: {
    276       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
    277       if (!surface->Initialize())
    278         return NULL;
    279 
    280       return surface;
    281     }
    282     case kGLImplementationDesktopGL: {
    283       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
    284       if (!surface->Initialize())
    285         return NULL;
    286 
    287       return surface;
    288     }
    289     case kGLImplementationMockGL:
    290       return new GLSurfaceStub;
    291     default:
    292       NOTREACHED();
    293       return NULL;
    294   }
    295 }
    296 
    297 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
    298   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11))
    299     return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
    300 
    301   return EGL_DEFAULT_DISPLAY;
    302 }
    303 
    304 }  // namespace gfx
    305