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 <OpenGL/CGLRenderers.h>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/debug/trace_event.h"
     11 #include "base/logging.h"
     12 #include "base/mac/mac_util.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "ui/gl/gl_bindings.h"
     15 #include "ui/gl/gl_context.h"
     16 #include "ui/gl/gl_implementation.h"
     17 #include "ui/gl/gl_surface_osmesa.h"
     18 #include "ui/gl/gl_surface_stub.h"
     19 #include "ui/gl/gpu_switching_manager.h"
     20 
     21 namespace gfx {
     22 namespace {
     23 
     24 // A "no-op" surface. It is not required that a CGLContextObj have an
     25 // associated drawable (pbuffer or fullscreen context) in order to be
     26 // made current. Everywhere this surface type is used, we allocate an
     27 // FBO at the user level as the drawable of the associated context.
     28 class GL_EXPORT NoOpGLSurface : public GLSurface {
     29  public:
     30   explicit NoOpGLSurface(const gfx::Size& size) : size_(size) {}
     31 
     32   // Implement GLSurface.
     33   virtual bool Initialize() OVERRIDE { return true; }
     34   virtual void Destroy() OVERRIDE {}
     35   virtual bool IsOffscreen() OVERRIDE { return true; }
     36   virtual bool SwapBuffers() OVERRIDE {
     37     NOTREACHED() << "Cannot call SwapBuffers on a NoOpGLSurface.";
     38     return false;
     39   }
     40   virtual gfx::Size GetSize() OVERRIDE { return size_; }
     41   virtual void* GetHandle() OVERRIDE { return NULL; }
     42   virtual void* GetDisplay() OVERRIDE { return NULL; }
     43 
     44  protected:
     45   virtual ~NoOpGLSurface() {}
     46 
     47  private:
     48   gfx::Size size_;
     49 
     50   DISALLOW_COPY_AND_ASSIGN(NoOpGLSurface);
     51 };
     52 
     53 // static
     54 bool InitializeOneOffForSandbox() {
     55   static bool initialized = false;
     56   if (initialized)
     57     return true;
     58 
     59   // This is called from the sandbox warmup code on Mac OS X.
     60   // GPU-related stuff is very slow without this, probably because
     61   // the sandbox prevents loading graphics drivers or some such.
     62   std::vector<CGLPixelFormatAttribute> attribs;
     63   if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
     64     // Avoid switching to the discrete GPU just for this pixel
     65     // format selection.
     66     attribs.push_back(kCGLPFAAllowOfflineRenderers);
     67   }
     68   if (GetGLImplementation() == kGLImplementationAppleGL) {
     69     attribs.push_back(kCGLPFARendererID);
     70     attribs.push_back(static_cast<CGLPixelFormatAttribute>(
     71       kCGLRendererGenericFloatID));
     72   }
     73   attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
     74 
     75   CGLPixelFormatObj format;
     76   GLint num_pixel_formats;
     77   if (CGLChoosePixelFormat(&attribs.front(),
     78                            &format,
     79                            &num_pixel_formats) != kCGLNoError) {
     80     LOG(ERROR) << "Error choosing pixel format.";
     81     return false;
     82   }
     83   if (!format) {
     84     LOG(ERROR) << "format == 0.";
     85     return false;
     86   }
     87   CGLReleasePixelFormat(format);
     88   DCHECK_NE(num_pixel_formats, 0);
     89   initialized = true;
     90   return true;
     91 }
     92 
     93 }  // namespace
     94 
     95 bool GLSurface::InitializeOneOffInternal() {
     96   switch (GetGLImplementation()) {
     97     case kGLImplementationDesktopGL:
     98     case kGLImplementationAppleGL:
     99       if (!InitializeOneOffForSandbox()) {
    100         LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed.";
    101         return false;
    102       }
    103       break;
    104     default:
    105       break;
    106   }
    107   return true;
    108 }
    109 
    110 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
    111     gfx::AcceleratedWidget window) {
    112   TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
    113   switch (GetGLImplementation()) {
    114     case kGLImplementationDesktopGL:
    115     case kGLImplementationAppleGL: {
    116       NOTIMPLEMENTED() << "No onscreen support on Mac.";
    117       return NULL;
    118     }
    119     case kGLImplementationOSMesaGL: {
    120       scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless());
    121       if (!surface->Initialize())
    122         return NULL;
    123       return surface;
    124     }
    125     case kGLImplementationMockGL:
    126       return new GLSurfaceStub;
    127     default:
    128       NOTREACHED();
    129       return NULL;
    130   }
    131 }
    132 
    133 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
    134     const gfx::Size& size) {
    135   TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
    136   switch (GetGLImplementation()) {
    137     case kGLImplementationOSMesaGL: {
    138       scoped_refptr<GLSurface> surface(
    139           new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
    140       if (!surface->Initialize())
    141         return NULL;
    142 
    143       return surface;
    144     }
    145     case kGLImplementationDesktopGL:
    146     case kGLImplementationAppleGL: {
    147       scoped_refptr<GLSurface> surface(new NoOpGLSurface(size));
    148       if (!surface->Initialize())
    149         return NULL;
    150 
    151       return surface;
    152     }
    153     case kGLImplementationMockGL:
    154       return new GLSurfaceStub;
    155     default:
    156       NOTREACHED();
    157       return NULL;
    158   }
    159 }
    160 
    161 }  // namespace gfx
    162