summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 23:59:03 +0000
committerapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 23:59:03 +0000
commitb0dc569d27817cccc7b09108da41054892c35bf7 (patch)
tree20c04c14a47197e57e637a6a910df6ff7bce0784 /app
parent440e7e0151dae967e5ab4d031c82b8c901dc88f8 (diff)
downloadchromium_src-b0dc569d27817cccc7b09108da41054892c35bf7.zip
chromium_src-b0dc569d27817cccc7b09108da41054892c35bf7.tar.gz
chromium_src-b0dc569d27817cccc7b09108da41054892c35bf7.tar.bz2
EGL contexts reference count the EGL surfaces they share.
This fixes the case where a NativeViewEGLContext and a SecondaryEGL context are backed by the same EGL surface and the native one, which previously owned the surface, is destroyed first. TEST=try BUG=none Review URL: http://codereview.chromium.org/6296004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71390 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app')
-rw-r--r--app/gfx/gl/gl_context_egl.cc76
-rw-r--r--app/gfx/gl/gl_context_egl.h36
2 files changed, 66 insertions, 46 deletions
diff --git a/app/gfx/gl/gl_context_egl.cc b/app/gfx/gl/gl_context_egl.cc
index fa82e6d..3fddb30 100644
--- a/app/gfx/gl/gl_context_egl.cc
+++ b/app/gfx/gl/gl_context_egl.cc
@@ -58,6 +58,22 @@ const char* GetLastEGLErrorString() {
}
} // 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)
@@ -143,7 +159,6 @@ std::string BaseEGLContext::GetExtensions() {
NativeViewEGLContext::NativeViewEGLContext(void* window)
: window_(window),
- surface_(NULL),
context_(NULL)
{
}
@@ -157,9 +172,12 @@ bool NativeViewEGLContext::Initialize() {
// Create a surface for the native window.
EGLNativeWindowType native_window =
reinterpret_cast<EGLNativeWindowType>(window_);
- surface_ = eglCreateWindowSurface(g_display, g_config, native_window, NULL);
+ surface_ = new SharedEGLSurface(eglCreateWindowSurface(g_display,
+ g_config,
+ native_window,
+ NULL));
- if (!surface_) {
+ if (!surface_->egl_surface()) {
LOG(ERROR) << "eglCreateWindowSurface failed with error "
<< GetLastEGLErrorString();
Destroy();
@@ -204,20 +222,14 @@ void NativeViewEGLContext::Destroy() {
context_ = NULL;
}
- if (surface_) {
- if (!eglDestroySurface(g_display, surface_)) {
- LOG(ERROR) << "eglDestroySurface failed with error "
- << GetLastEGLErrorString();
- }
-
- surface_ = NULL;
- }
+ surface_ = NULL;
}
bool NativeViewEGLContext::MakeCurrent() {
DCHECK(context_);
if (!eglMakeCurrent(g_display,
- surface_, surface_,
+ surface_->egl_surface(),
+ surface_->egl_surface(),
context_)) {
VLOG(1) << "eglMakeCurrent failed with error "
<< GetLastEGLErrorString();
@@ -237,7 +249,7 @@ bool NativeViewEGLContext::IsOffscreen() {
}
bool NativeViewEGLContext::SwapBuffers() {
- if (!eglSwapBuffers(g_display, surface_)) {
+ if (!eglSwapBuffers(g_display, surface_->egl_surface())) {
VLOG(1) << "eglSwapBuffers failed with error "
<< GetLastEGLErrorString();
return false;
@@ -260,8 +272,10 @@ gfx::Size NativeViewEGLContext::GetSize() {
// get updated on resize. When it does, we can share the code.
EGLint width;
EGLint height;
- if (!eglQuerySurface(g_display, surface_, EGL_WIDTH, &width) ||
- !eglQuerySurface(g_display, surface_, EGL_HEIGHT, &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();
@@ -283,14 +297,12 @@ void NativeViewEGLContext::SetSwapInterval(int interval) {
}
}
-EGLSurface NativeViewEGLContext::GetSurface() {
+SharedEGLSurface* NativeViewEGLContext::GetSurface() {
return surface_;
}
SecondaryEGLContext::SecondaryEGLContext()
- : surface_(NULL),
- own_surface_(false),
- context_(NULL)
+ : context_(NULL)
{
}
@@ -307,7 +319,6 @@ bool SecondaryEGLContext::Initialize(GLContext* shared_context) {
if (shared_context) {
surface_ = static_cast<BaseEGLContext*>(shared_context)->GetSurface();
- own_surface_ = false;
// Create a context.
context_ = eglCreateContext(g_display,
@@ -322,13 +333,15 @@ bool SecondaryEGLContext::Initialize(GLContext* shared_context) {
EGL_NONE
};
- surface_ = eglCreatePbufferSurface(g_display, g_config, kPbufferAttribs);
- if (!surface_) {
+ surface_ = new SharedEGLSurface(eglCreatePbufferSurface(g_display,
+ g_config,
+ kPbufferAttribs));
+ if (!surface_->egl_surface()) {
LOG(ERROR) << "eglCreatePbufferSurface failed with error "
<< GetLastEGLErrorString();
+ Destroy();
return false;
}
- own_surface_ = true;
context_ = eglCreateContext(g_display, g_config, NULL, kContextAttributes);
#else
@@ -348,16 +361,6 @@ bool SecondaryEGLContext::Initialize(GLContext* shared_context) {
}
void SecondaryEGLContext::Destroy() {
- if (own_surface_) {
- if (!eglDestroySurface(g_display, surface_)) {
- LOG(ERROR) << "eglDestroySurface failed with error "
- << GetLastEGLErrorString();
- }
-
- own_surface_ = false;
- }
- surface_ = NULL;
-
if (context_) {
if (!eglDestroyContext(g_display, context_)) {
LOG(ERROR) << "eglDestroyContext failed with error "
@@ -366,12 +369,15 @@ void SecondaryEGLContext::Destroy() {
context_ = NULL;
}
+
+ surface_ = NULL;
}
bool SecondaryEGLContext::MakeCurrent() {
DCHECK(context_);
if (!eglMakeCurrent(g_display,
- surface_, surface_,
+ surface_->egl_surface(),
+ surface_->egl_surface(),
context_)) {
VLOG(1) << "eglMakeCurrent failed with error "
<< GetLastEGLErrorString();
@@ -409,7 +415,7 @@ void SecondaryEGLContext::SetSwapInterval(int interval) {
NOTREACHED() << "Attempt to call SetSwapInterval on a SecondaryEGLContext.";
}
-EGLSurface SecondaryEGLContext::GetSurface() {
+SharedEGLSurface* SecondaryEGLContext::GetSurface() {
return surface_;
}
diff --git a/app/gfx/gl/gl_context_egl.h b/app/gfx/gl/gl_context_egl.h
index 1647239..fbbdabb 100644
--- a/app/gfx/gl/gl_context_egl.h
+++ b/app/gfx/gl/gl_context_egl.h
@@ -6,8 +6,9 @@
#define APP_GFX_GL_GL_CONTEXT_EGL_H_
#pragma once
-#include "gfx/size.h"
#include "app/gfx/gl/gl_context.h"
+#include "base/ref_counted.h"
+#include "gfx/size.h"
typedef void* EGLDisplay;
typedef void* EGLContext;
@@ -15,6 +16,20 @@ 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 {
@@ -27,7 +42,7 @@ class BaseEGLContext : public GLContext {
static EGLDisplay GetDisplay();
// Get the associated EGL surface.
- virtual EGLSurface GetSurface() = 0;
+ virtual SharedEGLSurface* GetSurface() = 0;
// Implement GLContext.
virtual std::string GetExtensions();
@@ -56,20 +71,21 @@ class NativeViewEGLContext : public BaseEGLContext {
virtual void SetSwapInterval(int interval);
// Implement BaseEGLContext.
- virtual EGLSurface GetSurface();
+ virtual SharedEGLSurface* GetSurface();
private:
void* window_;
- EGLSurface surface_;
+ 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 and will render to it. The caller
-// must bind an FBO to prevent this. Not using pbuffers because ANGLE does not
-// support them.
+// 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();
@@ -89,12 +105,10 @@ class SecondaryEGLContext : public BaseEGLContext {
virtual void SetSwapInterval(int interval);
// Implement BaseEGLContext.
- virtual EGLSurface GetSurface();
+ virtual SharedEGLSurface* GetSurface();
private:
- // All offscreen
- EGLSurface surface_;
- bool own_surface_;
+ scoped_refptr<SharedEGLSurface> surface_;
EGLContext context_;
DISALLOW_COPY_AND_ASSIGN(SecondaryEGLContext);