Initial ui/gl updates for Mac Sky shell target

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/1238983002 .
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index 5a06fed..35c6e66 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -160,6 +160,9 @@
 #elif defined(OS_IOS)
 typedef uintptr_t AcceleratedWidget;
 const AcceleratedWidget kNullAcceleratedWidget = 0;
+#elif defined(OS_MACOSX)
+typedef uintptr_t AcceleratedWidget;
+const AcceleratedWidget kNullAcceleratedWidget = 0;
 #else
 #error unknown platform
 #endif
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 332d8ce..a5ed5cc 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -207,7 +207,7 @@
       "//ui/ozone:ozone_base",
     ]
   }
-  if (is_ios) {
+  if (is_ios || is_mac) {
     sources = []
     sources = [
       "gl_bindings_autogen_gl.cc",
@@ -218,6 +218,7 @@
       "gl_context.h",
       "gl_context_ios.h",
       "gl_context_ios.mm",
+      "gl_context_mac.mm",
       "gl_context_stub.cc",
       "gl_context_stub.h",
       "gl_context_stub_with_extensions.cc",
@@ -230,12 +231,14 @@
       "gl_implementation.cc",
       "gl_implementation.h",
       "gl_implementation_ios.cc",
+      "gl_implementation_mac.cc",
       "gl_share_group.cc",
       "gl_share_group.h",
       "gl_surface.cc",
       "gl_surface.h",
       "gl_surface_ios.h",
       "gl_surface_ios.mm",
+      "gl_surface_mac.cc",
       "gl_surface_stub.cc",
       "gl_surface_stub.h",
       "gl_switches.cc",
@@ -246,6 +249,15 @@
       "gpu_timing.h",
     ]
   }
+
+  if (is_mac) {
+    sources += [
+      "gl_context_cgl.cc",
+      "gl_context_cgl.h",
+      "gpu_switching_manager.cc",
+      "gpu_switching_manager.h",
+    ]
+  }
 }
 
 source_set("gl_unittest_utils") {
diff --git a/ui/gl/gl_context_cgl.cc b/ui/gl/gl_context_cgl.cc
new file mode 100644
index 0000000..4a82d33
--- /dev/null
+++ b/ui/gl/gl_context_cgl.cc
@@ -0,0 +1,304 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/gl_context_cgl.h"
+
+#include <OpenGL/CGLRenderers.h>
+#include <OpenGL/CGLTypes.h>
+#include <OpenGL/CGLCurrent.h>
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gpu_switching_manager.h"
+
+extern "C" {
+extern CGLError CGLChoosePixelFormat(const CGLPixelFormatAttribute *attribs,
+                                     CGLPixelFormatObj *pix, GLint *npix);
+extern CGLError CGLDescribePixelFormat(CGLPixelFormatObj pix, GLint pix_num,
+                                       CGLPixelFormatAttribute attrib,
+                                       GLint *value);
+extern void CGLReleasePixelFormat(CGLPixelFormatObj pix);
+
+extern CGLError CGLCreateContext(CGLPixelFormatObj pix, CGLContextObj share,
+                                 CGLContextObj *ctx);
+extern CGLError CGLDestroyContext(CGLContextObj ctx);
+
+extern CGLError CGLGetParameter(CGLContextObj ctx, CGLContextParameter pname,
+                                GLint *params);
+
+extern CGLError CGLGetVirtualScreen(CGLContextObj ctx, GLint *screen);
+extern CGLError CGLSetVirtualScreen(CGLContextObj ctx, GLint screen);
+
+extern CGLError CGLQueryRendererInfo(GLuint display_mask,
+                                     CGLRendererInfoObj *rend, GLint *nrend);
+extern CGLError CGLDescribeRenderer(CGLRendererInfoObj rend, GLint rend_num,
+                                    CGLRendererProperty prop, GLint *value);
+extern CGLError CGLDestroyRendererInfo(CGLRendererInfoObj rend);
+}  // extern "C"
+
+namespace gfx {
+
+namespace {
+
+bool g_support_renderer_switching;
+
+struct CGLRendererInfoObjDeleter {
+  void operator()(CGLRendererInfoObj* x) {
+    if (x)
+      CGLDestroyRendererInfo(*x);
+  }
+};
+
+}  // namespace
+
+static CGLPixelFormatObj GetPixelFormat() {
+  static CGLPixelFormatObj format;
+  if (format)
+    return format;
+  std::vector<CGLPixelFormatAttribute> attribs;
+  // If the system supports dual gpus then allow offline renderers for every
+  // context, so that they can all be in the same share group.
+  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+    attribs.push_back(kCGLPFAAllowOfflineRenderers);
+    g_support_renderer_switching = true;
+  }
+  if (GetGLImplementation() == kGLImplementationAppleGL) {
+    attribs.push_back(kCGLPFARendererID);
+    attribs.push_back((CGLPixelFormatAttribute) kCGLRendererGenericFloatID);
+    g_support_renderer_switching = false;
+  }
+
+  attribs.push_back((CGLPixelFormatAttribute) 0);
+
+  GLint num_virtual_screens;
+  if (CGLChoosePixelFormat(&attribs.front(),
+                           &format,
+                           &num_virtual_screens) != kCGLNoError) {
+    LOG(ERROR) << "Error choosing pixel format.";
+    return nullptr;
+  }
+  if (!format) {
+    LOG(ERROR) << "format == 0.";
+    return nullptr;
+  }
+  DCHECK_NE(num_virtual_screens, 0);
+  return format;
+}
+
+GLContextCGL::GLContextCGL(GLShareGroup* share_group)
+  : GLContextReal(share_group),
+    context_(nullptr),
+    gpu_preference_(PreferIntegratedGpu),
+    discrete_pixelformat_(nullptr),
+    screen_(-1),
+    renderer_id_(-1),
+    safe_to_force_gpu_switch_(false) {
+}
+
+bool GLContextCGL::Initialize(GLSurface* compatible_surface,
+                              GpuPreference gpu_preference) {
+  DCHECK(compatible_surface);
+
+  gpu_preference = ui::GpuSwitchingManager::GetInstance()->AdjustGpuPreference(
+      gpu_preference);
+
+  GLContextCGL* share_context = share_group() ?
+      static_cast<GLContextCGL*>(share_group()->GetContext()) : nullptr;
+
+  CGLPixelFormatObj format = GetPixelFormat();
+  if (!format)
+    return false;
+
+  // If using the discrete gpu, create a pixel format requiring it before we
+  // create the context.
+  if (!ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus() ||
+      gpu_preference == PreferDiscreteGpu) {
+    std::vector<CGLPixelFormatAttribute> discrete_attribs;
+    discrete_attribs.push_back((CGLPixelFormatAttribute) 0);
+    GLint num_pixel_formats;
+    if (CGLChoosePixelFormat(&discrete_attribs.front(),
+                             &discrete_pixelformat_,
+                             &num_pixel_formats) != kCGLNoError) {
+      LOG(ERROR) << "Error choosing pixel format.";
+      return false;
+    }
+  }
+
+  CGLError res = CGLCreateContext(
+      format,
+      share_context ?
+          static_cast<CGLContextObj>(share_context->GetHandle()) : nullptr,
+      reinterpret_cast<CGLContextObj*>(&context_));
+  if (res != kCGLNoError) {
+    LOG(ERROR) << "Error creating context.";
+    Destroy();
+    return false;
+  }
+
+  gpu_preference_ = gpu_preference;
+  return true;
+}
+
+void GLContextCGL::Destroy() {
+  if (discrete_pixelformat_) {
+    if (base::MessageLoop::current() != nullptr) {
+      // Delay releasing the pixel format for 10 seconds to reduce the number of
+      // unnecessary GPU switches.
+      base::MessageLoop::current()->PostDelayedTask(
+          FROM_HERE, base::Bind(&CGLReleasePixelFormat, discrete_pixelformat_),
+          base::TimeDelta::FromSeconds(10));
+    } else {
+      CGLReleasePixelFormat(discrete_pixelformat_);
+    }
+    discrete_pixelformat_ = nullptr;
+  }
+  if (context_) {
+    CGLDestroyContext(static_cast<CGLContextObj>(context_));
+    context_ = nullptr;
+  }
+}
+
+bool GLContextCGL::ForceGpuSwitchIfNeeded() {
+  DCHECK(context_);
+  return true;
+}
+
+bool GLContextCGL::MakeCurrent(GLSurface* surface) {
+  DCHECK(context_);
+
+  if (!ForceGpuSwitchIfNeeded())
+    return false;
+
+  if (IsCurrent(surface))
+    return true;
+
+  ScopedReleaseCurrent release_current;
+  TRACE_EVENT0("gpu", "GLContextCGL::MakeCurrent");
+
+  if (CGLSetCurrentContext(
+      static_cast<CGLContextObj>(context_)) != kCGLNoError) {
+    LOG(ERROR) << "Unable to make gl context current.";
+    return false;
+  }
+
+  // Set this as soon as the context is current, since we might call into GL.
+  SetRealGLApi();
+
+  SetCurrent(surface);
+  if (!InitializeDynamicBindings()) {
+    return false;
+  }
+
+  if (!surface->OnMakeCurrent(this)) {
+    LOG(ERROR) << "Unable to make gl context current.";
+    return false;
+  }
+
+  release_current.Cancel();
+  return true;
+}
+
+void GLContextCGL::ReleaseCurrent(GLSurface* surface) {
+  if (!IsCurrent(surface))
+    return;
+
+  SetCurrent(nullptr);
+  CGLSetCurrentContext(nullptr);
+}
+
+bool GLContextCGL::IsCurrent(GLSurface* surface) {
+  bool native_context_is_current = CGLGetCurrentContext() == context_;
+
+  // If our context is current then our notion of which GLContext is
+  // current must be correct. On the other hand, third-party code
+  // using OpenGL might change the current context.
+  DCHECK(!native_context_is_current || (GetRealCurrent() == this));
+
+  if (!native_context_is_current)
+    return false;
+
+  return true;
+}
+
+void* GLContextCGL::GetHandle() {
+  return context_;
+}
+
+void GLContextCGL::OnSetSwapInterval(int interval) {
+  DCHECK(IsCurrent(nullptr));
+}
+
+bool GLContextCGL::GetTotalGpuMemory(size_t* bytes) {
+  DCHECK(bytes);
+  *bytes = 0;
+
+  CGLContextObj context = reinterpret_cast<CGLContextObj>(context_);
+  if (!context)
+    return false;
+
+  // Retrieve the current renderer ID
+  GLint current_renderer_id = 0;
+  if (CGLGetParameter(context,
+                      kCGLCPCurrentRendererID,
+                      &current_renderer_id) != kCGLNoError)
+    return false;
+
+  // Iterate through the list of all renderers
+  GLuint display_mask = static_cast<GLuint>(-1);
+  CGLRendererInfoObj renderer_info = nullptr;
+  GLint num_renderers = 0;
+  if (CGLQueryRendererInfo(display_mask,
+                           &renderer_info,
+                           &num_renderers) != kCGLNoError)
+    return false;
+
+  scoped_ptr<CGLRendererInfoObj,
+      CGLRendererInfoObjDeleter> scoper(&renderer_info);
+
+  for (GLint renderer_index = 0;
+       renderer_index < num_renderers;
+       ++renderer_index) {
+    // Skip this if this renderer is not the current renderer.
+    GLint renderer_id = 0;
+    if (CGLDescribeRenderer(renderer_info,
+                            renderer_index,
+                            kCGLRPRendererID,
+                            &renderer_id) != kCGLNoError)
+        continue;
+    if (renderer_id != current_renderer_id)
+        continue;
+    // Retrieve the video memory for the renderer.
+    GLint video_memory = 0;
+    if (CGLDescribeRenderer(renderer_info,
+                            renderer_index,
+                            kCGLRPVideoMemory,
+                            &video_memory) != kCGLNoError)
+        continue;
+    *bytes = video_memory;
+    return true;
+  }
+
+  return false;
+}
+
+void GLContextCGL::SetSafeToForceGpuSwitch() {
+  safe_to_force_gpu_switch_ = true;
+}
+
+
+GLContextCGL::~GLContextCGL() {
+  Destroy();
+}
+
+GpuPreference GLContextCGL::GetGpuPreference() {
+  return gpu_preference_;
+}
+
+}  // namespace gfx
diff --git a/ui/gl/gl_context_cgl.h b/ui/gl/gl_context_cgl.h
new file mode 100644
index 0000000..88813b3
--- /dev/null
+++ b/ui/gl/gl_context_cgl.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GL_GL_CONTEXT_CGL_H_
+#define UI_GL_GL_CONTEXT_CGL_H_
+
+#include <OpenGL/CGLTypes.h>
+
+#include "ui/gl/gl_context.h"
+
+namespace gfx {
+
+class GLSurface;
+
+// Encapsulates a CGL OpenGL context.
+class GLContextCGL : public GLContextReal {
+ public:
+  explicit GLContextCGL(GLShareGroup* share_group);
+
+  // Implement GLContext.
+  bool Initialize(GLSurface* compatible_surface,
+                  GpuPreference gpu_preference) override;
+  void Destroy() override;
+  bool MakeCurrent(GLSurface* surface) override;
+  void ReleaseCurrent(GLSurface* surface) override;
+  bool IsCurrent(GLSurface* surface) override;
+  void* GetHandle() override;
+  void OnSetSwapInterval(int interval) override;
+  bool GetTotalGpuMemory(size_t* bytes) override;
+  void SetSafeToForceGpuSwitch() override;
+  bool ForceGpuSwitchIfNeeded() override;
+
+ protected:
+  ~GLContextCGL() override;
+
+ private:
+  GpuPreference GetGpuPreference();
+
+  void* context_;
+  GpuPreference gpu_preference_;
+
+  CGLPixelFormatObj discrete_pixelformat_;
+
+  int screen_;
+  int renderer_id_;
+  bool safe_to_force_gpu_switch_;
+
+  DISALLOW_COPY_AND_ASSIGN(GLContextCGL);
+};
+
+}  // namespace gfx
+
+#endif  // UI_GL_GL_CONTEXT_CGL_H_
diff --git a/ui/gl/gl_context_mac.mm b/ui/gl/gl_context_mac.mm
new file mode 100644
index 0000000..389b80d
--- /dev/null
+++ b/ui/gl/gl_context_mac.mm
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/gl/gl_context_cgl.h"
+#include "ui/gl/gl_context_stub.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_switches.h"
+
+namespace gfx {
+
+class GLShareGroup;
+
+scoped_refptr<GLContext> GLContext::CreateGLContext(
+    GLShareGroup* share_group,
+    GLSurface* compatible_surface,
+    GpuPreference gpu_preference) {
+  TRACE_EVENT0("gpu", "GLContext::CreateGLContext");
+  switch (GetGLImplementation()) {
+    case kGLImplementationDesktopGL:
+    case kGLImplementationAppleGL: {
+      scoped_refptr<GLContext> context;
+      // Note that with virtualization we might still be able to make current
+      // a different onscreen surface with this context later. But we should
+      // always be creating the context with an offscreen surface first.
+      DCHECK(compatible_surface->IsOffscreen());
+      context = new GLContextCGL(share_group);
+      if (!context->Initialize(compatible_surface, gpu_preference))
+        return NULL;
+
+      return context;
+    }
+    case kGLImplementationMockGL:
+      return new GLContextStub;
+    default:
+      NOTREACHED();
+      return NULL;
+  }
+}
+
+}  // namespace gfx
diff --git a/ui/gl/gl_implementation_mac.cc b/ui/gl/gl_implementation_mac.cc
new file mode 100644
index 0000000..ae26dff
--- /dev/null
+++ b/ui/gl/gl_implementation_mac.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/native_library.h"
+#include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_stub_with_extensions.h"
+#include "ui/gl/gl_gl_api_implementation.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_osmesa_api_implementation.h"
+
+namespace gfx {
+namespace {
+const char kOpenGLFrameworkPath[] =
+    "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL";
+}  // namespace
+
+void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
+  impls->push_back(kGLImplementationDesktopGL);
+  impls->push_back(kGLImplementationAppleGL);
+  impls->push_back(kGLImplementationOSMesaGL);
+}
+
+bool InitializeStaticGLBindings(GLImplementation implementation) {
+  // Prevent reinitialization with a different implementation. Once the gpu
+  // unit tests have initialized with kGLImplementationMock, we don't want to
+  // later switch to another GL implementation.
+  DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
+
+  switch (implementation) {
+    case kGLImplementationOSMesaGL: {
+      // osmesa.so is located in the build directory. This code path is only
+      // valid in a developer build environment.
+      base::FilePath exe_path;
+      if (!PathService::Get(base::FILE_EXE, &exe_path)) {
+        LOG(ERROR) << "PathService::Get failed.";
+        return false;
+      }
+      base::FilePath bundle_path = base::mac::GetAppBundlePath(exe_path);
+      // Some unit test targets depend on osmesa but aren't built as app
+      // bundles. In that case, the .so is next to the executable.
+      if (bundle_path.empty())
+        bundle_path = exe_path;
+      base::FilePath build_dir_path = bundle_path.DirName();
+      base::FilePath osmesa_path = build_dir_path.Append("osmesa.so");
+
+      // When using OSMesa, just use OSMesaGetProcAddress to find entry points.
+      base::NativeLibrary library = base::LoadNativeLibrary(osmesa_path, NULL);
+      if (!library) {
+        LOG(ERROR) << "osmesa.so not found at " << osmesa_path.value();
+        return false;
+      }
+
+      GLGetProcAddressProc get_proc_address =
+          reinterpret_cast<GLGetProcAddressProc>(
+              base::GetFunctionPointerFromNativeLibrary(
+                  library, "OSMesaGetProcAddress"));
+      if (!get_proc_address) {
+        LOG(ERROR) << "OSMesaGetProcAddress not found.";
+        base::UnloadNativeLibrary(library);
+        return false;
+      }
+
+      SetGLGetProcAddressProc(get_proc_address);
+      AddGLNativeLibrary(library);
+      SetGLImplementation(kGLImplementationOSMesaGL);
+
+      InitializeStaticGLBindingsGL();
+      break;
+    }
+    case kGLImplementationDesktopGL:
+    case kGLImplementationAppleGL: {
+      base::NativeLibrary library = base::LoadNativeLibrary(
+          base::FilePath(kOpenGLFrameworkPath), NULL);
+      if (!library) {
+        LOG(ERROR) << "OpenGL framework not found";
+        return false;
+      }
+
+      AddGLNativeLibrary(library);
+      SetGLImplementation(implementation);
+
+      InitializeStaticGLBindingsGL();
+      break;
+    }
+    case kGLImplementationMockGL: {
+      SetGLImplementation(kGLImplementationMockGL);
+      InitializeStaticGLBindingsGL();
+      break;
+    }
+    default:
+      return false;
+  }
+
+  return true;
+}
+
+bool InitializeDynamicGLBindings(GLImplementation implementation,
+    GLContext* context) {
+  switch (implementation) {
+    case kGLImplementationOSMesaGL:
+    case kGLImplementationDesktopGL:
+    case kGLImplementationAppleGL:
+      InitializeDynamicGLBindingsGL(context);
+      break;
+    case kGLImplementationMockGL:
+      if (!context) {
+        scoped_refptr<GLContextStubWithExtensions> mock_context(
+            new GLContextStubWithExtensions());
+        mock_context->SetGLVersionString("3.0");
+        InitializeDynamicGLBindingsGL(mock_context.get());
+      } else
+        InitializeDynamicGLBindingsGL(context);
+      break;
+    default:
+      return false;
+  }
+
+  return true;
+}
+
+void InitializeDebugGLBindings() {
+  InitializeDebugGLBindingsGL();
+}
+
+void ClearGLBindings() {
+  ClearGLBindingsGL();
+  SetGLImplementation(kGLImplementationNone);
+
+  UnloadGLNativeLibraries();
+}
+
+bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
+  return false;
+}
+
+}  // namespace gfx
diff --git a/ui/gl/gl_surface_mac.cc b/ui/gl/gl_surface_mac.cc
new file mode 100644
index 0000000..28a8b85
--- /dev/null
+++ b/ui/gl/gl_surface_mac.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/gl_surface.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface_stub.h"
+#include "ui/gl/gpu_switching_manager.h"
+
+#include <OpenGL/CGLRenderers.h>
+#include <OpenGL/CGLTypes.h>
+
+extern "C" {
+// The header <OpenGL/OpenGL.h> may not be directly imported since it includes
+// gltypes.h which conflict with the types already included
+extern CGLError CGLChoosePixelFormat(const CGLPixelFormatAttribute *attribs,
+    CGLPixelFormatObj *pix, GLint *npix);
+extern void CGLReleasePixelFormat(CGLPixelFormatObj pix);
+}
+
+namespace gfx {
+namespace {
+
+// A "no-op" surface. It is not required that a CGLContextObj have an
+// associated drawable (pbuffer or fullscreen context) in order to be
+// made current. Everywhere this surface type is used, we allocate an
+// FBO at the user level as the drawable of the associated context.
+class GL_EXPORT NoOpGLSurface : public GLSurface {
+ public:
+  explicit NoOpGLSurface(const gfx::Size& size,
+                         const gfx::SurfaceConfiguration conf)
+      : GLSurface(conf),
+        size_(size) {}
+
+  // Implement GLSurface.
+  bool Initialize() override { return true; }
+  void Destroy() override {}
+  bool IsOffscreen() override { return true; }
+  bool SwapBuffers() override {
+    NOTREACHED() << "Cannot call SwapBuffers on a NoOpGLSurface.";
+    return false;
+  }
+  gfx::Size GetSize() override { return size_; }
+  void* GetHandle() override { return NULL; }
+  void* GetDisplay() override { return NULL; }
+  bool IsSurfaceless() const override { return true; }
+
+ protected:
+  ~NoOpGLSurface() override {}
+
+ private:
+  gfx::Size size_;
+
+  DISALLOW_COPY_AND_ASSIGN(NoOpGLSurface);
+};
+
+// static
+bool InitializeOneOffForSandbox() {
+  static bool initialized = false;
+  if (initialized)
+    return true;
+
+  // This is called from the sandbox warmup code on Mac OS X.
+  // GPU-related stuff is very slow without this, probably because
+  // the sandbox prevents loading graphics drivers or some such.
+  std::vector<CGLPixelFormatAttribute> attribs;
+  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+    // Avoid switching to the discrete GPU just for this pixel
+    // format selection.
+    attribs.push_back(kCGLPFAAllowOfflineRenderers);
+  }
+  if (GetGLImplementation() == kGLImplementationAppleGL) {
+    attribs.push_back(kCGLPFARendererID);
+    attribs.push_back(static_cast<CGLPixelFormatAttribute>(
+      kCGLRendererGenericFloatID));
+  }
+  attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+
+  CGLPixelFormatObj format;
+  GLint num_pixel_formats;
+  if (CGLChoosePixelFormat(&attribs.front(),
+                           &format,
+                           &num_pixel_formats) != kCGLNoError) {
+    LOG(ERROR) << "Error choosing pixel format.";
+    return false;
+  }
+  if (!format) {
+    LOG(ERROR) << "format == 0.";
+    return false;
+  }
+  CGLReleasePixelFormat(format);
+  DCHECK_NE(num_pixel_formats, 0);
+  initialized = true;
+  return true;
+}
+
+}  // namespace
+
+bool GLSurface::InitializeOneOffInternal() {
+  switch (GetGLImplementation()) {
+    case kGLImplementationDesktopGL:
+    case kGLImplementationAppleGL:
+      if (!InitializeOneOffForSandbox()) {
+        LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed.";
+        return false;
+      }
+      break;
+    default:
+      break;
+  }
+  return true;
+}
+
+scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
+    gfx::AcceleratedWidget window,
+    const gfx::SurfaceConfiguration& conf) {
+  TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
+  switch (GetGLImplementation()) {
+    case kGLImplementationDesktopGL:
+    case kGLImplementationAppleGL: {
+      NOTIMPLEMENTED() << "No onscreen support on Mac.";
+      return NULL;
+    }
+    case kGLImplementationMockGL:
+      return new GLSurfaceStub(conf);
+    default:
+      NOTREACHED();
+      return NULL;
+  }
+}
+
+scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
+    const gfx::Size& size,
+    const gfx::SurfaceConfiguration& conf) {
+  TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
+  switch (GetGLImplementation()) {
+    case kGLImplementationDesktopGL:
+    case kGLImplementationAppleGL: {
+      scoped_refptr<GLSurface> surface(new NoOpGLSurface(size, conf));
+      if (!surface->Initialize())
+        return NULL;
+
+      return surface;
+    }
+    case kGLImplementationMockGL:
+      return new GLSurfaceStub(conf);
+    default:
+      NOTREACHED();
+      return NULL;
+  }
+}
+
+}  // namespace gfx