Skip to content

Commit 50a66f0

Browse files
Romain GuyAndroid (Google) Code Review
authored andcommitted
Merge "Terminate EGL when an app goes in the background" into ics-mr1
2 parents de62d9c + 8ff6b9e commit 50a66f0

File tree

12 files changed

+204
-25
lines changed

12 files changed

+204
-25
lines changed

core/java/android/view/GLES20Canvas.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,27 @@ public static void flushCaches(int level) {
315315

316316
private static native void nFlushCaches(int level);
317317

318+
/**
319+
* Release all resources associated with the underlying caches. This should
320+
* only be called after a full flushCaches().
321+
*
322+
* @hide
323+
*/
324+
public static void terminateCaches() {
325+
nTerminateCaches();
326+
}
327+
328+
private static native void nTerminateCaches();
329+
330+
/**
331+
* @hide
332+
*/
333+
public static void initCaches() {
334+
nInitCaches();
335+
}
336+
337+
private static native void nInitCaches();
338+
318339
///////////////////////////////////////////////////////////////////////////
319340
// Display list
320341
///////////////////////////////////////////////////////////////////////////

core/java/android/view/HardwareRenderer.java

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.os.SystemClock;
2626
import android.os.SystemProperties;
2727
import android.util.Log;
28+
import com.google.android.gles_jni.EGLImpl;
2829

2930
import javax.microedition.khronos.egl.EGL10;
3031
import javax.microedition.khronos.egl.EGL11;
@@ -343,6 +344,15 @@ static void trimMemory(int level) {
343344
Gl20Renderer.trimMemory(level);
344345
}
345346

347+
/**
348+
* Invoke this method when the system needs to clean up all resources
349+
* associated with hardware rendering.
350+
*/
351+
static void terminate() {
352+
Log.d(LOG_TAG, "Terminating hardware rendering");
353+
Gl20Renderer.terminate();
354+
}
355+
346356
/**
347357
* Indicates whether hardware acceleration is currently enabled.
348358
*
@@ -651,6 +661,8 @@ GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException
651661
throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
652662
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
653663
}
664+
665+
initCaches();
654666

655667
// If mDirtyRegions is set, this means we have an EGL configuration
656668
// with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
@@ -671,6 +683,8 @@ GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException
671683
return mEglContext.getGL();
672684
}
673685

686+
abstract void initCaches();
687+
674688
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
675689
int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
676690

@@ -914,6 +928,11 @@ int[] getConfig(boolean dirtyRegions) {
914928
EGL_NONE
915929
};
916930
}
931+
932+
@Override
933+
void initCaches() {
934+
GLES20Canvas.initCaches();
935+
}
917936

918937
@Override
919938
boolean canDraw() {
@@ -1006,16 +1025,7 @@ static void trimMemory(int level) {
10061025
if (eglContext == null) {
10071026
return;
10081027
} else {
1009-
synchronized (sPbufferLock) {
1010-
// Create a temporary 1x1 pbuffer so we have a context
1011-
// to clear our OpenGL objects
1012-
if (sPbuffer == null) {
1013-
sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
1014-
EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
1015-
});
1016-
}
1017-
}
1018-
sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
1028+
usePbufferSurface(eglContext);
10191029
}
10201030

10211031
switch (level) {
@@ -1029,5 +1039,46 @@ static void trimMemory(int level) {
10291039
break;
10301040
}
10311041
}
1042+
1043+
private static void usePbufferSurface(EGLContext eglContext) {
1044+
synchronized (sPbufferLock) {
1045+
// Create a temporary 1x1 pbuffer so we have a context
1046+
// to clear our OpenGL objects
1047+
if (sPbuffer == null) {
1048+
sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
1049+
EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
1050+
});
1051+
}
1052+
}
1053+
sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
1054+
}
1055+
1056+
static void terminate() {
1057+
synchronized (sEglLock) {
1058+
if (sEgl == null) return;
1059+
1060+
if (EGLImpl.getInitCount(sEglDisplay) == 1) {
1061+
EGLContext eglContext = sEglContextStorage.get();
1062+
if (eglContext == null) return;
1063+
1064+
usePbufferSurface(eglContext);
1065+
GLES20Canvas.terminateCaches();
1066+
1067+
sEgl.eglDestroyContext(sEglDisplay, eglContext);
1068+
sEglContextStorage.remove();
1069+
1070+
sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
1071+
sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1072+
1073+
sEgl.eglReleaseThread();
1074+
sEgl.eglTerminate(sEglDisplay);
1075+
1076+
sEgl = null;
1077+
sEglDisplay = null;
1078+
sEglConfig = null;
1079+
sPbuffer = null;
1080+
}
1081+
}
1082+
}
10321083
}
10331084
}

core/java/android/view/ViewRootImpl.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ public void setView(View view, WindowManager.LayoutParams attrs, View panelParen
567567
}
568568
}
569569

570-
private void destroyHardwareResources() {
570+
void destroyHardwareResources() {
571571
if (mAttachInfo.mHardwareRenderer != null) {
572572
if (mAttachInfo.mHardwareRenderer.isEnabled()) {
573573
mAttachInfo.mHardwareRenderer.destroyLayers(mView);
@@ -880,12 +880,10 @@ private void performTraversals() {
880880
|| mNewSurfaceNeeded;
881881

882882
WindowManager.LayoutParams params = null;
883-
int windowAttributesChanges = 0;
884883
if (mWindowAttributesChanged) {
885884
mWindowAttributesChanged = false;
886885
surfaceChanged = true;
887886
params = lp;
888-
windowAttributesChanges = mWindowAttributesChangesFlag;
889887
}
890888
CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
891889
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {

core/java/android/view/WindowManagerImpl.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package android.view;
1818

19+
import android.app.ActivityManager;
20+
import android.content.ComponentCallbacks2;
1921
import android.content.res.CompatibilityInfo;
2022
import android.content.res.Configuration;
2123
import android.graphics.PixelFormat;
@@ -409,7 +411,30 @@ public void closeAll(IBinder token, String who, String what) {
409411
*/
410412
public void trimMemory(int level) {
411413
if (HardwareRenderer.isAvailable()) {
412-
HardwareRenderer.trimMemory(level);
414+
switch (level) {
415+
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
416+
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
417+
// On low and medium end gfx devices
418+
if (!ActivityManager.isHighEndGfx(getDefaultDisplay())) {
419+
// Force a full memory flush
420+
HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
421+
// Destroy all hardware surfaces and resources associated to
422+
// known windows
423+
synchronized (this) {
424+
if (mViews == null) return;
425+
int count = mViews.length;
426+
for (int i = 0; i < count; i++) {
427+
mRoots[i].destroyHardwareResources();
428+
}
429+
}
430+
// Terminate the hardware renderer to free all resources
431+
HardwareRenderer.terminate();
432+
break;
433+
}
434+
// high end gfx devices fall through to next case
435+
default:
436+
HardwareRenderer.trimMemory(level);
437+
}
413438
}
414439
}
415440

core/jni/android_view_GLES20Canvas.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz,
134134
}
135135
}
136136

137+
static void android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) {
138+
if (Caches::hasInstance()) {
139+
Caches::getInstance().init();
140+
}
141+
}
142+
143+
static void android_view_GLES20Canvas_terminateCaches(JNIEnv* env, jobject clazz) {
144+
if (Caches::hasInstance()) {
145+
Caches::getInstance().terminate();
146+
}
147+
}
148+
137149
// ----------------------------------------------------------------------------
138150
// Constructors
139151
// ----------------------------------------------------------------------------
@@ -756,6 +768,8 @@ static JNINativeMethod gMethods[] = {
756768
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
757769
{ "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
758770
{ "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches },
771+
{ "nInitCaches", "()V", (void*) android_view_GLES20Canvas_initCaches },
772+
{ "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches },
759773

760774
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
761775
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },

core/jni/com_google_android_gles_jni_EGLImpl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <EGL/egl.h>
2525
#include <GLES/gl.h>
2626

27+
#include <EGL/egl_display.h>
28+
2729
#include <surfaceflinger/Surface.h>
2830
#include <SkBitmap.h>
2931
#include <SkPixelRef.h>
@@ -173,6 +175,16 @@ static jboolean jni_eglQuerySurface(JNIEnv *_env, jobject _this, jobject display
173175
return success;
174176
}
175177

178+
static jint jni_getInitCount(JNIEnv *_env, jobject _clazz, jobject display) {
179+
EGLDisplay dpy = getDisplay(_env, display);
180+
egl_display_t* eglDisplay = get_display(dpy);
181+
return eglDisplay ? eglDisplay->getRefsCount() : 0;
182+
}
183+
184+
static jboolean jni_eglReleaseThread(JNIEnv *_env, jobject _this) {
185+
return eglReleaseThread();
186+
}
187+
176188
static jboolean jni_eglChooseConfig(JNIEnv *_env, jobject _this, jobject display,
177189
jintArray attrib_list, jobjectArray configs, jint config_size, jintArray num_config) {
178190
if (display == NULL
@@ -526,6 +538,8 @@ static JNINativeMethod methods[] = {
526538
{"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
527539
{"eglQueryContext", "(" DISPLAY CONTEXT "I[I)Z", (void*)jni_eglQueryContext },
528540
{"eglQuerySurface", "(" DISPLAY SURFACE "I[I)Z", (void*)jni_eglQuerySurface },
541+
{"eglReleaseThread","()Z", (void*)jni_eglReleaseThread },
542+
{"getInitCount", "(" DISPLAY ")I", (void*)jni_getInitCount },
529543
{"eglChooseConfig", "(" DISPLAY "[I[" CONFIG "I[I)Z", (void*)jni_eglChooseConfig },
530544
{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)I", (void*)jni_eglCreateContext },
531545
{"eglGetConfigs", "(" DISPLAY "[" CONFIG "I[I)Z", (void*)jni_eglGetConfigs },

libs/hwui/Caches.cpp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,16 @@ namespace uirenderer {
4646
// Constructors/destructor
4747
///////////////////////////////////////////////////////////////////////////////
4848

49-
Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
50-
lastDstMode(GL_ZERO), currentProgram(NULL) {
49+
Caches::Caches(): Singleton<Caches>(), mInitialized(false) {
5150
GLint maxTextureUnits;
5251
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
5352
if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
5453
LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
5554
}
5655

57-
glGenBuffers(1, &meshBuffer);
58-
glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
59-
glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
60-
6156
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
6257

63-
mCurrentBuffer = meshBuffer;
64-
mRegionMesh = NULL;
58+
init();
6559

6660
mDebugLevel = readDebugLevel();
6761
LOGD("Enabling debug mode %d", mDebugLevel);
@@ -71,8 +65,40 @@ Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
7165
#endif
7266
}
7367

74-
Caches::~Caches() {
68+
void Caches::init() {
69+
if (mInitialized) return;
70+
71+
glGenBuffers(1, &meshBuffer);
72+
glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
73+
glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
74+
75+
mCurrentBuffer = meshBuffer;
76+
mRegionMesh = NULL;
77+
78+
blend = false;
79+
lastSrcMode = GL_ZERO;
80+
lastDstMode = GL_ZERO;
81+
currentProgram = NULL;
82+
83+
mInitialized = true;
84+
}
85+
86+
void Caches::terminate() {
87+
if (!mInitialized) return;
88+
89+
glDeleteBuffers(1, &meshBuffer);
90+
mCurrentBuffer = 0;
91+
92+
glDeleteBuffers(1, &mRegionMeshIndices);
7593
delete[] mRegionMesh;
94+
mRegionMesh = NULL;
95+
96+
fboCache.clear();
97+
98+
programCache.clear();
99+
currentProgram = NULL;
100+
101+
mInitialized = false;
76102
}
77103

78104
///////////////////////////////////////////////////////////////////////////////

libs/hwui/Caches.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ struct CacheLogger {
8686

8787
class ANDROID_API Caches: public Singleton<Caches> {
8888
Caches();
89-
~Caches();
9089

9190
friend class Singleton<Caches>;
9291

@@ -108,13 +107,24 @@ class ANDROID_API Caches: public Singleton<Caches> {
108107
kFlushMode_Full
109108
};
110109

110+
/**
111+
* Initializes the cache.
112+
*/
113+
void init();
114+
111115
/**
112116
* Flush the cache.
113117
*
114118
* @param mode Indicates how much of the cache should be flushed
115119
*/
116120
void flush(FlushMode mode);
117121

122+
/**
123+
* Destroys all resources associated with this cache. This should
124+
* be called after a flush(kFlushMode_Full).
125+
*/
126+
void terminate();
127+
118128
/**
119129
* Indicates whether the renderer is in debug mode.
120130
* This debug mode provides limited information to app developers.
@@ -194,6 +204,7 @@ class ANDROID_API Caches: public Singleton<Caches> {
194204

195205
private:
196206
DebugLevel mDebugLevel;
207+
bool mInitialized;
197208
}; // class Caches
198209

199210
}; // namespace uirenderer

opengl/java/android/opengl/EGLLogWrapper.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,16 @@ public boolean eglQuerySurface(EGLDisplay display, EGLSurface surface,
314314
checkError();
315315
return result;
316316
}
317+
318+
/** @hide **/
319+
public boolean eglReleaseThread() {
320+
begin("eglReleaseThread");
321+
end();
322+
boolean result = mEgl10.eglReleaseThread();
323+
returns(result);
324+
checkError();
325+
return result;
326+
}
317327

318328
public boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface) {
319329
begin("eglInitialize");

0 commit comments

Comments
 (0)