summaryrefslogtreecommitdiffstats
path: root/opengl/libs/EGL
diff options
context:
space:
mode:
Diffstat (limited to 'opengl/libs/EGL')
-rw-r--r--opengl/libs/EGL/eglApi.cpp8
-rw-r--r--opengl/libs/EGL/egl_display.cpp41
-rw-r--r--opengl/libs/EGL/egl_display.h19
-rw-r--r--opengl/libs/EGL/egl_entries.in5
-rw-r--r--opengl/libs/EGL/egl_object.cpp23
-rw-r--r--opengl/libs/EGL/egl_object.h15
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;