diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-14 00:11:59 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-14 00:11:59 +0000 |
commit | 24edbd0b34b7177a781da8f5d0bbf4121d692b31 (patch) | |
tree | bf2e9f5b9e21ad74b358e48821d0dc1d63bb700c /ui/gfx/gl | |
parent | 866940781aa790de0a1e35f5d76163198e85e11c (diff) | |
download | chromium_src-24edbd0b34b7177a781da8f5d0bbf4121d692b31.zip chromium_src-24edbd0b34b7177a781da8f5d0bbf4121d692b31.tar.gz chromium_src-24edbd0b34b7177a781da8f5d0bbf4121d692b31.tar.bz2 |
Split EGLContext in GLContextEGL and GLSurfaceEGL.
Surfaces are independent of contexts in GL. To facilitate sharing of surfaces between processes, I have separated them from the notion of contexts because contexts cannot be shared between processes.
I have started with EGL. GLContextEGL still has a pointer to a surface and still has some surface specific operations that just forward through to it. Once I have refactored all the GLContext implementations in this way, I will remove these pointers and the surface specific opertations.
There will not be "view" and "offscreen" GL contexts. Rather there will be a single context type for each backend which can be made current with a surface that directs output either to a view or offscreen surface.
TEST=try, WebGL puppy works
BUG=none
Review URL: http://codereview.chromium.org/6839008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81512 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx/gl')
-rw-r--r-- | ui/gfx/gl/egl_util.cc | 47 | ||||
-rw-r--r-- | ui/gfx/gl/egl_util.h | 15 | ||||
-rw-r--r-- | ui/gfx/gl/gl.gyp | 37 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_egl.cc | 364 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_egl.h | 92 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_linux.cc | 24 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_win.cc | 38 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface.cc | 13 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface.h | 56 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_egl.cc | 245 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_egl.h | 80 |
11 files changed, 557 insertions, 454 deletions
diff --git a/ui/gfx/gl/egl_util.cc b/ui/gfx/gl/egl_util.cc new file mode 100644 index 0000000..29eb92d --- /dev/null +++ b/ui/gfx/gl/egl_util.cc @@ -0,0 +1,47 @@ +// 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/egl_util.h" + +#include "third_party/angle/include/EGL/egl.h" +#include "ui/gfx/gl/gl_bindings.h" + +namespace gfx { + +// Returns the last EGL error as a string. +const char* GetLastEGLErrorString() { + EGLint error = eglGetError(); + switch (error) { + case EGL_SUCCESS: + return "EGL_SUCCESS"; + case EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; + case EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG"; + case EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY"; + case EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + case EGL_BAD_MATCH: + return "EGL_BAD_MATCH"; + case EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW"; + default: + return "UNKNOWN"; + } +} + +} // namespace gfx diff --git a/ui/gfx/gl/egl_util.h b/ui/gfx/gl/egl_util.h new file mode 100644 index 0000000..71f471f --- /dev/null +++ b/ui/gfx/gl/egl_util.h @@ -0,0 +1,15 @@ +// 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_EGL_UTIL_H_ +#define UI_GFX_GL_EGL_UTIL_H_ + +namespace gfx { + +// Returns the last EGL error as a string. +const char* GetLastEGLErrorString(); + +} // namespace gfx + +#endif // UI_GFX_GL_EGL_UTIL_H_ diff --git a/ui/gfx/gl/gl.gyp b/ui/gfx/gl/gl.gyp index 4cdb279..50a9785 100644 --- a/ui/gfx/gl/gl.gyp +++ b/ui/gfx/gl/gl.gyp @@ -55,7 +55,6 @@ ], }, 'sources': [ - 'gl_bindings.gypi', 'gl_bindings.h', 'gl_bindings_skia_in_process.cc', 'gl_bindings_skia_in_process.h', @@ -75,6 +74,8 @@ 'gl_implementation_win.cc', 'gl_interface.cc', 'gl_interface.h', + 'gl_surface.cc', + 'gl_surface.h', 'gl_switches.cc', 'gl_switches.h', '<(gl_binding_output_dir)/gl_bindings_autogen_gl.cc', @@ -115,25 +116,38 @@ }, ], 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="win"', { 'sources': [ + 'egl_util.cc', + 'egl_util.h', 'gl_context_egl.cc', 'gl_context_egl.h', + 'gl_surface_egl.cc', + 'gl_surface_egl.h', '<(gl_binding_output_dir)/gl_bindings_autogen_egl.cc', '<(gl_binding_output_dir)/gl_bindings_autogen_egl.h', - '<(gl_binding_output_dir)/gl_bindings_autogen_glx.cc', - '<(gl_binding_output_dir)/gl_bindings_autogen_glx.h', ], 'include_dirs': [ - # We don't use angle, but pull the EGL/GLES headers from there. '<(DEPTH)/third_party/angle/include', ], + }], + ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + 'sources': [ + '<(gl_binding_output_dir)/gl_bindings_autogen_glx.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_glx.h', + ], 'all_dependent_settings': { 'defines': [ 'GL_GLEXT_PROTOTYPES', ], }, }], + ['OS=="win"', { + 'sources': [ + '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.cc', + '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.h', + ], + }], ['OS=="mac"', { 'link_settings': { 'libraries': [ @@ -141,19 +155,6 @@ ], }, }], - ['OS=="win"', { - 'sources': [ - 'gl_context_egl.cc', - 'gl_context_egl.h', - '<(gl_binding_output_dir)/gl_bindings_autogen_egl.cc', - '<(gl_binding_output_dir)/gl_bindings_autogen_egl.h', - '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.cc', - '<(gl_binding_output_dir)/gl_bindings_autogen_wgl.h', - ], - 'include_dirs': [ - '<(DEPTH)/third_party/angle/include', - ], - }], ], }, ], diff --git a/ui/gfx/gl/gl_context_egl.cc b/ui/gfx/gl/gl_context_egl.cc index 967329d..dd2ed27 100644 --- a/ui/gfx/gl/gl_context_egl.cc +++ b/ui/gfx/gl/gl_context_egl.cc @@ -2,12 +2,14 @@ // 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_context_egl.h" #include "build/build_config.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "third_party/angle/include/EGL/egl.h" -#include "ui/gfx/gl/gl_context_egl.h" +#include "ui/gfx/gl/gl_surface_egl.h" +#include "ui/gfx/gl/egl_util.h" // This header must come after the above third-party include, as // it brings in #defines that cause conflicts. @@ -22,180 +24,37 @@ extern "C" { namespace gfx { -namespace { - -// The EGL configuration to use. -EGLDisplay g_display; -EGLConfig g_config; - -// Returns the last EGL error as a string. -const char* GetLastEGLErrorString() { - EGLint error = eglGetError(); - switch (error) { - case EGL_SUCCESS: - return "EGL_SUCCESS"; - case EGL_BAD_ACCESS: - return "EGL_BAD_ACCESS"; - case EGL_BAD_ALLOC: - return "EGL_BAD_ALLOC"; - case EGL_BAD_ATTRIBUTE: - return "EGL_BAD_ATTRIBUTE"; - case EGL_BAD_CONTEXT: - return "EGL_BAD_CONTEXT"; - case EGL_BAD_CONFIG: - return "EGL_BAD_CONFIG"; - case EGL_BAD_CURRENT_SURFACE: - return "EGL_BAD_CURRENT_SURFACE"; - case EGL_BAD_DISPLAY: - return "EGL_BAD_DISPLAY"; - case EGL_BAD_SURFACE: - return "EGL_BAD_SURFACE"; - case EGL_BAD_MATCH: - return "EGL_BAD_MATCH"; - case EGL_BAD_PARAMETER: - return "EGL_BAD_PARAMETER"; - case EGL_BAD_NATIVE_PIXMAP: - return "EGL_BAD_NATIVE_PIXMAP"; - case EGL_BAD_NATIVE_WINDOW: - return "EGL_BAD_NATIVE_WINDOW"; - default: - return "UNKNOWN"; - } -} -} // namespace anonymous - -SharedEGLSurface::SharedEGLSurface(EGLSurface surface) : surface_(surface) { -} - -SharedEGLSurface::~SharedEGLSurface() { - if (surface_) { - if (!eglDestroySurface(g_display, surface_)) { - LOG(ERROR) << "eglDestroySurface failed with error " - << GetLastEGLErrorString(); - } - } -} - -EGLSurface SharedEGLSurface::egl_surface() const { - return surface_; -} - -bool BaseEGLContext::InitializeOneOff() { - static bool initialized = false; - if (initialized) - return true; - -#ifdef OS_LINUX - EGLNativeDisplayType native_display = XOpenDisplay(NULL); -#else - EGLNativeDisplayType native_display = EGL_DEFAULT_DISPLAY; -#endif - g_display = eglGetDisplay(native_display); - if (!g_display) { - LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString(); - return false; - } - - if (!eglInitialize(g_display, NULL, NULL)) { - LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString(); - return false; - } - - // Choose an EGL configuration. - static const EGLint kConfigAttribs[] = { - EGL_BUFFER_SIZE, 32, - EGL_ALPHA_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_RED_SIZE, 8, - EGL_DEPTH_SIZE, 16, - EGL_STENCIL_SIZE, 8, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, -#ifdef EGL_HAS_PBUFFERS - EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, -#else - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, -#endif - EGL_NONE - }; - - EGLint num_configs; - if (!eglChooseConfig(g_display, - kConfigAttribs, - NULL, - 0, - &num_configs)) { - LOG(ERROR) << "eglChooseConfig failed failed with error " - << GetLastEGLErrorString(); - return false; - } - - if (num_configs == 0) { - LOG(ERROR) << "No suitable EGL configs found."; - return false; - } - - scoped_array<EGLConfig> configs(new EGLConfig[num_configs]); - if (!eglChooseConfig(g_display, - kConfigAttribs, - configs.get(), - num_configs, - &num_configs)) { - LOG(ERROR) << "eglChooseConfig failed with error " - << GetLastEGLErrorString(); - return false; - } - - g_config = configs[0]; - - initialized = true; - return true; -} - -EGLDisplay BaseEGLContext::GetDisplay() { - return g_display; -} - -std::string BaseEGLContext::GetExtensions() { - const char* extensions = eglQueryString(g_display, EGL_EXTENSIONS); +std::string GLContextEGL::GetExtensions() { + const char* extensions = eglQueryString(GLSurfaceEGL::GetDisplay(), + EGL_EXTENSIONS); if (!extensions) return GLContext::GetExtensions(); return GLContext::GetExtensions() + " " + extensions; } -NativeViewEGLContext::NativeViewEGLContext(void* window) - : window_(window), +GLContextEGL::GLContextEGL(GLSurfaceEGL* surface) + : surface_(surface), context_(NULL) { } -NativeViewEGLContext::~NativeViewEGLContext() { +GLContextEGL::~GLContextEGL() { } -bool NativeViewEGLContext::Initialize() { +bool GLContextEGL::Initialize(GLContext* shared_context) { DCHECK(!context_); - // Create a surface for the native window. - EGLNativeWindowType native_window = - reinterpret_cast<EGLNativeWindowType>(window_); - surface_ = new SharedEGLSurface(eglCreateWindowSurface(g_display, - g_config, - native_window, - NULL)); - - if (!surface_->egl_surface()) { - LOG(ERROR) << "eglCreateWindowSurface failed with error " - << GetLastEGLErrorString(); - Destroy(); - return false; - } - static const EGLint kContextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - context_ = eglCreateContext(g_display, g_config, NULL, kContextAttributes); + context_ = eglCreateContext( + GLSurfaceEGL::GetDisplay(), + GLSurfaceEGL::GetConfig(), + shared_context ? shared_context->GetHandle() : NULL, + kContextAttributes); if (!context_) { LOG(ERROR) << "eglCreateContext failed with error " << GetLastEGLErrorString(); @@ -218,26 +77,25 @@ bool NativeViewEGLContext::Initialize() { return true; } -void NativeViewEGLContext::Destroy() { +void GLContextEGL::Destroy() { if (context_) { - if (!eglDestroyContext(g_display, context_)) { + if (!eglDestroyContext(GLSurfaceEGL::GetDisplay(), context_)) { LOG(ERROR) << "eglDestroyContext failed with error " << GetLastEGLErrorString(); } context_ = NULL; } - - surface_ = NULL; } -bool NativeViewEGLContext::MakeCurrent() { +bool GLContextEGL::MakeCurrent() { DCHECK(context_); - if (context_ == eglGetCurrentContext()) + if (IsCurrent()) return true; - if (!eglMakeCurrent(g_display, - surface_->egl_surface(), - surface_->egl_surface(), + + if (!eglMakeCurrent(GLSurfaceEGL::GetDisplay(), + surface_->GetHandle(), + surface_->GetHandle(), context_)) { VLOG(1) << "eglMakeCurrent failed with error " << GetLastEGLErrorString(); @@ -247,186 +105,36 @@ bool NativeViewEGLContext::MakeCurrent() { return true; } -bool NativeViewEGLContext::IsCurrent() { +bool GLContextEGL::IsCurrent() { DCHECK(context_); return context_ == eglGetCurrentContext(); } -bool NativeViewEGLContext::IsOffscreen() { - return false; +bool GLContextEGL::IsOffscreen() { + // TODO(apatrick): remove this from GLContext interface. + return surface_->IsOffscreen(); } -bool NativeViewEGLContext::SwapBuffers() { - if (!eglSwapBuffers(g_display, surface_->egl_surface())) { - VLOG(1) << "eglSwapBuffers failed with error " - << GetLastEGLErrorString(); - return false; - } - - return true; +bool GLContextEGL::SwapBuffers() { + // TODO(apatrick): remove this from GLContext interface. + return surface_->SwapBuffers(); } -gfx::Size NativeViewEGLContext::GetSize() { -#if defined(OS_WIN) - RECT rect; - if (!GetClientRect(static_cast<HWND>(window_), &rect)) { - DCHECK(false) << "GetClientRect failed."; - return gfx::Size(); - } - - return gfx::Size(rect.right - rect.left, rect.bottom - rect.top); -#else - // TODO(piman): This doesn't work correctly on Windows yet, the size doesn't - // get updated on resize. When it does, we can share the code. - EGLint width; - EGLint height; - if (!eglQuerySurface( - g_display, surface_->egl_surface(), EGL_WIDTH, &width) || - !eglQuerySurface( - g_display, surface_->egl_surface(), EGL_HEIGHT, &height)) { - NOTREACHED() << "eglQuerySurface failed with error " - << GetLastEGLErrorString(); - return gfx::Size(); - } - - return gfx::Size(width, height); -#endif +gfx::Size GLContextEGL::GetSize() { + // TODO(apatrick): remove this from GLContext interface. + return surface_->GetSize(); } -void* NativeViewEGLContext::GetHandle() { +void* GLContextEGL::GetHandle() { return context_; } -void NativeViewEGLContext::SetSwapInterval(int interval) { +void GLContextEGL::SetSwapInterval(int interval) { DCHECK(IsCurrent()); - if (!eglSwapInterval(g_display, interval)) { + if (!eglSwapInterval(GLSurfaceEGL::GetDisplay(), interval)) { LOG(ERROR) << "eglSwapInterval failed with error " << GetLastEGLErrorString(); } } -SharedEGLSurface* NativeViewEGLContext::GetSurface() { - return surface_; -} - -SecondaryEGLContext::SecondaryEGLContext() - : context_(NULL) -{ -} - -SecondaryEGLContext::~SecondaryEGLContext() { -} - -bool SecondaryEGLContext::Initialize(GLContext* shared_context) { - DCHECK(!context_); - - static const EGLint kContextAttributes[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - if (shared_context) { - surface_ = static_cast<BaseEGLContext*>(shared_context)->GetSurface(); - - // Create a context. - context_ = eglCreateContext(g_display, - g_config, - shared_context->GetHandle(), - kContextAttributes); - } else { -#ifdef EGL_HAS_PBUFFERS - static const EGLint kPbufferAttribs[] = { - EGL_WIDTH, 1, - EGL_HEIGHT, 1, - EGL_NONE - }; - - surface_ = new SharedEGLSurface(eglCreatePbufferSurface(g_display, - g_config, - kPbufferAttribs)); - if (!surface_->egl_surface()) { - LOG(ERROR) << "eglCreatePbufferSurface failed with error " - << GetLastEGLErrorString(); - Destroy(); - return false; - } - - context_ = eglCreateContext(g_display, g_config, NULL, kContextAttributes); -#else - NOTIMPLEMENTED() << "Offscreen non-shared GLES context"; - return false; -#endif - } - - if (!context_) { - LOG(ERROR) << "eglCreateContext failed with error " - << GetLastEGLErrorString(); - Destroy(); - return false; - } - - return true; -} - -void SecondaryEGLContext::Destroy() { - if (context_) { - if (!eglDestroyContext(g_display, context_)) { - LOG(ERROR) << "eglDestroyContext failed with error " - << GetLastEGLErrorString(); - } - - context_ = NULL; - } - - surface_ = NULL; -} - -bool SecondaryEGLContext::MakeCurrent() { - DCHECK(context_); - if (context_ == eglGetCurrentContext()) - return true; - if (!eglMakeCurrent(g_display, - surface_->egl_surface(), - surface_->egl_surface(), - context_)) { - VLOG(1) << "eglMakeCurrent failed with error " - << GetLastEGLErrorString(); - return false; - } - - return true; -} - -bool SecondaryEGLContext::IsCurrent() { - DCHECK(context_); - return context_ == eglGetCurrentContext(); -} - -bool SecondaryEGLContext::IsOffscreen() { - return true; -} - -bool SecondaryEGLContext::SwapBuffers() { - NOTREACHED() << "Attempted to call SwapBuffers on a SecondaryEGLContext."; - return false; -} - -gfx::Size SecondaryEGLContext::GetSize() { - NOTREACHED() << "Should not be requesting size of this SecondaryEGLContext."; - return gfx::Size(1, 1); -} - -void* SecondaryEGLContext::GetHandle() { - return context_; -} - -void SecondaryEGLContext::SetSwapInterval(int interval) { - DCHECK(IsCurrent()); - NOTREACHED() << "Attempt to call SetSwapInterval on a SecondaryEGLContext."; -} - -SharedEGLSurface* SecondaryEGLContext::GetSurface() { - return surface_; -} - } // namespace gfx diff --git a/ui/gfx/gl/gl_context_egl.h b/ui/gfx/gl/gl_context_egl.h index 4250457..43cbe922 100644 --- a/ui/gfx/gl/gl_context_egl.h +++ b/ui/gfx/gl/gl_context_egl.h @@ -6,92 +6,28 @@ #define UI_GFX_GL_GL_CONTEXT_EGL_H_ #pragma once -#include "base/memory/ref_counted.h" +#include <string> + +#include "base/memory/scoped_ptr.h" #include "ui/gfx/gl/gl_context.h" #include "ui/gfx/size.h" -typedef void* EGLDisplay; typedef void* EGLContext; -typedef void* EGLSurface; namespace gfx { -// Takes ownership of an EGL surface and reference counts it so it can be shared -// by multiple EGL contexts and destroyed with the last. -class SharedEGLSurface : public base::RefCounted<SharedEGLSurface> { - public: - explicit SharedEGLSurface(EGLSurface surface); - ~SharedEGLSurface(); - - EGLSurface egl_surface() const; - - private: - EGLSurface surface_; - DISALLOW_COPY_AND_ASSIGN(SharedEGLSurface); -}; - -// Interface for EGL contexts. Adds an EGL specific accessor for retreiving -// the surface. -class BaseEGLContext : public GLContext { - public: - BaseEGLContext() {} - virtual ~BaseEGLContext() {} - - static bool InitializeOneOff(); - - static EGLDisplay GetDisplay(); - - // Get the associated EGL surface. - virtual SharedEGLSurface* GetSurface() = 0; - - // Implement GLContext. - virtual std::string GetExtensions(); - - private: - DISALLOW_COPY_AND_ASSIGN(BaseEGLContext); -}; +class GLSurfaceEGL; // Encapsulates an EGL OpenGL ES context that renders to a view. -class NativeViewEGLContext : public BaseEGLContext { +class GLContextEGL : public GLContext { public: - explicit NativeViewEGLContext(void* window); - virtual ~NativeViewEGLContext(); + // Takes ownership of surface. TODO(apatrick): separate notion of surface + // from context. + explicit GLContextEGL(GLSurfaceEGL* surface); - // Initialize an EGL context. - bool Initialize(); + virtual ~GLContextEGL(); - // Implement GLContext. - virtual void Destroy(); - virtual bool MakeCurrent(); - virtual bool IsCurrent(); - virtual bool IsOffscreen(); - virtual bool SwapBuffers(); - virtual gfx::Size GetSize(); - virtual void* GetHandle(); - virtual void SetSwapInterval(int interval); - - // Implement BaseEGLContext. - virtual SharedEGLSurface* GetSurface(); - - private: - void* window_; - scoped_refptr<SharedEGLSurface> surface_; - EGLContext context_; - - DISALLOW_COPY_AND_ASSIGN(NativeViewEGLContext); -}; - -// Encapsulates an EGL OpenGL ES context intended for offscreen use. It is -// actually associated with a native window or a pbuffer on supporting platforms -// and will render to it. The caller must bind an FBO to prevent this. -// TODO(apatrick): implement pbuffers in ANGLE and change this to -// PbufferEGLContext and use it on all EGL platforms. -class SecondaryEGLContext : public BaseEGLContext { - public: - SecondaryEGLContext(); - virtual ~SecondaryEGLContext(); - - // Initialize an EGL context that shares a namespace with another. + // Initialize an EGL context. bool Initialize(GLContext* shared_context); // Implement GLContext. @@ -103,15 +39,13 @@ class SecondaryEGLContext : public BaseEGLContext { virtual gfx::Size GetSize(); virtual void* GetHandle(); virtual void SetSwapInterval(int interval); - - // Implement BaseEGLContext. - virtual SharedEGLSurface* GetSurface(); + virtual std::string GetExtensions(); private: - scoped_refptr<SharedEGLSurface> surface_; + scoped_ptr<GLSurfaceEGL> surface_; EGLContext context_; - DISALLOW_COPY_AND_ASSIGN(SecondaryEGLContext); + DISALLOW_COPY_AND_ASSIGN(GLContextEGL); }; } // namespace gfx diff --git a/ui/gfx/gl/gl_context_linux.cc b/ui/gfx/gl/gl_context_linux.cc index 430bba5..1a114d8 100644 --- a/ui/gfx/gl/gl_context_linux.cc +++ b/ui/gfx/gl/gl_context_linux.cc @@ -21,6 +21,7 @@ extern "C" { #include "ui/gfx/gl/gl_context_osmesa.h" #include "ui/gfx/gl/gl_context_stub.h" #include "ui/gfx/gl/gl_implementation.h" +#include "ui/gfx/gl/gl_surface_egl.h" namespace { @@ -217,8 +218,8 @@ bool GLContext::InitializeOneOff() { break; } case kGLImplementationEGLGLES2: - if (!BaseEGLContext::InitializeOneOff()) { - LOG(ERROR) << "BaseEGLContext::InitializeOneOff failed."; + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; return false; } break; @@ -515,9 +516,14 @@ GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window, return context.release(); } case kGLImplementationEGLGLES2: { - scoped_ptr<NativeViewEGLContext> context( - new NativeViewEGLContext(reinterpret_cast<void *>(window))); - if (!context->Initialize()) + scoped_ptr<NativeViewGLSurfaceEGL> surface(new NativeViewGLSurfaceEGL( + reinterpret_cast<void*>(window))); + if (!surface->Initialize()) + return NULL; + + scoped_ptr<GLContextEGL> context( + new GLContextEGL(surface.release())); + if (!context->Initialize(NULL)) return NULL; return context.release(); @@ -805,8 +811,12 @@ GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { return NULL; } case kGLImplementationEGLGLES2: { - scoped_ptr<SecondaryEGLContext> context( - new SecondaryEGLContext()); + scoped_ptr<PbufferGLSurfaceEGL> surface(new PbufferGLSurfaceEGL( + gfx::Size(1, 1))); + if (!surface->Initialize()) + return NULL; + + scoped_ptr<GLContextEGL> context(new GLContextEGL(surface.release())); if (!context->Initialize(shared_context)) return NULL; diff --git a/ui/gfx/gl/gl_context_win.cc b/ui/gfx/gl/gl_context_win.cc index 23f98b2..d2bbe77 100644 --- a/ui/gfx/gl/gl_context_win.cc +++ b/ui/gfx/gl/gl_context_win.cc @@ -17,6 +17,7 @@ #include "ui/gfx/gl/gl_context_osmesa.h" #include "ui/gfx/gl/gl_context_stub.h" #include "ui/gfx/gl/gl_implementation.h" +#include "ui/gfx/gl/gl_surface_egl.h" namespace gfx { @@ -132,10 +133,6 @@ static HWND g_window; static int g_regular_pixel_format = 0; static int g_multisampled_pixel_format = 0; -// When using ANGLE we still need a window for D3D. This context creates the -// D3D device. -static BaseEGLContext* g_default_context; - const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = { sizeof(kPixelFormatDescriptor), // Size of structure. 1, // Default version. @@ -313,8 +310,8 @@ bool GLContext::InitializeOneOff() { break; } case kGLImplementationEGLGLES2: - if (!BaseEGLContext::InitializeOneOff()) { - LOG(ERROR) << "BaseEGLContext::InitializeOneOff failed."; + if (!GLSurfaceEGL::InitializeOneOff()) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; return false; } break; @@ -551,9 +548,14 @@ GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window, return context.release(); } case kGLImplementationEGLGLES2: { - scoped_ptr<NativeViewEGLContext> context( - new NativeViewEGLContext(window)); - if (!context->Initialize()) + 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(); @@ -706,20 +708,12 @@ GLContext* GLContext::CreateOffscreenGLContext(GLContext* shared_context) { return context.release(); } case kGLImplementationEGLGLES2: { - if (!shared_context) { - if (!g_default_context) { - scoped_ptr<NativeViewEGLContext> default_context( - new NativeViewEGLContext(g_window)); - if (!default_context->Initialize()) - return NULL; - - g_default_context = default_context.release(); - } - shared_context = g_default_context; - } + scoped_ptr<PbufferGLSurfaceEGL> surface(new PbufferGLSurfaceEGL( + gfx::Size(1, 1))); + if (!surface->Initialize()) + return NULL; - scoped_ptr<SecondaryEGLContext> context( - new SecondaryEGLContext()); + scoped_ptr<GLContextEGL> context(new GLContextEGL(surface.release())); if (!context->Initialize(shared_context)) return NULL; diff --git a/ui/gfx/gl/gl_surface.cc b/ui/gfx/gl/gl_surface.cc new file mode 100644 index 0000000..b1dd505 --- /dev/null +++ b/ui/gfx/gl/gl_surface.cc @@ -0,0 +1,13 @@ +// 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" + +namespace gfx { + +unsigned int GLSurface::GetBackingFrameBufferObject() { + return 0; +} + +} // namespace gfx diff --git a/ui/gfx/gl/gl_surface.h b/ui/gfx/gl/gl_surface.h new file mode 100644 index 0000000..c0ab1e9 --- /dev/null +++ b/ui/gfx/gl/gl_surface.h @@ -0,0 +1,56 @@ +// 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_H_ +#define UI_GFX_GL_GL_SURFACE_H_ +#pragma once + +#include "build/build_config.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/size.h" + +namespace gfx { + +// Encapsulates a surface that can be rendered to with GL, hiding platform +// specific management. +class GLSurface { + public: + GLSurface() {} + virtual ~GLSurface() {} + + // Destroys the surface. + virtual void Destroy() = 0; + + // Returns true if this surface is offscreen. + virtual bool IsOffscreen() = 0; + + // Swaps front and back buffers. This has no effect for off-screen + // contexts. + virtual bool SwapBuffers() = 0; + + // Get the size of the surface. + virtual gfx::Size GetSize() = 0; + + // Get the underlying platform specific surface "handle". + virtual void* GetHandle() = 0; + + // Returns the internal frame buffer object name if the surface is backed by + // FBO. Otherwise returns 0. + virtual unsigned int GetBackingFrameBufferObject(); + +#if !defined(OS_MACOSX) + // Create a surface corresponding to a view. + static GLSurface* CreateViewGLContext(gfx::PluginWindowHandle window); +#endif + + // Create a surface used for offscreen rendering. + static GLSurface* CreateOffscreenGLContext(const gfx::Size& size); + + private: + DISALLOW_COPY_AND_ASSIGN(GLSurface); +}; + +} // namespace gfx + +#endif // UI_GFX_GL_GL_SURFACE_H_ diff --git a/ui/gfx/gl/gl_surface_egl.cc b/ui/gfx/gl/gl_surface_egl.cc new file mode 100644 index 0000000..ae17a1b --- /dev/null +++ b/ui/gfx/gl/gl_surface_egl.cc @@ -0,0 +1,245 @@ +// 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_egl.h" + +#include "build/build_config.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/angle/include/EGL/egl.h" +#include "ui/gfx/gl/egl_util.h" + +// This header must come after the above third-party include, as +// it brings in #defines that cause conflicts. +#include "ui/gfx/gl/gl_bindings.h" + +#if defined(OS_LINUX) +extern "C" { +#include <X11/Xlib.h> +} +#endif + +namespace gfx { + +namespace { +EGLConfig g_config; +EGLDisplay g_display; +} + +GLSurfaceEGL::GLSurfaceEGL() { +} + +GLSurfaceEGL::~GLSurfaceEGL() { +} + +bool GLSurfaceEGL::InitializeOneOff() { + static bool initialized = false; + if (initialized) + return true; + +#ifdef OS_LINUX + EGLNativeDisplayType native_display = XOpenDisplay(NULL); +#else + EGLNativeDisplayType native_display = EGL_DEFAULT_DISPLAY; +#endif + g_display = eglGetDisplay(native_display); + if (!g_display) { + LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString(); + return false; + } + + if (!eglInitialize(g_display, NULL, NULL)) { + LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString(); + return false; + } + + // Choose an EGL configuration. + static const EGLint kConfigAttribs[] = { + EGL_BUFFER_SIZE, 32, + EGL_ALPHA_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_DEPTH_SIZE, 16, + EGL_STENCIL_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, +#ifdef EGL_HAS_PBUFFERS + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, +#else + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, +#endif + EGL_NONE + }; + + EGLint num_configs; + if (!eglChooseConfig(g_display, + kConfigAttribs, + NULL, + 0, + &num_configs)) { + LOG(ERROR) << "eglChooseConfig failed failed with error " + << GetLastEGLErrorString(); + return false; + } + + if (num_configs == 0) { + LOG(ERROR) << "No suitable EGL configs found."; + return false; + } + + scoped_array<EGLConfig> configs(new EGLConfig[num_configs]); + if (!eglChooseConfig(g_display, + kConfigAttribs, + configs.get(), + num_configs, + &num_configs)) { + LOG(ERROR) << "eglChooseConfig failed with error " + << GetLastEGLErrorString(); + return false; + } + + g_config = configs[0]; + + initialized = true; + return true; +} + +EGLDisplay GLSurfaceEGL::GetDisplay() { + return g_display; +} + +EGLConfig GLSurfaceEGL::GetConfig() { + return g_config; +} + +NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(void* window) + : window_(window), + surface_(NULL) +{ +} + +NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() { + Destroy(); +} + +bool NativeViewGLSurfaceEGL::Initialize() { + DCHECK(!surface_); + + // Create a surface for the native window. + EGLNativeWindowType native_window = + reinterpret_cast<EGLNativeWindowType>(window_); + surface_ = eglCreateWindowSurface(g_display, + g_config, + native_window, + NULL); + + if (!surface_) { + LOG(ERROR) << "eglCreateWindowSurface failed with error " + << GetLastEGLErrorString(); + Destroy(); + return false; + } + + return true; +} + +void NativeViewGLSurfaceEGL::Destroy() { + if (surface_) { + if (!eglDestroySurface(g_display, surface_)) { + LOG(ERROR) << "eglDestroySurface failed with error " + << GetLastEGLErrorString(); + } + surface_ = NULL; + } +} + +bool NativeViewGLSurfaceEGL::IsOffscreen() { + return false; +} + +bool NativeViewGLSurfaceEGL::SwapBuffers() { + if (!eglSwapBuffers(g_display, surface_)) { + VLOG(1) << "eglSwapBuffers failed with error " + << GetLastEGLErrorString(); + return false; + } + + return true; +} + +gfx::Size NativeViewGLSurfaceEGL::GetSize() { + EGLint width; + EGLint height; + if (!eglQuerySurface(g_display, surface_, EGL_WIDTH, &width) || + !eglQuerySurface(g_display, surface_, EGL_HEIGHT, &height)) { + NOTREACHED() << "eglQuerySurface failed with error " + << GetLastEGLErrorString(); + return gfx::Size(); + } + + return gfx::Size(width, height); +} + +EGLSurface NativeViewGLSurfaceEGL::GetHandle() { + return surface_; +} + +PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size) + : size_(size), + surface_(NULL) { +} + +PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() { + Destroy(); +} + +bool PbufferGLSurfaceEGL::Initialize() { + DCHECK(!surface_); + + const EGLint pbuffer_attribs[] = { + EGL_WIDTH, size_.width(), + EGL_HEIGHT, size_.height(), + EGL_NONE + }; + + surface_ = eglCreatePbufferSurface(g_display, + g_config, + pbuffer_attribs); + if (!surface_) { + LOG(ERROR) << "eglCreatePbufferSurface failed with error " + << GetLastEGLErrorString(); + Destroy(); + return false; + } + + return true; +} + +void PbufferGLSurfaceEGL::Destroy() { + if (surface_) { + if (!eglDestroySurface(g_display, surface_)) { + LOG(ERROR) << "eglDestroySurface failed with error " + << GetLastEGLErrorString(); + } + surface_ = NULL; + } +} + +bool PbufferGLSurfaceEGL::IsOffscreen() { + return true; +} + +bool PbufferGLSurfaceEGL::SwapBuffers() { + NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL."; + return false; +} + +gfx::Size PbufferGLSurfaceEGL::GetSize() { + return size_; +} + +EGLSurface PbufferGLSurfaceEGL::GetHandle() { + return surface_; +} + +} // namespace gfx diff --git a/ui/gfx/gl/gl_surface_egl.h b/ui/gfx/gl/gl_surface_egl.h new file mode 100644 index 0000000..9ff1c2b --- /dev/null +++ b/ui/gfx/gl/gl_surface_egl.h @@ -0,0 +1,80 @@ +// 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_EGL_H_ +#define UI_GFX_GL_GL_SURFACE_EGL_H_ +#pragma once + +#include "ui/gfx/gl/gl_surface.h" +#include "ui/gfx/size.h" + +typedef void* EGLConfig; +typedef void* EGLDisplay; +typedef void* EGLSurface; + +namespace gfx { + +// Interface for EGL contexts. +class GLSurfaceEGL : public GLSurface { + public: + GLSurfaceEGL(); + virtual ~GLSurfaceEGL(); + + static bool InitializeOneOff(); + static EGLDisplay GetDisplay(); + static EGLConfig GetConfig(); + + private: + DISALLOW_COPY_AND_ASSIGN(GLSurfaceEGL); +}; + +// Encapsulates an EGL surface bound to a view. +class NativeViewGLSurfaceEGL : public GLSurfaceEGL { + public: + explicit NativeViewGLSurfaceEGL(void* window); + virtual ~NativeViewGLSurfaceEGL(); + + // Initialize an EGL context. + bool Initialize(); + + // Implement GLSurface. + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual EGLSurface GetHandle(); + + private: + void* window_; + EGLSurface surface_; + + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceEGL); +}; + +// Encapsulates a pbuffer EGL surface. +class PbufferGLSurfaceEGL : public GLSurfaceEGL { + public: + explicit PbufferGLSurfaceEGL(const gfx::Size& size); + virtual ~PbufferGLSurfaceEGL(); + + // Initialize an EGL context that shares a namespace with another. + bool Initialize(); + + // Implement GLSurface. + virtual void Destroy(); + virtual bool IsOffscreen(); + virtual bool SwapBuffers(); + virtual gfx::Size GetSize(); + virtual EGLSurface GetHandle(); + + private: + gfx::Size size_; + EGLSurface surface_; + + DISALLOW_COPY_AND_ASSIGN(PbufferGLSurfaceEGL); +}; + +} // namespace gfx + +#endif // UI_GFX_GL_GL_SURFACE_EGL_H_ |