aboutsummaryrefslogtreecommitdiffstats
path: root/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java')
-rw-r--r--src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java115
1 files changed, 101 insertions, 14 deletions
diff --git a/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java b/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java
index 8b34601..1d7c8bc 100644
--- a/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java
+++ b/src/org/cyanogenmod/wallpapers/photophase/utils/GLESUtil.java
@@ -22,6 +22,9 @@ import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.effect.Effect;
+import android.opengl.ETC1Util;
+import android.opengl.ETC1Util.ETC1Texture;
+import android.opengl.ETC1;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;
@@ -31,6 +34,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
/**
@@ -46,7 +52,10 @@ public final class GLESUtil {
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();
+ private static final Object SYNC = new Object();
+
+ private static final int MAX_ACEPTABLE_COMPRESSION_TIME = 1000;
+ private static boolean sDisabledTextureCompression = false;
/**
* A helper class to deal with OpenGL float colors.
@@ -330,10 +339,11 @@ public final class GLESUtil {
* @param effect The effect to apply to the image or null if no effect is needed
* @param dimen The new dimensions
* @param recycle If the bitmap should be recycled
+ * @param compress Try to compress the bitmap into ETC1
* @return GLESTextureInfo The texture info
*/
- public static GLESTextureInfo loadTexture(
- File file, Rect dimensions, Effect effect, Rect dimen, boolean recycle) {
+ public static GLESTextureInfo loadTexture(File file, Rect dimensions, Effect effect,
+ Rect dimen, boolean recycle, boolean compress) {
Bitmap bitmap = null;
try {
// Decode and associate the bitmap (invert the desired dimensions)
@@ -344,7 +354,7 @@ public final class GLESUtil {
}
if (DEBUG) Log.d(TAG, "image: " + file.getAbsolutePath());
- GLESTextureInfo ti = loadTexture(bitmap, effect, dimen);
+ GLESTextureInfo ti = loadTexture(bitmap, effect, dimen, compress);
ti.path = file;
return ti;
@@ -370,10 +380,11 @@ public final class GLESUtil {
* @param effect The effect to apply to the image or null if no effect is needed
* @param dimen The new dimensions
* @param recycle If the bitmap should be recycled
+ * @param compress Try to compress the bitmap into ETC1
* @return GLESTextureInfo The texture info
*/
- public static GLESTextureInfo loadTexture(
- Context ctx, int resourceId, Effect effect, Rect dimen, boolean recycle) {
+ public static GLESTextureInfo loadTexture(Context ctx, int resourceId, Effect effect,
+ Rect dimen, boolean recycle, boolean compress) {
Bitmap bitmap = null;
InputStream raw = null;
try {
@@ -387,7 +398,7 @@ public final class GLESUtil {
}
if (DEBUG) Log.d(TAG, "resourceId: " + resourceId);
- GLESTextureInfo ti = loadTexture(bitmap, effect, dimen);
+ GLESTextureInfo ti = loadTexture(bitmap, effect, dimen, compress);
return ti;
} catch (Exception e) {
@@ -418,9 +429,11 @@ public final class GLESUtil {
* @param bitmap The bitmap reference
* @param effect The effect to apply to the image or null if no effect is needed
* @param dimen The new dimensions
+ * @param compress Try to compress the bitmap into ETC1
* @return GLESTextureInfo The texture info
*/
- public static GLESTextureInfo loadTexture(Bitmap bitmap, Effect effect, Rect dimen) {
+ public static GLESTextureInfo loadTexture(Bitmap bitmap, Effect effect, Rect dimen,
+ boolean compress) {
// Check that we have a valid image name reference
if (bitmap == null) {
return new GLESTextureInfo();
@@ -455,18 +468,59 @@ public final class GLESUtil {
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLESUtil.glesCheckError("glTexParameteri");
- // Load the texture
- GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
- if (!GLES20.glIsTexture(textureHandles[0])) {
- Log.e(TAG, "Failed to load a valid texture");
- return new GLESTextureInfo();
+ // Load the texture. Check weather the device supports ETC1 compressed format
+ // AOSP ETC1 implementation doesn't support alpha channel
+ boolean fallback = true;
+ int bytesPerPixel = bitmap.getRowBytes() / bitmap.getWidth();
+ boolean hasAlpha = bitmap.hasAlpha() || (bytesPerPixel < 2 || bytesPerPixel > 3);
+ if (!sDisabledTextureCompression && compress && ETC1Util.isETC1Supported() && !hasAlpha) {
+ // Compress the texture
+ long start = System.currentTimeMillis();
+ ETC1Texture texture = createETC1CompressedTextureFromBitmap(bitmap);
+ if (texture != null) {
+ try {
+ long time = System.currentTimeMillis() - start;
+ if (DEBUG) {
+ Log.d(TAG, "Compression time: " + time + " ms");
+ }
+ if (time > MAX_ACEPTABLE_COMPRESSION_TIME) {
+ sDisabledTextureCompression = true;
+ Log.e(TAG, "Excessive compression time (" + time + " ms). " +
+ "Disabling compression");
+ }
+
+ // Load the compressed texture
+ int width = texture.getWidth();
+ int height = texture.getHeight();
+ Buffer data = texture.getData();
+ int imageSize = data.remaining();
+ GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D, 0, ETC1.ETC1_RGB8_OES,
+ width, height, 0, imageSize, data);
+ GLESUtil.glesCheckError("glCompressedTexImage2D");
+ fallback = !GLES20.glIsTexture(textureHandles[0]);
+ } finally {
+ texture = null;
+ }
+ }
+ }
+ if (fallback) {
+ if (DEBUG) {
+ Log.d(TAG, "Fallback to uncompressed texture.");
+ }
+
+ // Fallback to uncompressed texture
+ GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
+ if (!GLES20.glIsTexture(textureHandles[0])) {
+ Log.e(TAG, "Failed to load a valid texture");
+ return new GLESTextureInfo();
+ }
}
// Has a effect?
int handle = textureHandles[0];
if (effect != null) {
// Apply the effect (we need a thread-safe call here)
- synchronized (sSync) {
+ synchronized (SYNC) {
// No more than 1024 (the minimum supported by all the gles20 devices)
int w = Math.min(dimen.width(), 1024);
int h = Math.min(dimen.width(), 1024);
@@ -553,4 +607,37 @@ public final class GLESUtil {
}
}
+ /**
+ * Method that compress a uncompressed bitmap to an compressed ETC1 texture
+ *
+ * @param bitmap The uncompressed bitmap
+ * @return ETC1Texture The ETC1 compressed texture
+ */
+ private static ETC1Texture createETC1CompressedTextureFromBitmap(Bitmap bitmap) {
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+ int dataSize = bitmap.getRowBytes() * height;
+ int bytesPerPixel = bitmap.getRowBytes() / width;
+ int stride = bitmap.getRowBytes();
+
+ ByteBuffer dataBuffer = ByteBuffer.allocateDirect(dataSize).order(ByteOrder.nativeOrder());
+ try {
+ bitmap.copyPixelsToBuffer(dataBuffer);
+ dataBuffer.position(0);
+
+ int encodedImageSize = ETC1.getEncodedDataSize(width, height);
+ ByteBuffer compressedImage = ByteBuffer.allocateDirect(encodedImageSize).
+ order(ByteOrder.nativeOrder());
+ try {
+ ETC1.encodeImage(dataBuffer, width, height, bytesPerPixel, stride, compressedImage);
+ return new ETC1Util.ETC1Texture(width, height, compressedImage);
+ } catch (IllegalArgumentException ex) {
+ compressedImage = null;
+ }
+ } finally {
+ dataBuffer = null;
+ }
+ return null;
+ }
+
}