summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/GLES20Canvas.java21
-rw-r--r--core/java/android/view/HardwareRenderer.java71
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/view/WindowManagerImpl.java27
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp14
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp14
-rw-r--r--libs/hwui/Caches.cpp44
-rw-r--r--libs/hwui/Caches.h13
-rw-r--r--opengl/java/android/opengl/EGLLogWrapper.java10
-rw-r--r--opengl/java/com/google/android/gles_jni/EGLImpl.java7
-rw-r--r--opengl/java/javax/microedition/khronos/egl/EGL10.java2
-rw-r--r--opengl/libs/EGL/egl_display.h2
13 files changed, 205 insertions, 25 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index c934c7b..d948ec2 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -315,6 +315,27 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nFlushCaches(int level);
+ /**
+ * Release all resources associated with the underlying caches. This should
+ * only be called after a full flushCaches().
+ *
+ * @hide
+ */
+ public static void terminateCaches() {
+ nTerminateCaches();
+ }
+
+ private static native void nTerminateCaches();
+
+ /**
+ * @hide
+ */
+ public static void initCaches() {
+ nInitCaches();
+ }
+
+ private static native void nInitCaches();
+
///////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b86d21d..00e2100 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -25,6 +25,7 @@ import android.opengl.GLUtils;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Log;
+import com.google.android.gles_jni.EGLImpl;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
@@ -325,6 +326,15 @@ public abstract class HardwareRenderer {
}
/**
+ * Invoke this method when the system needs to clean up all resources
+ * associated with hardware rendering.
+ */
+ static void terminate() {
+ Log.d(LOG_TAG, "Terminating hardware rendering");
+ Gl20Renderer.terminate();
+ }
+
+ /**
* Indicates whether hardware acceleration is currently enabled.
*
* @return True if hardware acceleration is in use, false otherwise.
@@ -632,6 +642,8 @@ public abstract class HardwareRenderer {
throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
}
+
+ initCaches();
// If mDirtyRegions is set, this means we have an EGL configuration
// with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
@@ -652,6 +664,8 @@ public abstract class HardwareRenderer {
return mEglContext.getGL();
}
+ abstract void initCaches();
+
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
@@ -895,6 +909,11 @@ public abstract class HardwareRenderer {
EGL_NONE
};
}
+
+ @Override
+ void initCaches() {
+ GLES20Canvas.initCaches();
+ }
@Override
boolean canDraw() {
@@ -987,16 +1006,7 @@ public abstract class HardwareRenderer {
if (eglContext == null) {
return;
} else {
- synchronized (sPbufferLock) {
- // Create a temporary 1x1 pbuffer so we have a context
- // to clear our OpenGL objects
- if (sPbuffer == null) {
- sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
- EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
- });
- }
- }
- sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ usePbufferSurface(eglContext);
}
switch (level) {
@@ -1010,5 +1020,46 @@ public abstract class HardwareRenderer {
break;
}
}
+
+ private static void usePbufferSurface(EGLContext eglContext) {
+ synchronized (sPbufferLock) {
+ // Create a temporary 1x1 pbuffer so we have a context
+ // to clear our OpenGL objects
+ if (sPbuffer == null) {
+ sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
+ EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
+ });
+ }
+ }
+ sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ }
+
+ static void terminate() {
+ synchronized (sEglLock) {
+ if (sEgl == null) return;
+
+ if (EGLImpl.getInitCount(sEglDisplay) == 1) {
+ EGLContext eglContext = sEglContextStorage.get();
+ if (eglContext == null) return;
+
+ usePbufferSurface(eglContext);
+ GLES20Canvas.terminateCaches();
+
+ sEgl.eglDestroyContext(sEglDisplay, eglContext);
+ sEglContextStorage.remove();
+
+ sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ sEgl.eglReleaseThread();
+ sEgl.eglTerminate(sEglDisplay);
+
+ sEgl = null;
+ sEglDisplay = null;
+ sEglConfig = null;
+ sPbuffer = null;
+ }
+ }
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f7078ec..b15b155 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -567,7 +567,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
}
- private void destroyHardwareResources() {
+ void destroyHardwareResources() {
if (mAttachInfo.mHardwareRenderer != null) {
if (mAttachInfo.mHardwareRenderer.isEnabled()) {
mAttachInfo.mHardwareRenderer.destroyLayers(mView);
@@ -880,12 +880,10 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|| mNewSurfaceNeeded;
WindowManager.LayoutParams params = null;
- int windowAttributesChanges = 0;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
surfaceChanged = true;
params = lp;
- windowAttributesChanges = mWindowAttributesChangesFlag;
}
CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 5ef4f3e..d89bc36 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,6 +16,8 @@
package android.view;
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -409,7 +411,30 @@ public class WindowManagerImpl implements WindowManager {
*/
public void trimMemory(int level) {
if (HardwareRenderer.isAvailable()) {
- HardwareRenderer.trimMemory(level);
+ switch (level) {
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+ // On low and medium end gfx devices
+ if (!ActivityManager.isHighEndGfx(getDefaultDisplay())) {
+ // Force a full memory flush
+ HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+ // Destroy all hardware surfaces and resources associated to
+ // known windows
+ synchronized (this) {
+ if (mViews == null) return;
+ int count = mViews.length;
+ for (int i = 0; i < count; i++) {
+ mRoots[i].destroyHardwareResources();
+ }
+ }
+ // Terminate the hardware renderer to free all resources
+ HardwareRenderer.terminate();
+ break;
+ }
+ // high end gfx devices fall through to next case
+ default:
+ HardwareRenderer.trimMemory(level);
+ }
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 59a03e7..7a0ed01 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -160,6 +160,7 @@ LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
$(LOCAL_PATH)/android/graphics \
$(LOCAL_PATH)/../../libs/hwui \
+ $(LOCAL_PATH)/../../opengl/libs \
$(call include-path-for, bluedroid) \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e79de2d..4f75fad 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -134,6 +134,18 @@ static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz,
}
}
+static void android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().init();
+ }
+}
+
+static void android_view_GLES20Canvas_terminateCaches(JNIEnv* env, jobject clazz) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().terminate();
+ }
+}
+
// ----------------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------------
@@ -756,6 +768,8 @@ static JNINativeMethod gMethods[] = {
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
{ "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
{ "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches },
+ { "nInitCaches", "()V", (void*) android_view_GLES20Canvas_initCaches },
+ { "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches },
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 02974f9..4fe7600 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -24,6 +24,8 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
+#include <EGL/egl_display.h>
+
#include <surfaceflinger/Surface.h>
#include <SkBitmap.h>
#include <SkPixelRef.h>
@@ -173,6 +175,16 @@ static jboolean jni_eglQuerySurface(JNIEnv *_env, jobject _this, jobject display
return success;
}
+static jint jni_getInitCount(JNIEnv *_env, jobject _clazz, jobject display) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ egl_display_t* eglDisplay = get_display(dpy);
+ return eglDisplay ? eglDisplay->getRefsCount() : 0;
+}
+
+static jboolean jni_eglReleaseThread(JNIEnv *_env, jobject _this) {
+ return eglReleaseThread();
+}
+
static jboolean jni_eglChooseConfig(JNIEnv *_env, jobject _this, jobject display,
jintArray attrib_list, jobjectArray configs, jint config_size, jintArray num_config) {
if (display == NULL
@@ -526,6 +538,8 @@ static JNINativeMethod methods[] = {
{"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
{"eglQueryContext", "(" DISPLAY CONTEXT "I[I)Z", (void*)jni_eglQueryContext },
{"eglQuerySurface", "(" DISPLAY SURFACE "I[I)Z", (void*)jni_eglQuerySurface },
+{"eglReleaseThread","()Z", (void*)jni_eglReleaseThread },
+{"getInitCount", "(" DISPLAY ")I", (void*)jni_getInitCount },
{"eglChooseConfig", "(" DISPLAY "[I[" CONFIG "I[I)Z", (void*)jni_eglChooseConfig },
{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)I", (void*)jni_eglCreateContext },
{"eglGetConfigs", "(" DISPLAY "[" CONFIG "I[I)Z", (void*)jni_eglGetConfigs },
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 75b07de..f293cba 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -46,22 +46,16 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
- lastDstMode(GL_ZERO), currentProgram(NULL) {
+Caches::Caches(): Singleton<Caches>(), mInitialized(false) {
GLint maxTextureUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
}
- glGenBuffers(1, &meshBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
- mCurrentBuffer = meshBuffer;
- mRegionMesh = NULL;
+ init();
mDebugLevel = readDebugLevel();
LOGD("Enabling debug mode %d", mDebugLevel);
@@ -71,8 +65,40 @@ Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
#endif
}
-Caches::~Caches() {
+void Caches::init() {
+ if (mInitialized) return;
+
+ glGenBuffers(1, &meshBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
+
+ mCurrentBuffer = meshBuffer;
+ mRegionMesh = NULL;
+
+ blend = false;
+ lastSrcMode = GL_ZERO;
+ lastDstMode = GL_ZERO;
+ currentProgram = NULL;
+
+ mInitialized = true;
+}
+
+void Caches::terminate() {
+ if (!mInitialized) return;
+
+ glDeleteBuffers(1, &meshBuffer);
+ mCurrentBuffer = 0;
+
+ glDeleteBuffers(1, &mRegionMeshIndices);
delete[] mRegionMesh;
+ mRegionMesh = NULL;
+
+ fboCache.clear();
+
+ programCache.clear();
+ currentProgram = NULL;
+
+ mInitialized = false;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 9b0d7c6..5e58a9e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -86,7 +86,6 @@ struct CacheLogger {
class ANDROID_API Caches: public Singleton<Caches> {
Caches();
- ~Caches();
friend class Singleton<Caches>;
@@ -109,6 +108,11 @@ public:
};
/**
+ * Initializes the cache.
+ */
+ void init();
+
+ /**
* Flush the cache.
*
* @param mode Indicates how much of the cache should be flushed
@@ -116,6 +120,12 @@ public:
void flush(FlushMode mode);
/**
+ * Destroys all resources associated with this cache. This should
+ * be called after a flush(kFlushMode_Full).
+ */
+ void terminate();
+
+ /**
* Indicates whether the renderer is in debug mode.
* This debug mode provides limited information to app developers.
*/
@@ -194,6 +204,7 @@ public:
private:
DebugLevel mDebugLevel;
+ bool mInitialized;
}; // class Caches
}; // namespace uirenderer
diff --git a/opengl/java/android/opengl/EGLLogWrapper.java b/opengl/java/android/opengl/EGLLogWrapper.java
index 6c0fdb3..36e88a2 100644
--- a/opengl/java/android/opengl/EGLLogWrapper.java
+++ b/opengl/java/android/opengl/EGLLogWrapper.java
@@ -314,6 +314,16 @@ class EGLLogWrapper implements EGL11 {
checkError();
return result;
}
+
+ /** @hide **/
+ public boolean eglReleaseThread() {
+ begin("eglReleaseThread");
+ end();
+ boolean result = mEgl10.eglReleaseThread();
+ returns(result);
+ checkError();
+ return result;
+ }
public boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface) {
begin("eglInitialize");
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index 51d6ca8..6992019 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -31,6 +31,8 @@ public class EGLImpl implements EGL10 {
public native boolean eglInitialize(EGLDisplay display, int[] major_minor);
public native boolean eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
public native boolean eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
+ /** @hide **/
+ public native boolean eglReleaseThread();
public native boolean eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
public native boolean eglGetConfigAttrib(EGLDisplay display, EGLConfig config, int attribute, int[] value);
public native boolean eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
@@ -44,6 +46,9 @@ public class EGLImpl implements EGL10 {
public native boolean eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
public native boolean eglWaitGL();
public native boolean eglWaitNative(int engine, Object bindTarget);
+
+ /** @hide **/
+ public static native int getInitCount(EGLDisplay display);
public EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list) {
int eglContextId = _eglCreateContext(display, config, share_context, attrib_list);
@@ -85,7 +90,7 @@ public class EGLImpl implements EGL10 {
eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
} else if (native_window instanceof SurfaceTexture) {
eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
- (SurfaceTexture) native_window, attrib_list);
+ native_window, attrib_list);
} else {
throw new java.lang.UnsupportedOperationException(
"eglCreateWindowSurface() can only be called with an instance of " +
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index 2ae793a..cf58888 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -114,6 +114,8 @@ public interface EGL10 extends EGL {
boolean eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
String eglQueryString(EGLDisplay display, int name);
boolean eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
+ /** @hide **/
+ boolean eglReleaseThread();
boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface);
boolean eglTerminate(EGLDisplay display);
boolean eglWaitGL();
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 1c1092c..e0a367d 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -91,6 +91,8 @@ public:
inline bool isValid() const { return magic == '_dpy'; }
inline bool isAlive() const { return isValid(); }
+ inline uint32_t getRefsCount() const { return refs; }
+
struct strings_t {
char const * vendor;
char const * version;