summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-13 22:55:50 +0000
committerkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-13 22:55:50 +0000
commit276f89060fa4b38582dcd76ebdf9454bb7d42c8e (patch)
tree0ff1c47fed812c196ae491a6c7295164d557e813 /ui
parent91701aec11f289e96ce92b588b858b26179cb89c (diff)
downloadchromium_src-276f89060fa4b38582dcd76ebdf9454bb7d42c8e.zip
chromium_src-276f89060fa4b38582dcd76ebdf9454bb7d42c8e.tar.gz
chromium_src-276f89060fa4b38582dcd76ebdf9454bb7d42c8e.tar.bz2
Support dynamic switching between integrated and discrete GPUs on Mac OS X.
Change Chrome to allocate most OpenGL contexts with the kCGLPFAAllowOfflineRenderers flag, and specify NSSupportsAutomaticGraphicsSwitching in the Info.plist for the main executable and helper apps. This keeps Chrome on the integrated GPU except when using WebGL, accelerated 2D Canvas, Pepper 3D, and Core Animation-based plugins (except Flash). Chrome shares resources between OpenGL contexts in order to display WebGL and other content in the compositor, and resource sharing doesn't work between contexts allocated on different GPUs. Therefore, when the first context for a given renderer requests the discrete GPU, the channel is dropped and all contexts are reallocated on the discrete GPU. Similarly, when the last context requesting the discrete GPU for a given renderer is shut down, all contexts are dropped and reallocated on the integrated GPU. Currently dynamic GPU switching is only supported on the latest Mac OS X 10.7 update and MacBook Pros with dual AMD / Intel GPUs, though this will improve in future OS updates. Tested with WebGL, CSS 3D, Flash and Unity3D content and observed desired GPU switching behavior. Also added a layout test to WebKit under https://bugs.webkit.org/show_bug.cgi?id=69776 which when run in Chrome catches an assertion failure related to the destruction of contexts. The intent is to add it as a UI layout test on the GPU bots. BUG=88788 TEST=none Review URL: http://codereview.chromium.org/8233027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105399 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/gfx/compositor/compositor_gl.cc10
-rw-r--r--ui/gfx/gl/gl_context.h9
-rw-r--r--ui/gfx/gl/gl_context_cgl.cc50
-rw-r--r--ui/gfx/gl/gl_context_cgl.h6
-rw-r--r--ui/gfx/gl/gl_context_egl.cc3
-rw-r--r--ui/gfx/gl/gl_context_egl.h3
-rw-r--r--ui/gfx/gl/gl_context_glx.cc3
-rw-r--r--ui/gfx/gl/gl_context_glx.h3
-rw-r--r--ui/gfx/gl/gl_context_linux.cc13
-rw-r--r--ui/gfx/gl/gl_context_mac.cc102
-rw-r--r--ui/gfx/gl/gl_context_osmesa.cc3
-rw-r--r--ui/gfx/gl/gl_context_osmesa.h3
-rw-r--r--ui/gfx/gl/gl_context_stub.cc3
-rw-r--r--ui/gfx/gl/gl_context_stub.h3
-rw-r--r--ui/gfx/gl/gl_context_wgl.cc3
-rw-r--r--ui/gfx/gl/gl_context_wgl.h3
-rw-r--r--ui/gfx/gl/gl_context_win.cc13
-rw-r--r--ui/gfx/gl/gl_share_group.cc12
-rw-r--r--ui/gfx/gl/gl_share_group.h4
-rw-r--r--ui/gfx/gl/gl_surface_cgl.cc33
-rw-r--r--ui/gfx/gl/gpu_preference.h25
-rw-r--r--ui/gfx/surface/accelerated_surface_mac.cc12
-rw-r--r--ui/gfx/surface/accelerated_surface_mac.h14
23 files changed, 279 insertions, 54 deletions
diff --git a/ui/gfx/compositor/compositor_gl.cc b/ui/gfx/compositor/compositor_gl.cc
index b8eadfd..24d63ad 100644
--- a/ui/gfx/compositor/compositor_gl.cc
+++ b/ui/gfx/compositor/compositor_gl.cc
@@ -251,7 +251,10 @@ bool SharedResources::Initialize() {
return false;
}
- context_ = gfx::GLContext::CreateGLContext(NULL, surface_.get());
+ context_ = gfx::GLContext::CreateGLContext(
+ NULL,
+ surface_.get(),
+ gfx::PreferIntegratedGpu);
if (!context_.get()) {
LOG(ERROR) << "Unable to create GL context.";
return false;
@@ -303,7 +306,10 @@ bool SharedResources::MakeSharedContextCurrent() {
scoped_refptr<gfx::GLContext> SharedResources::CreateContext(
gfx::GLSurface* surface) {
if (initialized_)
- return gfx::GLContext::CreateGLContext(context_->share_group(), surface);
+ return gfx::GLContext::CreateGLContext(
+ context_->share_group(),
+ surface,
+ gfx::PreferIntegratedGpu);
else
return NULL;
}
diff --git a/ui/gfx/gl/gl_context.h b/ui/gfx/gl/gl_context.h
index 0a617f4..3046485 100644
--- a/ui/gfx/gl/gl_context.h
+++ b/ui/gfx/gl/gl_context.h
@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "ui/gfx/gl/gl_share_group.h"
+#include "ui/gfx/gl/gpu_preference.h"
namespace gfx {
@@ -25,7 +26,8 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
// context can be made with other surface's of the same type. The compatible
// surface is only needed for certain platforms like WGL, OSMesa and GLX. It
// should be specific for all platforms though.
- virtual bool Initialize(GLSurface* compatible_surface) = 0;
+ virtual bool Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference) = 0;
// Destroys the GL context.
virtual void Destroy() = 0;
@@ -60,10 +62,13 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
// internally created OpenGL context shares textures and other resources.
static scoped_refptr<GLContext> CreateGLContext(
GLShareGroup* share_group,
- GLSurface* compatible_surface);
+ GLSurface* compatible_surface,
+ GpuPreference gpu_preference);
static bool LosesAllContextsOnContextLost();
+ static bool SupportsDualGpus();
+
static GLContext* GetCurrent();
virtual bool WasAllocatedUsingARBRobustness();
diff --git a/ui/gfx/gl/gl_context_cgl.cc b/ui/gfx/gl/gl_context_cgl.cc
index 005af00..a759793 100644
--- a/ui/gfx/gl/gl_context_cgl.cc
+++ b/ui/gfx/gl/gl_context_cgl.cc
@@ -4,6 +4,8 @@
#include "ui/gfx/gl/gl_context_cgl.h"
+#include <vector>
+
#include "base/logging.h"
#include "ui/gfx/gl/gl_bindings.h"
#include "ui/gfx/gl/gl_surface_cgl.h"
@@ -12,27 +14,61 @@ namespace gfx {
GLContextCGL::GLContextCGL(GLShareGroup* share_group)
: GLContext(share_group),
- context_(NULL) {
+ context_(NULL),
+ gpu_preference_(PreferIntegratedGpu) {
}
GLContextCGL::~GLContextCGL() {
Destroy();
}
-bool GLContextCGL::Initialize(GLSurface* compatible_surface) {
+bool GLContextCGL::Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference) {
DCHECK(compatible_surface);
+ // Ensure the GPU preference is compatible with contexts already in the
+ // share group.
+ GLContextCGL* share_context = share_group() ?
+ static_cast<GLContextCGL*>(share_group()->GetContext()) : NULL;
+ if (share_context && gpu_preference != share_context->GetGpuPreference())
+ return false;
+
+ std::vector<CGLPixelFormatAttribute> attribs;
+ attribs.push_back(kCGLPFAPBuffer);
+ bool using_offline_renderer =
+ SupportsDualGpus() && gpu_preference == PreferIntegratedGpu;
+ if (using_offline_renderer) {
+ attribs.push_back(kCGLPFAAllowOfflineRenderers);
+ }
+ attribs.push_back((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;
+ }
+ DCHECK_NE(num_pixel_formats, 0);
+
CGLError res = CGLCreateContext(
- static_cast<CGLPixelFormatObj>(GLSurfaceCGL::GetPixelFormat()),
- share_group() ?
- static_cast<CGLContextObj>(share_group()->GetHandle()) : NULL,
+ format,
+ share_context ?
+ static_cast<CGLContextObj>(share_context->GetHandle()) : NULL,
reinterpret_cast<CGLContextObj*>(&context_));
+ CGLReleasePixelFormat(format);
if (res != kCGLNoError) {
LOG(ERROR) << "Error creating context.";
Destroy();
return false;
}
+ gpu_preference_ = gpu_preference;
return true;
}
@@ -115,4 +151,8 @@ void GLContextCGL::SetSwapInterval(int interval) {
LOG(WARNING) << "GLContex: GLContextCGL::SetSwapInterval is ignored.";
}
+GpuPreference GLContextCGL::GetGpuPreference() {
+ return gpu_preference_;
+}
+
} // namespace gfx
diff --git a/ui/gfx/gl/gl_context_cgl.h b/ui/gfx/gl/gl_context_cgl.h
index 14b59b3..af918de 100644
--- a/ui/gfx/gl/gl_context_cgl.h
+++ b/ui/gfx/gl/gl_context_cgl.h
@@ -15,7 +15,8 @@ class GLContextCGL : public GLContext {
virtual ~GLContextCGL();
// Implement GLContext.
- virtual bool Initialize(GLSurface* compatible_surface);
+ virtual bool Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference);
virtual void Destroy();
virtual bool MakeCurrent(GLSurface* surface);
virtual void ReleaseCurrent(GLSurface* surface);
@@ -25,6 +26,9 @@ class GLContextCGL : public GLContext {
private:
void* context_;
+ GpuPreference gpu_preference_;
+
+ GpuPreference GetGpuPreference();
DISALLOW_COPY_AND_ASSIGN(GLContextCGL);
};
diff --git a/ui/gfx/gl/gl_context_egl.cc b/ui/gfx/gl/gl_context_egl.cc
index a86c0d7..dea684b 100644
--- a/ui/gfx/gl/gl_context_egl.cc
+++ b/ui/gfx/gl/gl_context_egl.cc
@@ -42,7 +42,8 @@ GLContextEGL::~GLContextEGL() {
Destroy();
}
-bool GLContextEGL::Initialize(GLSurface* compatible_surface) {
+bool GLContextEGL::Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference) {
DCHECK(compatible_surface);
DCHECK(!context_);
diff --git a/ui/gfx/gl/gl_context_egl.h b/ui/gfx/gl/gl_context_egl.h
index 5a86f28..c429d5e7 100644
--- a/ui/gfx/gl/gl_context_egl.h
+++ b/ui/gfx/gl/gl_context_egl.h
@@ -25,7 +25,8 @@ class GLContextEGL : public GLContext {
virtual ~GLContextEGL();
// Implement GLContext.
- virtual bool Initialize(GLSurface* compatible_surface);
+ virtual bool Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference);
virtual void Destroy();
virtual bool MakeCurrent(GLSurface* surface);
virtual void ReleaseCurrent(GLSurface* surface);
diff --git a/ui/gfx/gl/gl_context_glx.cc b/ui/gfx/gl/gl_context_glx.cc
index 8e6cc06..071107a 100644
--- a/ui/gfx/gl/gl_context_glx.cc
+++ b/ui/gfx/gl/gl_context_glx.cc
@@ -53,7 +53,8 @@ GLContextGLX::~GLContextGLX() {
Destroy();
}
-bool GLContextGLX::Initialize(GLSurface* compatible_surface) {
+bool GLContextGLX::Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference) {
GLSurfaceGLX* surface_glx = static_cast<GLSurfaceGLX*>(compatible_surface);
GLXContext share_handle = static_cast<GLXContext>(
diff --git a/ui/gfx/gl/gl_context_glx.h b/ui/gfx/gl/gl_context_glx.h
index 5432df7..3f8a535 100644
--- a/ui/gfx/gl/gl_context_glx.h
+++ b/ui/gfx/gl/gl_context_glx.h
@@ -17,7 +17,8 @@ class GLContextGLX : public GLContext {
virtual ~GLContextGLX();
// Implement GLContext.
- virtual bool Initialize(GLSurface* compatible_surface);
+ virtual bool Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference);
virtual void Destroy();
virtual bool MakeCurrent(GLSurface* surface);
virtual void ReleaseCurrent(GLSurface* surface);
diff --git a/ui/gfx/gl/gl_context_linux.cc b/ui/gfx/gl/gl_context_linux.cc
index 083b1ff..a6f7525 100644
--- a/ui/gfx/gl/gl_context_linux.cc
+++ b/ui/gfx/gl/gl_context_linux.cc
@@ -24,19 +24,20 @@ class GLShareGroup;
scoped_refptr<GLContext> GLContext::CreateGLContext(
GLShareGroup* share_group,
- GLSurface* compatible_surface) {
+ GLSurface* compatible_surface,
+ GpuPreference gpu_preference) {
switch (GetGLImplementation()) {
#if !defined(USE_WAYLAND)
case kGLImplementationOSMesaGL: {
scoped_refptr<GLContext> context(new GLContextOSMesa(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
}
case kGLImplementationDesktopGL: {
scoped_refptr<GLContext> context(new GLContextGLX(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
@@ -44,7 +45,7 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(
#endif
case kGLImplementationEGLGLES2: {
scoped_refptr<GLContext> context(new GLContextEGL(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
@@ -57,4 +58,8 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(
}
}
+bool GLContext::SupportsDualGpus() {
+ return false;
+}
+
} // namespace gfx
diff --git a/ui/gfx/gl/gl_context_mac.cc b/ui/gfx/gl/gl_context_mac.cc
index cdfc6f4..0c870e2 100644
--- a/ui/gfx/gl/gl_context_mac.cc
+++ b/ui/gfx/gl/gl_context_mac.cc
@@ -4,6 +4,8 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/memory/scoped_generic_obj.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/mesa/MesaLib/include/GL/osmesa.h"
#include "ui/gfx/gl/gl_bindings.h"
@@ -14,24 +16,37 @@
#include "ui/gfx/gl/gl_surface_cgl.h"
#include "ui/gfx/gl/gl_surface_osmesa.h"
+namespace {
+
+// ScopedGenericObj functor for CGLDestroyRendererInfo().
+class ScopedDestroyRendererInfo {
+ public:
+ void operator()(CGLRendererInfoObj x) const {
+ CGLDestroyRendererInfo(x);
+ }
+};
+
+} // namespace
+
namespace gfx {
class GLShareGroup;
scoped_refptr<GLContext> GLContext::CreateGLContext(
GLShareGroup* share_group,
- GLSurface* compatible_surface) {
+ GLSurface* compatible_surface,
+ GpuPreference gpu_preference) {
switch (GetGLImplementation()) {
case kGLImplementationDesktopGL: {
scoped_refptr<GLContext> context(new GLContextCGL(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
}
case kGLImplementationOSMesaGL: {
scoped_refptr<GLContext> context(new GLContextOSMesa(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
@@ -44,4 +59,85 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(
}
}
+bool GLContext::SupportsDualGpus() {
+ // We need to know the GL implementation in order to correctly
+ // answer whether dual GPUs are supported. This introduces an
+ // initialization cycle with GLSurface::InitializeOneOff() which we
+ // need to break.
+ static bool initialized = false;
+ static bool initializing = false;
+ static bool supports_dual_gpus = false;
+
+ if (initialized) {
+ return supports_dual_gpus;
+ } else {
+ if (!initializing) {
+ initializing = true;
+ if (!GLSurface::InitializeOneOff()) {
+ return false;
+ }
+ }
+ initialized = true;
+ }
+
+ if (!base::mac::IsOSLionOrLater()) {
+ return false;
+ }
+
+ if (GetGLImplementation() != kGLImplementationDesktopGL) {
+ return false;
+ }
+
+ // Enumerate all hardware-accelerated renderers. If we find one
+ // online and one offline, assume we're on a dual-GPU system.
+ GLuint display_mask = static_cast<GLuint>(-1);
+ CGLRendererInfoObj renderer_info = NULL;
+ GLint num_renderers = 0;
+
+ bool found_online = false;
+ bool found_offline = false;
+
+ if (CGLQueryRendererInfo(display_mask,
+ &renderer_info,
+ &num_renderers) != kCGLNoError) {
+ return false;
+ }
+
+ ScopedGenericObj<CGLRendererInfoObj, ScopedDestroyRendererInfo>
+ scoper(renderer_info);
+
+ for (GLint i = 0; i < num_renderers; ++i) {
+ GLint accelerated = 0;
+ if (CGLDescribeRenderer(renderer_info,
+ i,
+ kCGLRPAccelerated,
+ &accelerated) != kCGLNoError) {
+ return false;
+ }
+
+ if (!accelerated)
+ continue;
+
+ GLint online = 0;
+ if (CGLDescribeRenderer(renderer_info,
+ i,
+ kCGLRPOnline,
+ &online) != kCGLNoError) {
+ return false;
+ }
+
+ if (online) {
+ found_online = true;
+ } else {
+ found_offline = true;
+ }
+ }
+
+ if (found_online && found_offline) {
+ supports_dual_gpus = true;
+ }
+
+ return supports_dual_gpus;
+}
+
} // namespace gfx
diff --git a/ui/gfx/gl/gl_context_osmesa.cc b/ui/gfx/gl/gl_context_osmesa.cc
index e35d645..6b56f9d 100644
--- a/ui/gfx/gl/gl_context_osmesa.cc
+++ b/ui/gfx/gl/gl_context_osmesa.cc
@@ -21,7 +21,8 @@ GLContextOSMesa::~GLContextOSMesa() {
Destroy();
}
-bool GLContextOSMesa::Initialize(GLSurface* compatible_surface) {
+bool GLContextOSMesa::Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference) {
DCHECK(!context_);
OSMesaContext share_handle = static_cast<OSMesaContext>(
diff --git a/ui/gfx/gl/gl_context_osmesa.h b/ui/gfx/gl/gl_context_osmesa.h
index 6b4c0a9..65d6853 100644
--- a/ui/gfx/gl/gl_context_osmesa.h
+++ b/ui/gfx/gl/gl_context_osmesa.h
@@ -22,7 +22,8 @@ class GLContextOSMesa : public GLContext {
virtual ~GLContextOSMesa();
// Implement GLContext.
- virtual bool Initialize(GLSurface* compatible_surface);
+ virtual bool Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference);
virtual void Destroy();
virtual bool MakeCurrent(GLSurface* surface);
virtual void ReleaseCurrent(GLSurface* surface);
diff --git a/ui/gfx/gl/gl_context_stub.cc b/ui/gfx/gl/gl_context_stub.cc
index 82b7b94..5067413 100644
--- a/ui/gfx/gl/gl_context_stub.cc
+++ b/ui/gfx/gl/gl_context_stub.cc
@@ -12,7 +12,8 @@ GLContextStub::GLContextStub() : GLContext(NULL) {
GLContextStub::~GLContextStub() {
}
-bool GLContextStub::Initialize(GLSurface* compatible_surface) {
+bool GLContextStub::Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference) {
return true;
}
diff --git a/ui/gfx/gl/gl_context_stub.h b/ui/gfx/gl/gl_context_stub.h
index cb2ff6b..da391b9 100644
--- a/ui/gfx/gl/gl_context_stub.h
+++ b/ui/gfx/gl/gl_context_stub.h
@@ -17,7 +17,8 @@ class GL_EXPORT GLContextStub : public GLContext {
virtual ~GLContextStub();
// Implement GLContext.
- virtual bool Initialize(GLSurface* compatible_surface);
+ virtual bool Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference);
virtual void Destroy();
virtual bool MakeCurrent(GLSurface* surface);
virtual void ReleaseCurrent(GLSurface* surface);
diff --git a/ui/gfx/gl/gl_context_wgl.cc b/ui/gfx/gl/gl_context_wgl.cc
index f096ca6..bf44450 100644
--- a/ui/gfx/gl/gl_context_wgl.cc
+++ b/ui/gfx/gl/gl_context_wgl.cc
@@ -37,7 +37,8 @@ std::string GLContextWGL::GetExtensions() {
return GLContext::GetExtensions();
}
-bool GLContextWGL::Initialize(GLSurface* compatible_surface) {
+bool GLContextWGL::Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference) {
GLSurfaceWGL* surface_wgl = static_cast<GLSurfaceWGL*>(compatible_surface);
// TODO(apatrick): When contexts and surfaces are separated, we won't be
diff --git a/ui/gfx/gl/gl_context_wgl.h b/ui/gfx/gl/gl_context_wgl.h
index 3684c96..4d20bc7 100644
--- a/ui/gfx/gl/gl_context_wgl.h
+++ b/ui/gfx/gl/gl_context_wgl.h
@@ -21,7 +21,8 @@ class GLContextWGL : public GLContext {
virtual ~GLContextWGL();
// Implement GLContext.
- virtual bool Initialize(GLSurface* compatible_surface);
+ virtual bool Initialize(
+ GLSurface* compatible_surface, GpuPreference gpu_preference);
virtual void Destroy();
virtual bool MakeCurrent(GLSurface* surface);
virtual void ReleaseCurrent(GLSurface* surface);
diff --git a/ui/gfx/gl/gl_context_win.cc b/ui/gfx/gl/gl_context_win.cc
index 3ca5f3b..65ce32d 100644
--- a/ui/gfx/gl/gl_context_win.cc
+++ b/ui/gfx/gl/gl_context_win.cc
@@ -22,25 +22,26 @@ namespace gfx {
scoped_refptr<GLContext> GLContext::CreateGLContext(
GLShareGroup* share_group,
- GLSurface* compatible_surface) {
+ GLSurface* compatible_surface,
+ GpuPreference gpu_preference) {
switch (GetGLImplementation()) {
case kGLImplementationOSMesaGL: {
scoped_refptr<GLContext> context(new GLContextOSMesa(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
}
case kGLImplementationEGLGLES2: {
scoped_refptr<GLContext> context(new GLContextEGL(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
}
case kGLImplementationDesktopGL: {
scoped_refptr<GLContext> context(new GLContextWGL(share_group));
- if (!context->Initialize(compatible_surface))
+ if (!context->Initialize(compatible_surface, gpu_preference))
return NULL;
return context;
@@ -53,4 +54,8 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(
}
}
+bool GLContext::SupportsDualGpus() {
+ return false;
+}
+
} // namespace gfx
diff --git a/ui/gfx/gl/gl_share_group.cc b/ui/gfx/gl/gl_share_group.cc
index fa2bfcb..21c175e 100644
--- a/ui/gfx/gl/gl_share_group.cc
+++ b/ui/gfx/gl/gl_share_group.cc
@@ -20,11 +20,19 @@ void GLShareGroup::RemoveContext(GLContext* context) {
}
void* GLShareGroup::GetHandle() {
+ GLContext* context = GetContext();
+ if (context)
+ return context->GetHandle();
+
+ return NULL;
+}
+
+GLContext* GLShareGroup::GetContext() {
for (ContextSet::iterator it = contexts_.begin();
it != contexts_.end();
++it) {
- if ((*it)->GetHandle())
- return (*it)->GetHandle();
+ if ((*it)->GetHandle())
+ return *it;
}
return NULL;
diff --git a/ui/gfx/gl/gl_share_group.h b/ui/gfx/gl/gl_share_group.h
index a9f7529..8df2fb2 100644
--- a/ui/gfx/gl/gl_share_group.h
+++ b/ui/gfx/gl/gl_share_group.h
@@ -30,6 +30,10 @@ class GL_EXPORT GLShareGroup : public base::RefCounted<GLShareGroup> {
// there are no initialized contexts in the share group.
void* GetHandle();
+ // Returns a pointer to any initialized context in the share group
+ // or NULL if there are no initialized contexts in the share group.
+ GLContext* GetContext();
+
private:
friend class base::RefCounted<GLShareGroup>;
~GLShareGroup();
diff --git a/ui/gfx/gl/gl_surface_cgl.cc b/ui/gfx/gl/gl_surface_cgl.cc
index ec14cfc..695d744 100644
--- a/ui/gfx/gl/gl_surface_cgl.cc
+++ b/ui/gfx/gl/gl_surface_cgl.cc
@@ -6,7 +6,9 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/mac/mac_util.h"
#include "ui/gfx/gl/gl_bindings.h"
+#include "ui/gfx/gl/gl_context.h"
namespace gfx {
@@ -25,26 +27,31 @@ bool GLSurfaceCGL::InitializeOneOff() {
if (initialized)
return true;
- static const CGLPixelFormatAttribute attribs[] = {
- (CGLPixelFormatAttribute) kCGLPFAPBuffer,
- (CGLPixelFormatAttribute) 0
- };
+ // 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 (GLContext::SupportsDualGpus()) {
+ // Avoid switching to the discrete GPU just for this pixel
+ // format selection.
+ attribs.push_back(kCGLPFAAllowOfflineRenderers);
+ }
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+
+ CGLPixelFormatObj format;
GLint num_pixel_formats;
- if (CGLChoosePixelFormat(attribs,
- &g_pixel_format,
+ if (CGLChoosePixelFormat(&attribs.front(),
+ &format,
&num_pixel_formats) != kCGLNoError) {
LOG(ERROR) << "Error choosing pixel format.";
return false;
}
- if (num_pixel_formats == 0) {
- LOG(ERROR) << "num_pixel_formats == 0.";
+ if (!format) {
+ LOG(ERROR) << "format == 0.";
return false;
}
- if (!g_pixel_format) {
- LOG(ERROR) << "pixel_format == 0.";
- return false;
- }
-
+ CGLReleasePixelFormat(format);
+ DCHECK_NE(num_pixel_formats, 0);
initialized = true;
return true;
}
diff --git a/ui/gfx/gl/gpu_preference.h b/ui/gfx/gl/gpu_preference.h
new file mode 100644
index 0000000..189ed3d
--- /dev/null
+++ b/ui/gfx/gl/gpu_preference.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 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_GFX_GL_GPU_PREFERENCE_H_
+#define UI_GFX_GL_GPU_PREFERENCE_H_
+#pragma once
+
+namespace gfx {
+
+// On dual-GPU systems, expresses a preference for using the integrated
+// or discrete GPU. On systems that have dual-GPU support (see
+// GLContext::SupportsDualGpus), resource sharing only works between
+// contexts that are created with the same GPU preference.
+//
+// This API will likely need to be adjusted as the functionality is
+// implemented on more operating systems.
+enum GpuPreference {
+ PreferIntegratedGpu,
+ PreferDiscreteGpu
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GL_GPU_PREFERENCE_H_
diff --git a/ui/gfx/surface/accelerated_surface_mac.cc b/ui/gfx/surface/accelerated_surface_mac.cc
index d6b63cd..759ae81 100644
--- a/ui/gfx/surface/accelerated_surface_mac.cc
+++ b/ui/gfx/surface/accelerated_surface_mac.cc
@@ -24,8 +24,10 @@ AcceleratedSurface::AcceleratedSurface()
AcceleratedSurface::~AcceleratedSurface() {}
-bool AcceleratedSurface::Initialize(gfx::GLContext* share_context,
- bool allocate_fbo) {
+bool AcceleratedSurface::Initialize(
+ gfx::GLContext* share_context,
+ bool allocate_fbo,
+ gfx::GpuPreference gpu_preference) {
allocate_fbo_ = allocate_fbo;
// Ensure GL is initialized before trying to create an offscreen GL context.
@@ -47,8 +49,10 @@ bool AcceleratedSurface::Initialize(gfx::GLContext* share_context,
gfx::GLShareGroup* share_group =
share_context ? share_context->share_group() : NULL;
- gl_context_ = gfx::GLContext::CreateGLContext(share_group,
- gl_surface_.get());
+ gl_context_ = gfx::GLContext::CreateGLContext(
+ share_group,
+ gl_surface_.get(),
+ gpu_preference);
if (!gl_context_.get()) {
Destroy();
return false;
diff --git a/ui/gfx/surface/accelerated_surface_mac.h b/ui/gfx/surface/accelerated_surface_mac.h
index 5163a57..0e29ae5 100644
--- a/ui/gfx/surface/accelerated_surface_mac.h
+++ b/ui/gfx/surface/accelerated_surface_mac.h
@@ -11,10 +11,11 @@
#include "base/callback_old.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
#include "ui/gfx/gl/gl_context.h"
#include "ui/gfx/gl/gl_surface.h"
+#include "ui/gfx/gl/gpu_preference.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
#include "ui/gfx/surface/surface_export.h"
#include "ui/gfx/surface/transport_dib.h"
@@ -46,9 +47,14 @@ class SURFACE_EXPORT AcceleratedSurface {
// an FBO internally does NOT work properly with client code which uses
// OpenGL (i.e., via GLES2 command buffers), because the GLES2
// implementation does not know to bind the accelerated surface's
- // internal FBO when the default FBO is bound. Returns false upon
+ // internal FBO when the default FBO is bound. |gpu_preference| indicates
+ // the GPU preference for the internally allocated GLContext. If
+ // |share_context| is non-NULL, then on platforms supporting dual GPUs,
+ // its GPU preference must match the passed one. Returns false upon
// failure.
- bool Initialize(gfx::GLContext* share_context, bool allocate_fbo);
+ bool Initialize(gfx::GLContext* share_context,
+ bool allocate_fbo,
+ gfx::GpuPreference gpu_preference);
// Tear down. Must be called before destructor to prevent leaks.
void Destroy();