diff options
Diffstat (limited to 'opengl/libs/EGL')
-rw-r--r-- | opengl/libs/EGL/eglApi.cpp | 8 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_display.cpp | 41 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_display.h | 19 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_entries.in | 5 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_object.cpp | 23 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_object.h | 15 |
6 files changed, 94 insertions, 17 deletions
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 969b50f..1bc4eb7 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -649,9 +649,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) return NULL; } - // The EGL_ANDROID_blob_cache extension should not be exposed to - // applications. It is used internally by the Android EGL layer. - if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID")) { + // These extensions should not be exposed to applications. They're used + // internally by the Android EGL layer. + if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID") || + !strcmp(procname, "eglHibernateProcessIMG") || + !strcmp(procname, "eglAwakenProcessIMG")) { return NULL; } diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 52e79f2..2e08f24 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -59,6 +59,7 @@ static char const * const sExtensionString = // extensions not exposed to applications but used by the ANDROID system // "EGL_ANDROID_recordable " // mandatory // "EGL_ANDROID_blob_cache " // strongly recommended +// "EGL_IMG_hibernate_process " // optional extern void initEglTraceLevel(); extern void initEglDebugLevel(); @@ -70,7 +71,7 @@ egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; egl_display_t::egl_display_t() : magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0), - mWakeCount(0) { + mWakeCount(0), mHibernating(false), mAttemptHibernation(false) { } egl_display_t::~egl_display_t() { @@ -349,12 +350,18 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { c->onMakeCurrent(draw, read); + if (!cur_c) { + mWakeCount++; + mAttemptHibernation = false; + } } } else { result = cur_c->cnx->egl.eglMakeCurrent( disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { cur_c->onLooseCurrent(); + mWakeCount--; + mAttemptHibernation = true; } } } @@ -376,13 +383,45 @@ bool egl_display_t::enter() { ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX, "Invalid WakeCount (%d) on enter\n", mWakeCount); mWakeCount++; + if (CC_UNLIKELY(mHibernating)) { + ALOGV("Awakening\n"); + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->egl.eglAwakenProcessIMG()) { + ALOGE("Failed to awaken EGL implementation\n"); + return false; + } + mHibernating = false; + } return true; } void egl_display_t::leave() { Mutex::Autolock _l(lock); ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount); + if (--mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) { + egl_connection_t* const cnx = &gEGLImpl; + mAttemptHibernation = false; + if (cnx->egl.eglHibernateProcessIMG && cnx->egl.eglAwakenProcessIMG) { + ALOGV("Hibernating\n"); + if (!cnx->egl.eglHibernateProcessIMG()) { + ALOGE("Failed to hibernate EGL implementation\n"); + return; + } + mHibernating = true; + } + } +} + +void egl_display_t::onWindowSurfaceCreated() { + Mutex::Autolock _l(lock); + mWakeCount++; + mAttemptHibernation = false; +} + +void egl_display_t::onWindowSurfaceDestroyed() { + Mutex::Autolock _l(lock); mWakeCount--; + mAttemptHibernation = true; } // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h index 8fd23eb..28607da 100644 --- a/opengl/libs/EGL/egl_display.h +++ b/opengl/libs/EGL/egl_display.h @@ -70,6 +70,16 @@ public: // add reference to this object. returns true if this is a valid object. bool getObject(egl_object_t* object) const; + // These notifications allow the display to keep track of how many window + // surfaces exist, which it uses to decide whether to hibernate the + // underlying EGL implementation. They can be called by any thread without + // holding a lock, but must be called via egl_display_ptr to ensure + // proper hibernate/wakeup sequencing. If a surface destruction triggers + // hibernation, hibernation will be delayed at least until the calling + // thread's egl_display_ptr is destroyed. + void onWindowSurfaceCreated(); + void onWindowSurfaceDestroyed(); + static egl_display_t* get(EGLDisplay dpy); static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp); @@ -124,10 +134,16 @@ private: String8 mClientApiString; String8 mExtensionString; int32_t mWakeCount; + bool mHibernating; + bool mAttemptHibernation; }; // ---------------------------------------------------------------------------- +// An egl_display_ptr is a kind of smart pointer for egl_display_t objects. +// It doesn't refcount the egl_display_t, but does ensure that the underlying +// EGL implementation is "awake" (not hibernating) and ready for use as long +// as the egl_display_ptr exists. class egl_display_ptr { public: explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) { @@ -141,12 +157,13 @@ public: // 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. + // can't use a move constructor until those are cleaned up. // // 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(); diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in index bdd2a7e..9feb716 100644 --- a/opengl/libs/EGL/egl_entries.in +++ b/opengl/libs/EGL/egl_entries.in @@ -67,3 +67,8 @@ EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface) EGL_ENTRY(EGLuint64NV, eglGetSystemTimeFrequencyNV, void) EGL_ENTRY(EGLuint64NV, eglGetSystemTimeNV, void) + +/* IMG extensions */ + +EGL_ENTRY(EGLBoolean, eglHibernateProcessIMG, void) +EGL_ENTRY(EGLBoolean, eglAwakenProcessIMG, void)
\ No newline at end of file diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index b42b268..aaa5e72 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -63,6 +63,29 @@ bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) { // ---------------------------------------------------------------------------- +egl_surface_t::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) +{ + if (win) { + getDisplay()->onWindowSurfaceCreated(); + } +} + +egl_surface_t::~egl_surface_t() { + ANativeWindow* const window = win.get(); + if (window != NULL) { + native_window_set_buffers_format(window, 0); + if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) { + ALOGW("EGLNativeWindowType %p disconnect failed", window); + } + getDisplay()->onWindowSurfaceDestroyed(); + } +} + +// ---------------------------------------------------------------------------- + egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, egl_connection_t const* cnx, int version) : egl_object_t(get_display_nowake(dpy)), dpy(dpy), context(context), diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index d1162db..2a08424 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -127,23 +127,14 @@ void egl_object_t::LocalRef<N,T>::terminate() { class egl_surface_t : public egl_object_t { protected: - ~egl_surface_t() { - ANativeWindow* const window = win.get(); - if (window != NULL) { - native_window_set_buffers_format(window, 0); - if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) { - ALOGW("EGLNativeWindowType %p disconnect failed", window); - } - } - } + ~egl_surface_t(); public: typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref; 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) - {} + egl_connection_t const* cnx); + EGLSurface surface; EGLConfig config; sp<ANativeWindow> win; |