Increment/decrement a counter around EGL calls

This is in preparation for a change that will hibernate the underlying
EGL when idle. Instead of a bare egl_display_t*, get_display() now
returns a egl_display_ptr, which acts like a smart pointer. The
"wakecount" counter managed by the smart pointer isn't used for
anything in this change. It will be used to make sure we don't
hibernate when any thread is in an EGL call, without having to hold a
mutex for the duration of the call.

Change-Id: Iee52f3549a51162efc3800e1195d3f76bba2f2ce
This commit is contained in:
Jesse Hall 2012-04-04 16:53:42 -07:00
parent d5caca1d0d
commit b29e5e8c26
6 changed files with 169 additions and 91 deletions

View File

@ -203,27 +203,27 @@ static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
// ----------------------------------------------------------------------------
egl_display_t* validate_display(EGLDisplay dpy) {
egl_display_t * const dp = get_display(dpy);
egl_display_ptr validate_display(EGLDisplay dpy) {
egl_display_ptr dp = get_display(dpy);
if (!dp)
return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
return setError(EGL_BAD_DISPLAY, egl_display_ptr(NULL));
if (!dp->isReady())
return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);
return setError(EGL_NOT_INITIALIZED, egl_display_ptr(NULL));
return dp;
}
egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig,
egl_display_t const*& dp) {
dp = validate_display(dpy);
egl_display_ptr validate_display_connection(EGLDisplay dpy,
egl_connection_t*& cnx) {
cnx = NULL;
egl_display_ptr dp = validate_display(dpy);
if (!dp)
return (egl_connection_t*) NULL;
egl_connection_t* const cnx = &gEGLImpl;
return dp;
cnx = &gEGLImpl;
if (cnx->dso == 0) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
return setError(EGL_BAD_CONFIG, egl_display_ptr(NULL));
}
return cnx;
return dp;
}
// ----------------------------------------------------------------------------

View File

@ -133,7 +133,7 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
{
clearError();
egl_display_t * const dp = get_display(dpy);
egl_display_ptr dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
EGLBoolean res = dp->initialize(major, minor);
@ -149,7 +149,7 @@ EGLBoolean eglTerminate(EGLDisplay dpy)
clearError();
egl_display_t* const dp = get_display(dpy);
egl_display_ptr dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
EGLBoolean res = dp->terminate();
@ -167,7 +167,7 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
if (num_config==0) {
@ -192,7 +192,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
if (num_config==0) {
@ -215,9 +215,9 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
{
clearError();
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (!cnx) return EGL_FALSE;
egl_connection_t* cnx = NULL;
const egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (!dp) return EGL_FALSE;
return cnx->egl.eglGetConfigAttrib(
dp->disp.dpy, config, attribute, value);
@ -233,9 +233,9 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
{
clearError();
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
egl_connection_t* cnx = NULL;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
EGLDisplay iDpy = dp->disp.dpy;
EGLint format;
@ -267,7 +267,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
EGLSurface surface = cnx->egl.eglCreateWindowSurface(
iDpy, config, window, attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, cnx);
egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
surface, cnx);
return s;
}
@ -284,13 +285,14 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
{
clearError();
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
egl_connection_t* cnx = NULL;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
dp->disp.dpy, config, pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
surface, cnx);
return s;
}
}
@ -302,13 +304,14 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
{
clearError();
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
egl_connection_t* cnx = NULL;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dp) {
EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
surface, cnx);
return s;
}
}
@ -319,10 +322,10 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -339,10 +342,10 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -355,12 +358,12 @@ void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
ATRACE_CALL();
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) {
return;
}
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get()) {
setError(EGL_BAD_SURFACE, EGL_FALSE);
return;
@ -381,9 +384,9 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
{
clearError();
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (cnx) {
egl_connection_t* cnx = NULL;
const egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (dpy) {
if (share_list != EGL_NO_CONTEXT) {
egl_context_t* const c = get_context(share_list);
share_list = c->context;
@ -406,7 +409,8 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
}
};
}
egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version);
egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
version);
#if EGL_TRACE
if (gEGLDebugLevel > 0)
GLTrace_eglCreateContext(version, c);
@ -421,11 +425,11 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp)
return EGL_FALSE;
ContextRef _c(dp, ctx);
ContextRef _c(dp.get(), ctx);
if (!_c.get())
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
@ -442,7 +446,7 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
{
clearError();
egl_display_t const * const dp = get_display(dpy);
egl_display_ptr dp = validate_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
// If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
@ -454,9 +458,9 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
}
// get a reference to the object passed in
ContextRef _c(dp, ctx);
SurfaceRef _d(dp, draw);
SurfaceRef _r(dp, read);
ContextRef _c(dp.get(), ctx);
SurfaceRef _d(dp.get(), draw);
SurfaceRef _r(dp.get(), read);
// validate the context (if not EGL_NO_CONTEXT)
if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
@ -506,7 +510,7 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
}
EGLBoolean result = const_cast<egl_display_t*>(dp)->makeCurrent(c, cur_c,
EGLBoolean result = dp->makeCurrent(c, cur_c,
draw, read, ctx,
impl_draw, impl_read, impl_ctx);
@ -538,10 +542,10 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
ContextRef _c(dp, ctx);
ContextRef _c(dp.get(), ctx);
if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
egl_context_t * const c = get_context(ctx);
@ -783,10 +787,10 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
ATRACE_CALL();
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, draw);
SurfaceRef _s(dp.get(), draw);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -827,10 +831,10 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -842,7 +846,7 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return (const char *) NULL;
switch (name) {
@ -870,10 +874,10 @@ EGLBoolean eglSurfaceAttrib(
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -890,10 +894,10 @@ EGLBoolean eglBindTexImage(
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -910,10 +914,10 @@ EGLBoolean eglReleaseTexImage(
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -929,7 +933,7 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean res = EGL_TRUE;
@ -1023,9 +1027,9 @@ EGLSurface eglCreatePbufferFromClientBuffer(
{
clearError();
egl_display_t const* dp = 0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp);
if (!cnx) return EGL_FALSE;
egl_connection_t* cnx = NULL;
const egl_display_ptr dp = validate_display_connection(dpy, cnx);
if (!dp) return EGL_FALSE;
if (cnx->egl.eglCreatePbufferFromClientBuffer) {
return cnx->egl.eglCreatePbufferFromClientBuffer(
dp->disp.dpy, buftype, buffer, config, attrib_list);
@ -1042,10 +1046,10 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -1061,10 +1065,10 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
SurfaceRef _s(dp, surface);
SurfaceRef _s(dp.get(), surface);
if (!_s.get())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
@ -1080,10 +1084,10 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_NO_IMAGE_KHR;
ContextRef _c(dp, ctx);
ContextRef _c(dp.get(), ctx);
egl_context_t * const c = _c.get();
EGLImageKHR result = EGL_NO_IMAGE_KHR;
@ -1101,7 +1105,7 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
@ -1120,7 +1124,7 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_l
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_NO_SYNC_KHR;
EGLSyncKHR result = EGL_NO_SYNC_KHR;
@ -1135,7 +1139,7 @@ EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean result = EGL_FALSE;
@ -1151,7 +1155,7 @@ EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean result = EGL_FALSE;
@ -1168,7 +1172,7 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
{
clearError();
egl_display_t const * const dp = validate_display(dpy);
const egl_display_ptr dp = validate_display(dpy);
if (!dp) return EGL_FALSE;
EGLBoolean result = EGL_FALSE;

View File

@ -14,6 +14,8 @@
** limitations under the License.
*/
#define __STDC_LIMIT_MACROS 1
#include <string.h>
#include "egl_cache.h"
@ -67,7 +69,8 @@ extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
egl_display_t::egl_display_t() :
magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0) {
magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0),
mWakeCount(0) {
}
egl_display_t::~egl_display_t() {
@ -368,6 +371,20 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
return result;
}
bool egl_display_t::enter() {
Mutex::Autolock _l(lock);
ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
"Invalid WakeCount (%d) on enter\n", mWakeCount);
mWakeCount++;
return true;
}
void egl_display_t::leave() {
Mutex::Autolock _l(lock);
ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
mWakeCount--;
}
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------

View File

@ -27,6 +27,7 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <cutils/compiler.h>
#include <utils/SortedVector.h>
#include <utils/threads.h>
#include <utils/String8.h>
@ -111,6 +112,10 @@ public:
bool traceGpuCompletion; // property: debug.egl.traceGpuCompletion
private:
friend class egl_display_ptr;
bool enter();
void leave();
uint32_t refs;
mutable Mutex lock;
SortedVector<egl_object_t*> objects;
@ -118,19 +123,74 @@ private:
String8 mVersionString;
String8 mClientApiString;
String8 mExtensionString;
int32_t mWakeCount;
};
// ----------------------------------------------------------------------------
inline egl_display_t* get_display(EGLDisplay dpy) {
class egl_display_ptr {
public:
explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) {
if (mDpy) {
if (CC_UNLIKELY(!mDpy->enter())) {
mDpy = NULL;
}
}
}
// We only really need a C++11 move constructor, not a copy constructor.
// A move constructor would save an enter()/leave() pair on every EGL API
// call. But enabling -std=c++0x causes lots of errors elsewhere, so I
// can't use a move constructor yet.
//
// egl_display_ptr(egl_display_ptr&& other) {
// mDpy = other.mDpy;
// other.mDpy = NULL;
// }
egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) {
if (mDpy) {
mDpy->enter();
}
}
~egl_display_ptr() {
if (mDpy) {
mDpy->leave();
}
}
const egl_display_t* operator->() const { return mDpy; }
egl_display_t* operator->() { return mDpy; }
const egl_display_t* get() const { return mDpy; }
egl_display_t* get() { return mDpy; }
operator bool() const { return mDpy != NULL; }
private:
egl_display_t* mDpy;
// non-assignable
egl_display_ptr& operator=(const egl_display_ptr&);
};
// ----------------------------------------------------------------------------
inline egl_display_ptr get_display(EGLDisplay dpy) {
return egl_display_ptr(egl_display_t::get(dpy));
}
// Does not ensure EGL is unhibernated. Use with caution: calls into the
// underlying EGL implementation are not safe.
inline egl_display_t* get_display_nowake(EGLDisplay dpy) {
return egl_display_t::get(dpy);
}
// ----------------------------------------------------------------------------
egl_display_t* validate_display(EGLDisplay dpy);
egl_connection_t* validate_display_config(EGLDisplay dpy,
EGLConfig config, egl_display_t const*& dp);
egl_display_ptr validate_display(EGLDisplay dpy);
egl_display_ptr validate_display_connection(EGLDisplay dpy,
egl_connection_t*& cnx);
EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx);
EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface);

View File

@ -65,10 +65,8 @@ bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) {
egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
egl_connection_t const* cnx, int version) :
egl_object_t(get_display(dpy)), dpy(dpy), context(context),
config(config), read(0), draw(0), cnx(cnx),
version(version)
{
egl_object_t(get_display_nowake(dpy)), dpy(dpy), context(context),
config(config), read(0), draw(0), cnx(cnx), version(version) {
}
void egl_context_t::onLooseCurrent() {

View File

@ -139,12 +139,11 @@ protected:
public:
typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
EGLSurface surface, egl_connection_t const* cnx) :
egl_object_t(get_display(dpy)), dpy(dpy), surface(surface),
config(config), win(win), cnx(cnx) {
}
EGLDisplay dpy;
egl_surface_t(egl_display_t* dpy, EGLConfig config,
EGLNativeWindowType win, EGLSurface surface,
egl_connection_t const* cnx) :
egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx)
{}
EGLSurface surface;
EGLConfig config;
sp<ANativeWindow> win;