Merge "Terminate EGL when an app goes in the background" into ics-mr1
This commit is contained in:
@@ -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
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
@@ -343,6 +344,15 @@ public abstract class HardwareRenderer {
|
||||
Gl20Renderer.trimMemory(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -651,6 +661,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
|
||||
@@ -671,6 +683,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 };
|
||||
|
||||
@@ -914,6 +928,11 @@ public abstract class HardwareRenderer {
|
||||
EGL_NONE
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
void initCaches() {
|
||||
GLES20Canvas.initCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canDraw() {
|
||||
@@ -1006,16 +1025,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) {
|
||||
@@ -1029,5 +1039,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -86,7 +86,6 @@ struct CacheLogger {
|
||||
|
||||
class ANDROID_API Caches: public Singleton<Caches> {
|
||||
Caches();
|
||||
~Caches();
|
||||
|
||||
friend class Singleton<Caches>;
|
||||
|
||||
@@ -108,6 +107,11 @@ public:
|
||||
kFlushMode_Full
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the cache.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Flush the cache.
|
||||
*
|
||||
@@ -115,6 +119,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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 " +
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user