diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-12 00:25:46 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-12 00:25:46 +0000 |
commit | e134cf21752f90003a17fe0a0d38a05fe2728edb (patch) | |
tree | 2f9a59be1e117bb1d14660bc94f7d884e03e169c /ui | |
parent | e4d9a972ed8350b5e45f5da90b2a1b5ab47c1ca7 (diff) | |
download | chromium_src-e134cf21752f90003a17fe0a0d38a05fe2728edb.zip chromium_src-e134cf21752f90003a17fe0a0d38a05fe2728edb.tar.gz chromium_src-e134cf21752f90003a17fe0a0d38a05fe2728edb.tar.bz2 |
Reland 85013 - Split GLContext::Create*GLContext into GLSurface::Create*GLSurface plus a surface type independent GLContext::CreateGLContext.
TEST=webgl on windows and mac, trybots
BUG=none
Review URL: http://codereview.chromium.org/6997003
Review URL: http://codereview.chromium.org/7015016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85081 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/gfx/compositor/compositor_gl.cc | 15 | ||||
-rw-r--r-- | ui/gfx/gl/gl.gyp | 5 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context.h | 21 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_linux.cc | 316 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_mac.cc | 53 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_osmesa.cc | 1 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_stub.cc | 20 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_stub.h | 8 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_win.cc | 232 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface.cc | 6 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface.h | 14 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_linux.cc | 306 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_mac.cc | 103 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_osmesa.cc | 1 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_stub.cc | 31 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_stub.h | 33 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_win.cc | 231 | ||||
-rw-r--r-- | ui/gfx/surface/accelerated_surface_mac.cc | 17 |
18 files changed, 818 insertions, 595 deletions
diff --git a/ui/gfx/compositor/compositor_gl.cc b/ui/gfx/compositor/compositor_gl.cc index 4beb65c..fa8e100 100644 --- a/ui/gfx/compositor/compositor_gl.cc +++ b/ui/gfx/compositor/compositor_gl.cc @@ -9,9 +9,10 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "ui/gfx/transform.h" -#include "ui/gfx/gl/gl_context.h" #include "ui/gfx/gl/gl_bindings.h" +#include "ui/gfx/gl/gl_context.h" #include "ui/gfx/gl/gl_implementation.h" +#include "ui/gfx/gl/gl_surface.h" namespace ui { @@ -38,8 +39,10 @@ class CompositorGL : public Compositor { }; CompositorGL::CompositorGL(gfx::AcceleratedWidget widget) - : gl_context_(gfx::GLContext::CreateViewGLContext(widget, false)), - started_(false) { + : started_(false) { + scoped_ptr<gfx::GLSurface> surface( + gfx::GLSurface::CreateViewGLSurface(widget)); + gl_context_.reset(gfx::GLContext::CreateGLContext(surface.release(), NULL)), } Texture* CompositorGL::CreateTexture() { @@ -89,8 +92,10 @@ class CompositorGL : public Compositor { }; CompositorGL::CompositorGL(gfx::AcceleratedWidget widget) - : gl_context_(gfx::GLContext::CreateViewGLContext(widget, false)), - started_(false) { + : started_(false) { + scoped_ptr<gfx::GLSurface> surface( + gfx::GLSurface::CreateViewGLSurface(widget)); + gl_context_.reset(gfx::GLContext::CreateGLContext(surface.release(), NULL)); } void CompositorGL::NotifyStart() { diff --git a/ui/gfx/gl/gl.gyp b/ui/gfx/gl/gl.gyp index 4e45a72..83acee4 100644 --- a/ui/gfx/gl/gl.gyp +++ b/ui/gfx/gl/gl.gyp @@ -76,6 +76,11 @@ 'gl_interface.h', 'gl_surface.cc', 'gl_surface.h', + 'gl_surface_linux.cc', + 'gl_surface_mac.cc', + 'gl_surface_stub.cc', + 'gl_surface_stub.h', + 'gl_surface_win.cc', 'gl_surface_osmesa.cc', 'gl_surface_osmesa.h', 'gl_switches.cc', diff --git a/ui/gfx/gl/gl_context.h b/ui/gfx/gl/gl_context.h index b27f8c9..548b6ae 100644 --- a/ui/gfx/gl/gl_context.h +++ b/ui/gfx/gl/gl_context.h @@ -66,19 +66,14 @@ class GLContext { // context must be current. bool HasExtension(const char* name); - static bool InitializeOneOff(); - -#if !defined(OS_MACOSX) - // Create a GL context that renders directly to a view. - static GLContext* CreateViewGLContext(gfx::PluginWindowHandle window, - bool multisampled); -#endif - - // Create a GL context used for offscreen rendering. It is initially backed by - // a 1x1 pbuffer. Use it to create an FBO to do useful rendering. - // |share_context|, if non-NULL, is a context which the internally created - // OpenGL context shares textures and other resources. - static GLContext* CreateOffscreenGLContext(GLContext* shared_context); + // Create a GL context that is compatible with the given surface. + // |share_context|, if non-NULL, is a context which the + // internally created OpenGL context shares textures and other resources. + // TODO(apatrick): For the time being, the context will take ownership of the + // surface and the surface will be made the current read and draw surface + // when the context is made current. + static GLContext* CreateGLContext(GLSurface* compatible_surface, + GLContext* shared_context); static bool LosesAllContextsOnContextLost(); diff --git a/ui/gfx/gl/gl_context_linux.cc b/ui/gfx/gl/gl_context_linux.cc index deac474..3db60f3 100644 --- a/ui/gfx/gl/gl_context_linux.cc +++ b/ui/gfx/gl/gl_context_linux.cc @@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <GL/osmesa.h> +#include "ui/gfx/gl/gl_context.h" -#include "base/basictypes.h" #include "base/logging.h" -#include "ui/base/x/x11_util.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" #include "ui/gfx/gl/gl_bindings.h" -#include "ui/gfx/gl/gl_context.h" #include "ui/gfx/gl/gl_context_egl.h" #include "ui/gfx/gl/gl_context_glx.h" #include "ui/gfx/gl/gl_context_osmesa.h" @@ -16,322 +15,45 @@ #include "ui/gfx/gl/gl_implementation.h" #include "ui/gfx/gl/gl_surface_egl.h" #include "ui/gfx/gl/gl_surface_glx.h" +#include "ui/gfx/gl/gl_surface_stub.h" #include "ui/gfx/gl/gl_surface_osmesa.h" namespace gfx { -namespace { -Display* g_osmesa_display; -} // namespace anonymous - -// This OSMesa GL surface can use XLib to swap the contents of the buffer to a -// view. -class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { - public: - explicit NativeViewGLSurfaceOSMesa(gfx::PluginWindowHandle window); - virtual ~NativeViewGLSurfaceOSMesa(); - - static bool InitializeOneOff(); - - // Initializes the GL context. - bool Initialize(); - - // Implement a subset of GLSurface. - virtual void Destroy(); - virtual bool IsOffscreen(); - virtual bool SwapBuffers(); - - private: - bool UpdateSize(); - - GC window_graphics_context_; - gfx::PluginWindowHandle window_; - GC pixmap_graphics_context_; - Pixmap pixmap_; - - DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); -}; - -bool GLContext::InitializeOneOff() { - static bool initialized = false; - if (initialized) - return true; - - static const GLImplementation kAllowedGLImplementations[] = { - kGLImplementationDesktopGL, - kGLImplementationEGLGLES2, - kGLImplementationOSMesaGL - }; - - if (!InitializeRequestedGLBindings( - kAllowedGLImplementations, - kAllowedGLImplementations + arraysize(kAllowedGLImplementations), - kGLImplementationDesktopGL)) { - LOG(ERROR) << "InitializeRequestedGLBindings failed."; - return false; - } - - switch (GetGLImplementation()) { - case kGLImplementationDesktopGL: - if (!GLSurfaceGLX::InitializeOneOff()) { - LOG(ERROR) << "GLSurfaceGLX::InitializeOneOff failed."; - return false; - } - break; - case kGLImplementationEGLGLES2: - if (!GLSurfaceEGL::InitializeOneOff()) { - LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; - return false; - } - break; - case kGLImplementationOSMesaGL: - if (!NativeViewGLSurfaceOSMesa::InitializeOneOff()) { - LOG(ERROR) << "NativeViewGLSurfaceOSMesa::InitializeOneOff failed."; - return false; - } - break; - default: - break; - } - - initialized = true; - return true; -} - -NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( - gfx::PluginWindowHandle window) - : window_graphics_context_(0), - window_(window), - pixmap_graphics_context_(0), - pixmap_(0) { - DCHECK(window); -} - -NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { - Destroy(); -} - -bool NativeViewGLSurfaceOSMesa::InitializeOneOff() { - static bool initialized = false; - if (initialized) - return true; - - g_osmesa_display = XOpenDisplay(NULL); - if (!g_osmesa_display) { - LOG(ERROR) << "XOpenDisplay failed."; - return false; - } - - initialized = true; - return true; -} - -bool NativeViewGLSurfaceOSMesa::Initialize() { - window_graphics_context_ = XCreateGC(g_osmesa_display, - window_, - 0, - NULL); - if (!window_graphics_context_) { - LOG(ERROR) << "XCreateGC failed."; - Destroy(); - return false; - } - - UpdateSize(); - - return true; -} - -void NativeViewGLSurfaceOSMesa::Destroy() { - if (pixmap_graphics_context_) { - XFreeGC(g_osmesa_display, pixmap_graphics_context_); - pixmap_graphics_context_ = NULL; - } - - if (pixmap_) { - XFreePixmap(g_osmesa_display, pixmap_); - pixmap_ = 0; - } - - if (window_graphics_context_) { - XFreeGC(g_osmesa_display, window_graphics_context_); - window_graphics_context_ = NULL; - } -} - -bool NativeViewGLSurfaceOSMesa::IsOffscreen() { - return false; -} - -bool NativeViewGLSurfaceOSMesa::SwapBuffers() { - // Update the size before blitting so that the blit size is exactly the same - // as the window. - if (!UpdateSize()) { - LOG(ERROR) << "Failed to update size of GLContextOSMesa."; - return false; - } - - gfx::Size size = GetSize(); - - // Copy the frame into the pixmap. - XWindowAttributes attributes; - XGetWindowAttributes(g_osmesa_display, window_, &attributes); - ui::PutARGBImage(g_osmesa_display, - attributes.visual, - attributes.depth, - pixmap_, - pixmap_graphics_context_, - static_cast<const uint8*>(GetHandle()), - size.width(), - size.height()); - - // Copy the pixmap to the window. - XCopyArea(g_osmesa_display, - pixmap_, - window_, - window_graphics_context_, - 0, 0, - size.width(), size.height(), - 0, 0); - - return true; -} - -bool NativeViewGLSurfaceOSMesa::UpdateSize() { - // Get the window size. - XWindowAttributes attributes; - XGetWindowAttributes(g_osmesa_display, window_, &attributes); - gfx::Size window_size = gfx::Size(std::max(1, attributes.width), - std::max(1, attributes.height)); - - // Early out if the size has not changed. - gfx::Size osmesa_size = GetSize(); - if (pixmap_graphics_context_ && pixmap_ && window_size == osmesa_size) - return true; - - // Change osmesa surface size to that of window. - Resize(window_size); +GLContext* GLContext::CreateGLContext(GLSurface* compatible_surface, + GLContext* shared_context) { + scoped_ptr<GLSurface> surface(compatible_surface); - // Destroy the previous pixmap and graphics context. - if (pixmap_graphics_context_) { - XFreeGC(g_osmesa_display, pixmap_graphics_context_); - pixmap_graphics_context_ = NULL; - } - if (pixmap_) { - XFreePixmap(g_osmesa_display, pixmap_); - pixmap_ = 0; - } - - // Recreate a pixmap to hold the frame. - pixmap_ = XCreatePixmap(g_osmesa_display, - window_, - window_size.width(), - window_size.height(), - attributes.depth); - if (!pixmap_) { - LOG(ERROR) << "XCreatePixmap failed."; - return false; - } - - // Recreate a graphics context for the pixmap. - pixmap_graphics_context_ = XCreateGC(g_osmesa_display, pixmap_, 0, NULL); - if (!pixmap_graphics_context_) { - LOG(ERROR) << "XCreateGC failed"; - return false; - } - - return true; -} - -GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window, - bool multisampled) { switch (GetGLImplementation()) { - case kGLImplementationDesktopGL: { - scoped_ptr<GLSurfaceGLX> surface(new NativeViewGLSurfaceGLX(window)); - if (!surface->Initialize()) { - return NULL; - } - - scoped_ptr<GLContextGLX> context( - new GLContextGLX(surface.release())); - if (!context->Initialize(NULL)) - return NULL; - - return context.release(); - } - case kGLImplementationEGLGLES2: { - scoped_ptr<NativeViewGLSurfaceEGL> surface(new NativeViewGLSurfaceEGL( - window)); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextEGL> context( - new GLContextEGL(surface.release())); - if (!context->Initialize(NULL)) - return NULL; - - return context.release(); - } case kGLImplementationOSMesaGL: { - scoped_ptr<NativeViewGLSurfaceOSMesa> surface( - new NativeViewGLSurfaceOSMesa(window)); - if (!surface->Initialize()) - return NULL; - scoped_ptr<GLContextOSMesa> context( - new GLContextOSMesa(surface.release())); - if (!context->Initialize(OSMESA_BGRA, NULL)) - return NULL; - - return context.release(); - } - case kGLImplementationMockGL: - return new StubGLContext; - default: - NOTREACHED(); - return NULL; - } -} - -GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { - switch (GetGLImplementation()) { - case kGLImplementationDesktopGL: { - scoped_ptr<PbufferGLSurfaceGLX> surface(new PbufferGLSurfaceGLX( - gfx::Size(1, 1))); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextGLX> context(new GLContextGLX(surface.release())); - if (!context->Initialize(shared_context)) + new GLContextOSMesa(static_cast<GLSurfaceOSMesa*>( + surface.release()))); + if (!context->Initialize(OSMESA_RGBA, shared_context)) return NULL; return context.release(); } case kGLImplementationEGLGLES2: { - scoped_ptr<PbufferGLSurfaceEGL> surface(new PbufferGLSurfaceEGL( - gfx::Size(1, 1))); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextEGL> context(new GLContextEGL(surface.release())); + scoped_ptr<GLContextEGL> context( + new GLContextEGL( + static_cast<GLSurfaceEGL*>(surface.release()))); if (!context->Initialize(shared_context)) return NULL; return context.release(); } - case kGLImplementationOSMesaGL: { - scoped_ptr<GLSurfaceOSMesa> surface(new GLSurfaceOSMesa()); - surface->Resize(gfx::Size(1, 1)); - - scoped_ptr<GLContextOSMesa> context( - new GLContextOSMesa(surface.release())); - if (!context->Initialize(OSMESA_BGRA, shared_context)) + case kGLImplementationDesktopGL: { + scoped_ptr<GLContextGLX> context( + new GLContextGLX( + static_cast<GLSurfaceGLX*>(surface.release()))); + if (!context->Initialize(shared_context)) return NULL; return context.release(); } case kGLImplementationMockGL: - return new StubGLContext; + return new GLContextStub; default: NOTREACHED(); return NULL; diff --git a/ui/gfx/gl/gl_context_mac.cc b/ui/gfx/gl/gl_context_mac.cc index fbb18b0..91ca660 100644 --- a/ui/gfx/gl/gl_context_mac.cc +++ b/ui/gfx/gl/gl_context_mac.cc @@ -16,66 +16,31 @@ namespace gfx { -bool GLContext::InitializeOneOff() { - static bool initialized = false; - if (initialized) - return true; - - static const GLImplementation kAllowedGLImplementations[] = { - kGLImplementationDesktopGL, - kGLImplementationOSMesaGL - }; - - if (!InitializeRequestedGLBindings( - kAllowedGLImplementations, - kAllowedGLImplementations + arraysize(kAllowedGLImplementations), - kGLImplementationDesktopGL)) { - LOG(ERROR) << "InitializeRequestedGLBindings failed."; - return false; - } +GLContext* GLContext::CreateGLContext(GLSurface* compatible_surface, + GLContext* shared_context) { + scoped_ptr<GLSurface> surface(compatible_surface); switch (GetGLImplementation()) { - case kGLImplementationDesktopGL: - if (!GLSurfaceCGL::InitializeOneOff()) { - LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed."; - return false; - } - break; - default: - break; - } - - initialized = true; - return true; -} - -GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { - switch (GetGLImplementation()) { case kGLImplementationDesktopGL: { - scoped_ptr<PbufferGLSurfaceCGL> surface(new PbufferGLSurfaceCGL( - gfx::Size(1, 1))); - if (!surface->Initialize()) - return false; - - scoped_ptr<GLContextCGL> context(new GLContextCGL(surface.release())); + scoped_ptr<GLContextCGL> context( + new GLContextCGL( + static_cast<GLSurfaceCGL*>(surface.release()))); if (!context->Initialize(shared_context)) return NULL; return context.release(); } case kGLImplementationOSMesaGL: { - scoped_ptr<GLSurfaceOSMesa> surface(new GLSurfaceOSMesa()); - surface->Resize(gfx::Size(1, 1)); - scoped_ptr<GLContextOSMesa> context( - new GLContextOSMesa(surface.release())); + new GLContextOSMesa( + static_cast<GLSurfaceOSMesa*>(surface.release()))); if (!context->Initialize(OSMESA_RGBA, shared_context)) return NULL; return context.release(); } case kGLImplementationMockGL: - return new StubGLContext; + return new GLContextStub; default: NOTREACHED(); return NULL; diff --git a/ui/gfx/gl/gl_context_osmesa.cc b/ui/gfx/gl/gl_context_osmesa.cc index 6da01d1..d6c2a07 100644 --- a/ui/gfx/gl/gl_context_osmesa.cc +++ b/ui/gfx/gl/gl_context_osmesa.cc @@ -19,6 +19,7 @@ GLContextOSMesa::GLContextOSMesa(GLSurfaceOSMesa* surface) } GLContextOSMesa::~GLContextOSMesa() { + Destroy(); } bool GLContextOSMesa::Initialize(GLuint format, GLContext* shared_context) { diff --git a/ui/gfx/gl/gl_context_stub.cc b/ui/gfx/gl/gl_context_stub.cc index 6462f61..4154cdd 100644 --- a/ui/gfx/gl/gl_context_stub.cc +++ b/ui/gfx/gl/gl_context_stub.cc @@ -6,33 +6,37 @@ namespace gfx { -StubGLContext::~StubGLContext() {} +GLContextStub::GLContextStub() { +} + +GLContextStub::~GLContextStub() { +} -bool StubGLContext::MakeCurrent() { +bool GLContextStub::MakeCurrent() { return true; } -bool StubGLContext::IsCurrent() { +bool GLContextStub::IsCurrent() { return true; } -bool StubGLContext::IsOffscreen() { +bool GLContextStub::IsOffscreen() { return false; } -bool StubGLContext::SwapBuffers() { +bool GLContextStub::SwapBuffers() { return true; } -gfx::Size StubGLContext::GetSize() { +gfx::Size GLContextStub::GetSize() { return size_; } -void* StubGLContext::GetHandle() { +void* GLContextStub::GetHandle() { return NULL; } -std::string StubGLContext::GetExtensions() { +std::string GLContextStub::GetExtensions() { return std::string(); } diff --git a/ui/gfx/gl/gl_context_stub.h b/ui/gfx/gl/gl_context_stub.h index 03e5cf4..37c49d1 100644 --- a/ui/gfx/gl/gl_context_stub.h +++ b/ui/gfx/gl/gl_context_stub.h @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file implements the StubGLContext. - #ifndef UI_GFX_GL_GL_CONTEXT_STUB_H_ #define UI_GFX_GL_GL_CONTEXT_STUB_H_ #pragma once @@ -13,9 +11,10 @@ namespace gfx { // A GLContext that does nothing for unit tests. -class StubGLContext : public gfx::GLContext { +class GLContextStub : public GLContext { public: - virtual ~StubGLContext(); + GLContextStub(); + virtual ~GLContextStub(); void SetSize(const gfx::Size& size) { size_ = size; } @@ -32,6 +31,7 @@ class StubGLContext : public gfx::GLContext { private: gfx::Size size_; + DISALLOW_COPY_AND_ASSIGN(GLContextStub); }; } // namespace gfx diff --git a/ui/gfx/gl/gl_context_win.cc b/ui/gfx/gl/gl_context_win.cc index 83e4198..ff5c142 100644 --- a/ui/gfx/gl/gl_context_win.cc +++ b/ui/gfx/gl/gl_context_win.cc @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file implements the NativeViewGLContext and PbufferGLContext classes. - -#include <algorithm> - #include "ui/gfx/gl/gl_context.h" #include "base/logging.h" @@ -19,247 +15,45 @@ #include "ui/gfx/gl/gl_implementation.h" #include "ui/gfx/gl/gl_surface_egl.h" #include "ui/gfx/gl/gl_surface_osmesa.h" +#include "ui/gfx/gl/gl_surface_stub.h" #include "ui/gfx/gl/gl_surface_wgl.h" namespace gfx { -// This OSMesa GL surface can use GDI to swap the contents of the buffer to a -// view. -class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { - public: - explicit NativeViewGLSurfaceOSMesa(gfx::PluginWindowHandle window); - virtual ~NativeViewGLSurfaceOSMesa(); - - // Initializes the GL context. - bool Initialize(); - - // Implement subset of GLSurface. - virtual void Destroy(); - virtual bool IsOffscreen(); - virtual bool SwapBuffers(); - - private: - void UpdateSize(); - - gfx::PluginWindowHandle window_; - HDC device_context_; - - DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); -}; - -// Helper routine that does one-off initialization like determining the -// pixel format and initializing the GL bindings. -bool GLContext::InitializeOneOff() { - static bool initialized = false; - if (initialized) - return true; - - static const GLImplementation kAllowedGLImplementations[] = { - kGLImplementationEGLGLES2, - kGLImplementationDesktopGL, - kGLImplementationOSMesaGL - }; - - if (!InitializeRequestedGLBindings( - kAllowedGLImplementations, - kAllowedGLImplementations + arraysize(kAllowedGLImplementations), - kGLImplementationEGLGLES2)) { - LOG(ERROR) << "InitializeRequestedGLBindings failed."; - return false; - } +GLContext* GLContext::CreateGLContext(GLSurface* compatible_surface, + GLContext* shared_context) { + scoped_ptr<GLSurface> surface(compatible_surface); switch (GetGLImplementation()) { - case kGLImplementationDesktopGL: - if (!GLSurfaceWGL::InitializeOneOff()) { - LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed."; - return false; - } - break; - case kGLImplementationEGLGLES2: - if (!GLSurfaceEGL::InitializeOneOff()) { - LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; - return false; - } - break; - } - - initialized = true; - return true; -} - -NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( - gfx::PluginWindowHandle window) - : window_(window), - device_context_(NULL) { - DCHECK(window); -} - -NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { - Destroy(); -} - -bool NativeViewGLSurfaceOSMesa::Initialize() { - device_context_ = GetDC(window_); - UpdateSize(); - return true; -} - -void NativeViewGLSurfaceOSMesa::Destroy() { - if (window_ && device_context_) - ReleaseDC(window_, device_context_); - - window_ = NULL; - device_context_ = NULL; - - GLSurfaceOSMesa::Destroy(); -} - -bool NativeViewGLSurfaceOSMesa::IsOffscreen() { - return false; -} - -bool NativeViewGLSurfaceOSMesa::SwapBuffers() { - DCHECK(device_context_); - - // Update the size before blitting so that the blit size is exactly the same - // as the window. - UpdateSize(); - - gfx::Size size = GetSize(); - - // Note: negating the height below causes GDI to treat the bitmap data as row - // 0 being at the top. - BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) }; - info.bV4Width = size.width(); - info.bV4Height = -size.height(); - info.bV4Planes = 1; - info.bV4BitCount = 32; - info.bV4V4Compression = BI_BITFIELDS; - info.bV4RedMask = 0x000000FF; - info.bV4GreenMask = 0x0000FF00; - info.bV4BlueMask = 0x00FF0000; - info.bV4AlphaMask = 0xFF000000; - - // Copy the back buffer to the window's device context. Do not check whether - // StretchDIBits succeeds or not. It will fail if the window has been - // destroyed but it is preferable to allow rendering to silently fail if the - // window is destroyed. This is because the primary application of this - // class of GLContext is for testing and we do not want every GL related ui / - // browser test to become flaky if there is a race condition between GL - // context destruction and window destruction. - StretchDIBits(device_context_, - 0, 0, size.width(), size.height(), - 0, 0, size.width(), size.height(), - GetHandle(), - reinterpret_cast<BITMAPINFO*>(&info), - DIB_RGB_COLORS, - SRCCOPY); - - return true; -} - -void NativeViewGLSurfaceOSMesa::UpdateSize() { - // Change back buffer size to that of window. If window handle is invalid, do - // not change the back buffer size. - RECT rect; - if (!GetClientRect(window_, &rect)) - return; - - gfx::Size window_size = gfx::Size( - std::max(1, static_cast<int>(rect.right - rect.left)), - std::max(1, static_cast<int>(rect.bottom - rect.top))); - Resize(window_size); -} - -GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window, - bool multisampled) { - switch (GetGLImplementation()) { case kGLImplementationOSMesaGL: { - scoped_ptr<NativeViewGLSurfaceOSMesa> surface( - new NativeViewGLSurfaceOSMesa(window)); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextOSMesa> context( - new GLContextOSMesa(surface.release())); - if (!context->Initialize(OSMESA_RGBA, NULL)) - return NULL; - - return context.release(); - } - case kGLImplementationEGLGLES2: { - scoped_ptr<NativeViewGLSurfaceEGL> surface(new NativeViewGLSurfaceEGL( - window)); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextEGL> context( - new GLContextEGL(surface.release())); - if (!context->Initialize(NULL)) - return NULL; - - return context.release(); - } - case kGLImplementationDesktopGL: { - scoped_ptr<NativeViewGLSurfaceWGL> surface(new NativeViewGLSurfaceWGL( - window)); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextWGL> context( - new GLContextWGL(surface.release())); - if (!context->Initialize(NULL)) - return NULL; - - return context.release(); - } - case kGLImplementationMockGL: - return new StubGLContext; - default: - NOTREACHED(); - return NULL; - } -} - -GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { - switch (GetGLImplementation()) { - case kGLImplementationOSMesaGL: { - scoped_ptr<GLSurfaceOSMesa> surface(new GLSurfaceOSMesa()); - surface->Resize(gfx::Size(1, 1)); - scoped_ptr<GLContextOSMesa> context( - new GLContextOSMesa(surface.release())); + new GLContextOSMesa(static_cast<GLSurfaceOSMesa*>( + surface.release()))); if (!context->Initialize(OSMESA_RGBA, shared_context)) return NULL; return context.release(); } case kGLImplementationEGLGLES2: { - scoped_ptr<PbufferGLSurfaceEGL> surface(new PbufferGLSurfaceEGL( - gfx::Size(1, 1))); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextEGL> context(new GLContextEGL(surface.release())); + scoped_ptr<GLContextEGL> context( + new GLContextEGL(static_cast<GLSurfaceEGL*>( + surface.release()))); if (!context->Initialize(shared_context)) return NULL; return context.release(); } case kGLImplementationDesktopGL: { - scoped_ptr<PbufferGLSurfaceWGL> surface(new PbufferGLSurfaceWGL( - gfx::Size(1, 1))); - if (!surface->Initialize()) - return NULL; - - scoped_ptr<GLContextWGL> context(new GLContextWGL(surface.release())); + scoped_ptr<GLContextWGL> context( + new GLContextWGL(static_cast<GLSurfaceWGL*>( + surface.release()))); if (!context->Initialize(shared_context)) return NULL; return context.release(); } case kGLImplementationMockGL: - return new StubGLContext; + return new GLContextStub; default: NOTREACHED(); return NULL; diff --git a/ui/gfx/gl/gl_surface.cc b/ui/gfx/gl/gl_surface.cc index de4b8a2..3e4cb7e 100644 --- a/ui/gfx/gl/gl_surface.cc +++ b/ui/gfx/gl/gl_surface.cc @@ -6,6 +6,12 @@ namespace gfx { +GLSurface::GLSurface() { +} + +GLSurface::~GLSurface() { +} + bool GLSurface::Initialize() { return true; diff --git a/ui/gfx/gl/gl_surface.h b/ui/gfx/gl/gl_surface.h index ca8afd1..9c1dcc4 100644 --- a/ui/gfx/gl/gl_surface.h +++ b/ui/gfx/gl/gl_surface.h @@ -16,8 +16,8 @@ namespace gfx { // specific management. class GLSurface { public: - GLSurface() {} - virtual ~GLSurface() {} + GLSurface(); + virtual ~GLSurface(); // (Re)create the surface. TODO(apatrick): This is an ugly hack to allow the // EGL surface associated to be recreated without destroying the associated @@ -45,6 +45,16 @@ class GLSurface { // FBO. Otherwise returns 0. virtual unsigned int GetBackingFrameBufferObject(); + static bool InitializeOneOff(); + +#if !defined(OS_MACOSX) + // Create a GL surface that renders directly to a view. + static GLSurface* CreateViewGLSurface(gfx::PluginWindowHandle window); +#endif + + // Create a GL surface used for offscreen rendering. + static GLSurface* CreateOffscreenGLSurface(const gfx::Size& size); + private: DISALLOW_COPY_AND_ASSIGN(GLSurface); }; diff --git a/ui/gfx/gl/gl_surface_linux.cc b/ui/gfx/gl/gl_surface_linux.cc new file mode 100644 index 0000000..b1f6db1 --- /dev/null +++ b/ui/gfx/gl/gl_surface_linux.cc @@ -0,0 +1,306 @@ +// 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. + +#include "ui/gfx/gl/gl_surface.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gfx/gl/gl_bindings.h" +#include "ui/gfx/gl/gl_implementation.h" +#include "ui/gfx/gl/gl_surface_egl.h" +#include "ui/gfx/gl/gl_surface_glx.h" +#include "ui/gfx/gl/gl_surface_osmesa.h" +#include "ui/gfx/gl/gl_surface_stub.h" + +namespace gfx { + +namespace { +Display* g_osmesa_display; +} // namespace anonymous + +// This OSMesa GL surface can use XLib to swap the contents of the buffer to a +// view. +class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { + public: + explicit NativeViewGLSurfaceOSMesa(gfx::PluginWindowHandle window); + virtual ~NativeViewGLSurfaceOSMesa(); + + static bool InitializeOneOff(); + + // Initializes the GL context. + bool Initialize(); + + // Implement a subset of GLSurface. + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + + private: + bool UpdateSize(); + + GC window_graphics_context_; + gfx::PluginWindowHandle window_; + GC pixmap_graphics_context_; + Pixmap pixmap_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); +}; + +bool GLSurface::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + static const GLImplementation kAllowedGLImplementations[] = { + kGLImplementationDesktopGL, + kGLImplementationEGLGLES2, + kGLImplementationOSMesaGL + }; + + if (!InitializeRequestedGLBindings( + kAllowedGLImplementations, + kAllowedGLImplementations + arraysize(kAllowedGLImplementations), + kGLImplementationDesktopGL)) { + LOG(ERROR) << "InitializeRequestedGLBindings failed."; + return false; + } + + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + if (!GLSurfaceGLX::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceGLX::InitializeOneOff failed."; + return false; + } + break; + case kGLImplementationEGLGLES2: + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; + return false; + } + break; + case kGLImplementationOSMesaGL: + if (!NativeViewGLSurfaceOSMesa::InitializeOneOff()) { + LOG(ERROR) << "NativeViewGLSurfaceOSMesa::InitializeOneOff failed."; + return false; + } + break; + default: + break; + } + + initialized = true; + return true; +} + +NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( + gfx::PluginWindowHandle window) + : window_graphics_context_(0), + window_(window), + pixmap_graphics_context_(0), + pixmap_(0) { + DCHECK(window); +} + +NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { + Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + g_osmesa_display = XOpenDisplay(NULL); + if (!g_osmesa_display) { + LOG(ERROR) << "XOpenDisplay failed."; + return false; + } + + initialized = true; + return true; +} + +bool NativeViewGLSurfaceOSMesa::Initialize() { + window_graphics_context_ = XCreateGC(g_osmesa_display, + window_, + 0, + NULL); + if (!window_graphics_context_) { + LOG(ERROR) << "XCreateGC failed."; + Destroy(); + return false; + } + + UpdateSize(); + + return true; +} + +void NativeViewGLSurfaceOSMesa::Destroy() { + if (pixmap_graphics_context_) { + XFreeGC(g_osmesa_display, pixmap_graphics_context_); + pixmap_graphics_context_ = NULL; + } + + if (pixmap_) { + XFreePixmap(g_osmesa_display, pixmap_); + pixmap_ = 0; + } + + if (window_graphics_context_) { + XFreeGC(g_osmesa_display, window_graphics_context_); + window_graphics_context_ = NULL; + } +} + +bool NativeViewGLSurfaceOSMesa::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceOSMesa::SwapBuffers() { + // Update the size before blitting so that the blit size is exactly the same + // as the window. + if (!UpdateSize()) { + LOG(ERROR) << "Failed to update size of GLContextOSMesa."; + return false; + } + + gfx::Size size = GetSize(); + + // Copy the frame into the pixmap. + XWindowAttributes attributes; + XGetWindowAttributes(g_osmesa_display, window_, &attributes); + ui::PutARGBImage(g_osmesa_display, + attributes.visual, + attributes.depth, + pixmap_, + pixmap_graphics_context_, + static_cast<const uint8*>(GetHandle()), + size.width(), + size.height()); + + // Copy the pixmap to the window. + XCopyArea(g_osmesa_display, + pixmap_, + window_, + window_graphics_context_, + 0, 0, + size.width(), size.height(), + 0, 0); + + return true; +} + +bool NativeViewGLSurfaceOSMesa::UpdateSize() { + // Get the window size. + XWindowAttributes attributes; + XGetWindowAttributes(g_osmesa_display, window_, &attributes); + gfx::Size window_size = gfx::Size(std::max(1, attributes.width), + std::max(1, attributes.height)); + + // Early out if the size has not changed. + gfx::Size osmesa_size = GetSize(); + if (pixmap_graphics_context_ && pixmap_ && window_size == osmesa_size) + return true; + + // Change osmesa surface size to that of window. + Resize(window_size); + + // Destroy the previous pixmap and graphics context. + if (pixmap_graphics_context_) { + XFreeGC(g_osmesa_display, pixmap_graphics_context_); + pixmap_graphics_context_ = NULL; + } + if (pixmap_) { + XFreePixmap(g_osmesa_display, pixmap_); + pixmap_ = 0; + } + + // Recreate a pixmap to hold the frame. + pixmap_ = XCreatePixmap(g_osmesa_display, + window_, + window_size.width(), + window_size.height(), + attributes.depth); + if (!pixmap_) { + LOG(ERROR) << "XCreatePixmap failed."; + return false; + } + + // Recreate a graphics context for the pixmap. + pixmap_graphics_context_ = XCreateGC(g_osmesa_display, pixmap_, 0, NULL); + if (!pixmap_graphics_context_) { + LOG(ERROR) << "XCreateGC failed"; + return false; + } + + return true; +} + +GLSurface* GLSurface::CreateViewGLSurface(gfx::PluginWindowHandle window) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_ptr<NativeViewGLSurfaceOSMesa> surface( + new NativeViewGLSurfaceOSMesa(window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationEGLGLES2: { + scoped_ptr<NativeViewGLSurfaceEGL> surface(new NativeViewGLSurfaceEGL( + window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationDesktopGL: { + scoped_ptr<NativeViewGLSurfaceGLX> surface(new NativeViewGLSurfaceGLX( + window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +GLSurface* GLSurface::CreateOffscreenGLSurface(const gfx::Size& size) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_ptr<GLSurfaceOSMesa> surface(new GLSurfaceOSMesa()); + surface->Resize(size); + + return surface.release(); + } + case kGLImplementationEGLGLES2: { + scoped_ptr<PbufferGLSurfaceEGL> surface(new PbufferGLSurfaceEGL(size)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationDesktopGL: { + scoped_ptr<PbufferGLSurfaceGLX> surface(new PbufferGLSurfaceGLX(size)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +} // namespace gfx diff --git a/ui/gfx/gl/gl_surface_mac.cc b/ui/gfx/gl/gl_surface_mac.cc new file mode 100644 index 0000000..2fe1f0e --- /dev/null +++ b/ui/gfx/gl/gl_surface_mac.cc @@ -0,0 +1,103 @@ +// 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. + +#include "ui/gfx/gl/gl_surface.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gfx/gl/gl_bindings.h" +#include "ui/gfx/gl/gl_implementation.h" +#include "ui/gfx/gl/gl_surface_cgl.h" +#include "ui/gfx/gl/gl_surface_osmesa.h" +#include "ui/gfx/gl/gl_surface_stub.h" + +namespace gfx { + +bool GLSurface::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + static const GLImplementation kAllowedGLImplementations[] = { + kGLImplementationDesktopGL, + kGLImplementationOSMesaGL + }; + + if (!InitializeRequestedGLBindings( + kAllowedGLImplementations, + kAllowedGLImplementations + arraysize(kAllowedGLImplementations), + kGLImplementationDesktopGL)) { + LOG(ERROR) << "InitializeRequestedGLBindings failed."; + return false; + } + + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + if (!GLSurfaceCGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed."; + return false; + } + break; + default: + break; + } + + initialized = true; + return true; +} + +// TODO(apatrick): support ViewGLSurface on mac. +#if 0 +GLSurface* GLSurface::CreateViewGLSurface(gfx::PluginWindowHandle window) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_ptr<NativeViewGLSurfaceOSMesa> surface( + new NativeViewGLSurfaceOSMesa(window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationDesktopGL: { + scoped_ptr<NativeViewGLSurfaceCGL> surface(new NativeViewGLSurfaceCGL( + window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} +#endif + +GLSurface* GLSurface::CreateOffscreenGLSurface(const gfx::Size& size) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_ptr<GLSurfaceOSMesa> surface(new GLSurfaceOSMesa()); + surface->Resize(size); + + return surface.release(); + } + case kGLImplementationDesktopGL: { + scoped_ptr<PbufferGLSurfaceCGL> surface(new PbufferGLSurfaceCGL(size)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +} // namespace gfx diff --git a/ui/gfx/gl/gl_surface_osmesa.cc b/ui/gfx/gl/gl_surface_osmesa.cc index 6ac4f02..191b2ce 100644 --- a/ui/gfx/gl/gl_surface_osmesa.cc +++ b/ui/gfx/gl/gl_surface_osmesa.cc @@ -13,6 +13,7 @@ GLSurfaceOSMesa::GLSurfaceOSMesa() } GLSurfaceOSMesa::~GLSurfaceOSMesa() { + Destroy(); } void GLSurfaceOSMesa::Resize(const gfx::Size& new_size) { diff --git a/ui/gfx/gl/gl_surface_stub.cc b/ui/gfx/gl/gl_surface_stub.cc new file mode 100644 index 0000000..bdea1bd --- /dev/null +++ b/ui/gfx/gl/gl_surface_stub.cc @@ -0,0 +1,31 @@ +// 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. + +#include "ui/gfx/gl/gl_surface_stub.h" + +namespace gfx { + +GLSurfaceStub::~GLSurfaceStub() { +} + +void GLSurfaceStub::Destroy() { +} + +bool GLSurfaceStub::IsOffscreen() { + return false; +} + +bool GLSurfaceStub::SwapBuffers() { + return true; +} + +gfx::Size GLSurfaceStub::GetSize() { + return size_; +} + +void* GLSurfaceStub::GetHandle() { + return NULL; +} + +} // namespace gfx diff --git a/ui/gfx/gl/gl_surface_stub.h b/ui/gfx/gl/gl_surface_stub.h new file mode 100644 index 0000000..da494be --- /dev/null +++ b/ui/gfx/gl/gl_surface_stub.h @@ -0,0 +1,33 @@ +// 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_GL_SURFACE_STUB_H_ +#define UI_GFX_GL_GL_SURFACE_STUB_H_ +#pragma once + +#include "ui/gfx/gl/gl_surface.h" + +namespace gfx { + +// A GLSurface that does nothing for unit tests. +class GLSurfaceStub : public GLSurface { + public: + virtual ~GLSurfaceStub(); + + void SetSize(const gfx::Size& size) { size_ = size; } + + // Implement GLSurface. + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual void* GetHandle(); + + private: + gfx::Size size_; +}; + +} // namespace gfx + +#endif // UI_GFX_GL_GL_SURFACE_STUB_H_ diff --git a/ui/gfx/gl/gl_surface_win.cc b/ui/gfx/gl/gl_surface_win.cc new file mode 100644 index 0000000..4c0b15d --- /dev/null +++ b/ui/gfx/gl/gl_surface_win.cc @@ -0,0 +1,231 @@ +// 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. + +#include "ui/gfx/gl/gl_surface.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/mesa/MesaLib/include/GL/osmesa.h" +#include "ui/gfx/gl/gl_bindings.h" +#include "ui/gfx/gl/gl_implementation.h" +#include "ui/gfx/gl/gl_surface_egl.h" +#include "ui/gfx/gl/gl_surface_osmesa.h" +#include "ui/gfx/gl/gl_surface_stub.h" +#include "ui/gfx/gl/gl_surface_wgl.h" + +namespace gfx { + +// This OSMesa GL surface can use GDI to swap the contents of the buffer to a +// view. +class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa { + public: + explicit NativeViewGLSurfaceOSMesa(gfx::PluginWindowHandle window); + virtual ~NativeViewGLSurfaceOSMesa(); + + // Initializes the GL context. + bool Initialize(); + + // Implement subset of GLSurface. + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + + private: + void UpdateSize(); + + gfx::PluginWindowHandle window_; + HDC device_context_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa); +}; + +// Helper routine that does one-off initialization like determining the +// pixel format and initializing the GL bindings. +bool GLSurface::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + + static const GLImplementation kAllowedGLImplementations[] = { + kGLImplementationEGLGLES2, + kGLImplementationDesktopGL, + kGLImplementationOSMesaGL + }; + + if (!InitializeRequestedGLBindings( + kAllowedGLImplementations, + kAllowedGLImplementations + arraysize(kAllowedGLImplementations), + kGLImplementationEGLGLES2)) { + LOG(ERROR) << "InitializeRequestedGLBindings failed."; + return false; + } + + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: + if (!GLSurfaceWGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed."; + return false; + } + break; + case kGLImplementationEGLGLES2: + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; + return false; + } + break; + } + + initialized = true; + return true; +} + +NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa( + gfx::PluginWindowHandle window) + : window_(window), + device_context_(NULL) { + DCHECK(window); +} + +NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() { + Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::Initialize() { + device_context_ = GetDC(window_); + UpdateSize(); + return true; +} + +void NativeViewGLSurfaceOSMesa::Destroy() { + if (window_ && device_context_) + ReleaseDC(window_, device_context_); + + window_ = NULL; + device_context_ = NULL; + + GLSurfaceOSMesa::Destroy(); +} + +bool NativeViewGLSurfaceOSMesa::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceOSMesa::SwapBuffers() { + DCHECK(device_context_); + + // Update the size before blitting so that the blit size is exactly the same + // as the window. + UpdateSize(); + + gfx::Size size = GetSize(); + + // Note: negating the height below causes GDI to treat the bitmap data as row + // 0 being at the top. + BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) }; + info.bV4Width = size.width(); + info.bV4Height = -size.height(); + info.bV4Planes = 1; + info.bV4BitCount = 32; + info.bV4V4Compression = BI_BITFIELDS; + info.bV4RedMask = 0x000000FF; + info.bV4GreenMask = 0x0000FF00; + info.bV4BlueMask = 0x00FF0000; + info.bV4AlphaMask = 0xFF000000; + + // Copy the back buffer to the window's device context. Do not check whether + // StretchDIBits succeeds or not. It will fail if the window has been + // destroyed but it is preferable to allow rendering to silently fail if the + // window is destroyed. This is because the primary application of this + // class of GLContext is for testing and we do not want every GL related ui / + // browser test to become flaky if there is a race condition between GL + // context destruction and window destruction. + StretchDIBits(device_context_, + 0, 0, size.width(), size.height(), + 0, 0, size.width(), size.height(), + GetHandle(), + reinterpret_cast<BITMAPINFO*>(&info), + DIB_RGB_COLORS, + SRCCOPY); + + return true; +} + +void NativeViewGLSurfaceOSMesa::UpdateSize() { + // Change back buffer size to that of window. If window handle is invalid, do + // not change the back buffer size. + RECT rect; + if (!GetClientRect(window_, &rect)) + return; + + gfx::Size window_size = gfx::Size( + std::max(1, static_cast<int>(rect.right - rect.left)), + std::max(1, static_cast<int>(rect.bottom - rect.top))); + Resize(window_size); +} + +GLSurface* GLSurface::CreateViewGLSurface(gfx::PluginWindowHandle window) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_ptr<NativeViewGLSurfaceOSMesa> surface( + new NativeViewGLSurfaceOSMesa(window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationEGLGLES2: { + scoped_ptr<NativeViewGLSurfaceEGL> surface(new NativeViewGLSurfaceEGL( + window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationDesktopGL: { + scoped_ptr<NativeViewGLSurfaceWGL> surface(new NativeViewGLSurfaceWGL( + window)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +GLSurface* GLSurface::CreateOffscreenGLSurface(const gfx::Size& size) { + switch (GetGLImplementation()) { + case kGLImplementationOSMesaGL: { + scoped_ptr<GLSurfaceOSMesa> surface(new GLSurfaceOSMesa()); + surface->Resize(size); + + return surface.release(); + } + case kGLImplementationEGLGLES2: { + scoped_ptr<PbufferGLSurfaceEGL> surface(new PbufferGLSurfaceEGL(size)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationDesktopGL: { + scoped_ptr<PbufferGLSurfaceWGL> surface(new PbufferGLSurfaceWGL(size)); + if (!surface->Initialize()) + return NULL; + + return surface.release(); + } + case kGLImplementationMockGL: + return new GLSurfaceStub; + default: + NOTREACHED(); + return NULL; + } +} + +} // namespace gfx diff --git a/ui/gfx/surface/accelerated_surface_mac.cc b/ui/gfx/surface/accelerated_surface_mac.cc index 43c6890..2210a6f 100644 --- a/ui/gfx/surface/accelerated_surface_mac.cc +++ b/ui/gfx/surface/accelerated_surface_mac.cc @@ -8,6 +8,7 @@ #include "base/mac/scoped_cftyperef.h" #include "ui/gfx/gl/gl_bindings.h" #include "ui/gfx/gl/gl_implementation.h" +#include "ui/gfx/gl/gl_surface.h" #include "ui/gfx/rect.h" #include "ui/gfx/surface/io_surface_support_mac.h" @@ -26,7 +27,7 @@ bool AcceleratedSurface::Initialize(gfx::GLContext* share_context, allocate_fbo_ = allocate_fbo; // Ensure GL is initialized before trying to create an offscreen GL context. - if (!gfx::GLContext::InitializeOneOff()) + if (!gfx::GLSurface::InitializeOneOff()) return false; // Drawing to IOSurfaces via OpenGL only works with desktop GL and @@ -34,9 +35,19 @@ bool AcceleratedSurface::Initialize(gfx::GLContext* share_context, if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) return false; - gl_context_.reset(gfx::GLContext::CreateOffscreenGLContext(share_context)); - if (!gl_context_.get()) + scoped_ptr<gfx::GLSurface> surface(gfx::GLSurface::CreateOffscreenGLSurface( + gfx::Size(1, 1))); + if (!surface.get()) { + Destroy(); return false; + } + + gl_context_.reset(gfx::GLContext::CreateGLContext(surface.release(), + share_context)); + if (!gl_context_.get()) { + Destroy(); + return false; + } // Now we're ready to handle SetSurfaceSize calls, which will // allocate and/or reallocate the IOSurface and associated offscreen |