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,
+ ¤t_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