From c8d004f3be2bc071184dd32e17b87efccb3aca38 Mon Sep 17 00:00:00 2001 From: Jorge Ruesga Date: Sun, 31 Aug 2014 16:44:41 +0200 Subject: photophase: fix memory leaks * Fix memory leak caused by unreleased of framebuffers new refs * pre-cache Roboto typeface * trace allocations/deallocations GL's resources Change-Id: Ib1ca22aae7ba90c4282f91dcef69a5fe274017a8 Signed-off-by: Jorge Ruesga --- .../wallpapers/photophase/PhotoFrame.java | 9 ++++++++ .../wallpapers/photophase/TextureManager.java | 8 +++++++ .../photophase/effects/PhotoPhaseEffect.java | 16 +++++++++++++- .../wallpapers/photophase/shapes/ColorShape.java | 4 ++++ .../wallpapers/photophase/shapes/OopsShape.java | 21 ++++++++++++++++-- .../photophase/transitions/Transition.java | 5 +++++ .../wallpapers/photophase/utils/GLESUtil.java | 25 ++++++++++++++++++++++ 7 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/org/cyanogenmod/wallpapers/photophase/PhotoFrame.java b/src/org/cyanogenmod/wallpapers/photophase/PhotoFrame.java index 25b2734..57fd98a 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/PhotoFrame.java +++ b/src/org/cyanogenmod/wallpapers/photophase/PhotoFrame.java @@ -19,6 +19,7 @@ package org.cyanogenmod.wallpapers.photophase; import android.content.Context; import android.graphics.RectF; import android.opengl.GLES20; +import android.util.Log; import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil; import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil.GLColor; @@ -139,6 +140,10 @@ public class PhotoFrame implements TextureRequestor { if (mTextureInfo != null) { if (GLES20.glIsTexture(mTextureInfo.handle)) { int[] textures = new int[]{mTextureInfo.handle}; + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + + mTextureInfo.handle + "]"); + } GLES20.glDeleteTextures(1, textures, 0); GLESUtil.glesCheckError("glDeleteTextures"); } @@ -279,6 +284,10 @@ public class PhotoFrame implements TextureRequestor { public void recycle() { if (mTextureInfo != null && mTextureInfo.handle != 0) { int[] textures = new int[]{mTextureInfo.handle}; + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + + mTextureInfo.handle + "]"); + } GLES20.glDeleteTextures(1, textures, 0); GLESUtil.glesCheckError("glDeleteTextures"); } diff --git a/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java b/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java index 104db0d..417cfb9 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java +++ b/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java @@ -281,6 +281,10 @@ public class TextureManager implements OnMediaPictureDiscoveredListener { for (GLESTextureInfo info : all) { if (GLES20.glIsTexture(info.handle)) { int[] textures = new int[] {info.handle}; + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + + info.handle + "]"); + } GLES20.glDeleteTextures(1, textures, 0); GLESUtil.glesCheckError("glDeleteTextures"); } @@ -449,6 +453,10 @@ public class TextureManager implements OnMediaPictureDiscoveredListener { // Destroy references int[] textures = new int[]{ti.handle}; + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + + ti.handle + "]"); + } GLES20.glDeleteTextures(1, textures, 0); GLESUtil.glesCheckError("glDeleteTextures"); if (ti.bitmap != null) { diff --git a/src/org/cyanogenmod/wallpapers/photophase/effects/PhotoPhaseEffect.java b/src/org/cyanogenmod/wallpapers/photophase/effects/PhotoPhaseEffect.java index 0b3c5fc..0900322 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/effects/PhotoPhaseEffect.java +++ b/src/org/cyanogenmod/wallpapers/photophase/effects/PhotoPhaseEffect.java @@ -21,6 +21,7 @@ import android.media.effect.EffectContext; import android.media.effect.EffectFactory; import android.opengl.GLES20; import android.opengl.GLUtils; +import android.util.Log; import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil; @@ -138,11 +139,14 @@ public abstract class PhotoPhaseEffect extends Effect { // Save the GLES state saveGLState(); + int[] fb = new int[1]; try { // Create a framebuffer object and call the effect apply method to draw the effect - int[] fb = new int[1]; GLES20.glGenFramebuffers(1, fb, 0); GLESUtil.glesCheckError("glGenFramebuffers"); + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_NEW_TAG, "glGenFramebuffers: " + fb[0]); + } GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]); GLESUtil.glesCheckError("glBindFramebuffer"); @@ -171,6 +175,13 @@ public abstract class PhotoPhaseEffect extends Effect { } finally { // Restore the GLES state restoreGLState(); + + // Clean framebuffer memory + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteFramebuffers: " + fb[0]); + } + GLES20.glDeleteFramebuffers(1, fb, 0); + GLESUtil.glesCheckError("glDeleteFramebuffers"); } } @@ -189,6 +200,9 @@ public abstract class PhotoPhaseEffect extends Effect { @Override public void release() { if (GLES20.glIsProgram(mProgram)) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteProgram: " + mProgram); + } GLES20.glDeleteProgram(mProgram); GLESUtil.glesCheckError("glDeleteProgram"); } diff --git a/src/org/cyanogenmod/wallpapers/photophase/shapes/ColorShape.java b/src/org/cyanogenmod/wallpapers/photophase/shapes/ColorShape.java index ceb7ec4..c05836f 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/shapes/ColorShape.java +++ b/src/org/cyanogenmod/wallpapers/photophase/shapes/ColorShape.java @@ -18,6 +18,7 @@ package org.cyanogenmod.wallpapers.photophase.shapes; import android.content.Context; import android.opengl.GLES20; +import android.util.Log; import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil; import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil.GLColor; @@ -137,6 +138,9 @@ public class ColorShape implements DrawableShape { */ public void recycle() { if (GLES20.glIsProgram(mProgramHandler)) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteProgram: " + mProgramHandler); + } GLES20.glDeleteProgram(mProgramHandler); GLESUtil.glesCheckError("glDeleteProgram"); } diff --git a/src/org/cyanogenmod/wallpapers/photophase/shapes/OopsShape.java b/src/org/cyanogenmod/wallpapers/photophase/shapes/OopsShape.java index d7b3e89..195a1e4 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/shapes/OopsShape.java +++ b/src/org/cyanogenmod/wallpapers/photophase/shapes/OopsShape.java @@ -24,6 +24,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.opengl.GLES20; +import android.util.Log; import org.cyanogenmod.wallpapers.photophase.Colors; import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil; @@ -65,6 +66,8 @@ public class OopsShape implements DrawableShape { 0.5f, 0.75f }; + private static Typeface sRobotoFont; + private FloatBuffer mPositionBuffer; private FloatBuffer mTextureBuffer; @@ -87,6 +90,9 @@ public class OopsShape implements DrawableShape { */ public OopsShape(Context ctx, int resourceMessageId) { super(); + if (sRobotoFont == null) { + sRobotoFont = Typeface.createFromAsset(ctx.getAssets(), "fonts/Roboto-Bold.ttf"); + } int orientation = ctx.getResources().getConfiguration().orientation; float[] vertex = VERTEX_COORDS_PORTRAIT; @@ -233,12 +239,20 @@ public class OopsShape implements DrawableShape { public void recycle() { // Remove textures if (mOopsImageTexture != null && mOopsImageTexture.handle != 0) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + + mOopsImageTexture.handle + "]"); + } int[] textures = new int[]{mOopsImageTexture.handle}; GLES20.glDeleteTextures(1, textures, 0); GLESUtil.glesCheckError("glDeleteTextures"); } mOopsImageTexture = null; if (mOopsTextTexture != null && mOopsTextTexture.handle != 0) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + + mOopsTextTexture.handle + "]"); + } int[] textures = new int[]{mOopsTextTexture.handle}; GLES20.glDeleteTextures(1, textures, 0); GLESUtil.glesCheckError("glDeleteTextures"); @@ -257,6 +271,10 @@ public class OopsShape implements DrawableShape { for (int i = 0; i < 2; i++) { if (GLES20.glIsProgram(mProgramHandlers[i])) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteProgram: " + + mProgramHandlers[i]); + } GLES20.glDeleteProgram(mProgramHandlers[i]); GLESUtil.glesCheckError("glDeleteProgram(" + i + ")"); } @@ -277,8 +295,7 @@ public class OopsShape implements DrawableShape { */ public Bitmap text2Bitmap(Context ctx, String text) { Paint paint = new Paint(); - Typeface font = Typeface.createFromAsset(ctx.getAssets(), "fonts/Roboto-Bold.ttf"); - paint.setTypeface(font); + paint.setTypeface(sRobotoFont); paint.setColor(Color.WHITE); paint.setTextSize(24.0f); paint.setAntiAlias(true); diff --git a/src/org/cyanogenmod/wallpapers/photophase/transitions/Transition.java b/src/org/cyanogenmod/wallpapers/photophase/transitions/Transition.java index bae0399..c82323d 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/transitions/Transition.java +++ b/src/org/cyanogenmod/wallpapers/photophase/transitions/Transition.java @@ -18,6 +18,7 @@ package org.cyanogenmod.wallpapers.photophase.transitions; import android.content.Context; import android.opengl.GLES20; +import android.util.Log; import org.cyanogenmod.wallpapers.photophase.utils.GLESUtil; import org.cyanogenmod.wallpapers.photophase.PhotoFrame; @@ -192,6 +193,10 @@ public abstract class Transition { int cc = mProgramHandlers.length; for (int i = 0; i < cc; i++) { if (GLES20.glIsProgram(mProgramHandlers[i])) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteProgram: " + + mProgramHandlers[i]); + } GLES20.glDeleteProgram(mProgramHandlers[i]); GLESUtil.glesCheckError("glDeleteProgram"); } diff --git a/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java b/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java index 0078ea6..8b34601 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java +++ b/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java @@ -42,6 +42,10 @@ public final class GLESUtil { private static final boolean DEBUG = false; + public static final boolean DEBUG_GL_MEMOBJS = false; + public static final String DEBUG_GL_MEMOBJS_NEW_TAG = "MEMOBJS_NEW"; + public static final String DEBUG_GL_MEMOBJS_DEL_TAG = "MEMOBJS_DEL"; + private static final Object sSync = new Object(); /** @@ -207,6 +211,9 @@ public final class GLESUtil { int[] compiled = new int[1]; // Create, load and compile the shader int shader = GLES20.glCreateShader(type); + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_NEW_TAG, "glCreateShader (" + type + "): " + shader); + } GLESUtil.glesCheckError("glCreateShader"); if (shader <= 0) { Log.e(TAG, "Cannot create a shader"); @@ -265,6 +272,9 @@ public final class GLESUtil { // Create the programa ref progid = GLES20.glCreateProgram(); + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_NEW_TAG, "glCreateProgram: " + progid); + } GLESUtil.glesCheckError("glCreateProgram"); if (progid <= 0) { String msg = "Cannot create a program"; @@ -296,10 +306,16 @@ public final class GLESUtil { } finally { // Delete the shaders if (vshader != 0) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteShader (v): " + vshader); + } GLES20.glDeleteShader(vshader); GLESUtil.glesCheckError("glDeleteShader"); } if (fshader != 0) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteShader (f): " + fshader); + } GLES20.glDeleteShader(fshader); GLESUtil.glesCheckError("glDeleteShader"); } @@ -415,6 +431,11 @@ public final class GLESUtil { int[] textureHandles = new int[num]; GLES20.glGenTextures(num, textureHandles, 0); GLESUtil.glesCheckError("glGenTextures"); + for (int i = 0; i < num; i++) { + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_NEW_TAG, "glGenTextures: " + textureHandles[i]); + } + } if (textureHandles[0] <= 0 || (effect != null && textureHandles[1] <= 0)) { Log.e(TAG, "Failed to generate a valid texture"); return new GLESTextureInfo(); @@ -455,6 +476,10 @@ public final class GLESUtil { // Delete the unused texture int[] textures = {textureHandles[0]}; + if (GLESUtil.DEBUG_GL_MEMOBJS) { + Log.d(GLESUtil.DEBUG_GL_MEMOBJS_DEL_TAG, "glDeleteTextures: [" + + textureHandles[0] + "]"); + } GLES20.glDeleteTextures(1, textures, 0); GLESUtil.glesCheckError("glDeleteTextures"); } -- cgit v1.2.3