diff options
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 21 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 71 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 4 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerImpl.java | 27 | ||||
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 14 | ||||
-rw-r--r-- | core/jni/com_google_android_gles_jni_EGLImpl.cpp | 14 | ||||
-rw-r--r-- | libs/hwui/Caches.cpp | 44 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 13 | ||||
-rw-r--r-- | opengl/java/android/opengl/EGLLogWrapper.java | 10 | ||||
-rw-r--r-- | opengl/java/com/google/android/gles_jni/EGLImpl.java | 7 | ||||
-rw-r--r-- | opengl/java/javax/microedition/khronos/egl/EGL10.java | 2 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_display.h | 2 |
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; |