Adjust loading priority and throttle texture upload to make animation more smooth.
Change-Id: Ibed8d7250aaa3530386c8968a9cab8d29a35ac9a
diff --git a/new3d/src/com/android/gallery3d/data/ImageService.java b/new3d/src/com/android/gallery3d/data/ImageService.java
index 1465f23..485db0d 100644
--- a/new3d/src/com/android/gallery3d/data/ImageService.java
+++ b/new3d/src/com/android/gallery3d/data/ImageService.java
@@ -18,6 +18,7 @@
import android.content.ContentResolver;
import android.graphics.Bitmap;
+import android.os.Process;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
@@ -28,6 +29,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -42,7 +44,8 @@
private final Executor mExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
- TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
+ TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
+ new MyThreadFactory());
private final ContentResolver mContentResolver;
@@ -229,4 +232,14 @@
}
}
+ class MyThreadFactory implements ThreadFactory {
+ public Thread newThread(final Runnable r) {
+ return new Thread() {
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ r.run();
+ }
+ };
+ }
+ }
}
diff --git a/new3d/src/com/android/gallery3d/data/LocalAlbum.java b/new3d/src/com/android/gallery3d/data/LocalAlbum.java
index 2a1078e..2609f05 100644
--- a/new3d/src/com/android/gallery3d/data/LocalAlbum.java
+++ b/new3d/src/com/android/gallery3d/data/LocalAlbum.java
@@ -94,6 +94,7 @@
Uri uri = mBaseUri.buildUpon()
.appendQueryParameter("limit", start + "," + count).build();
ArrayList<MediaItem> list = new ArrayList<MediaItem>();
+ Utils.assertNotInRenderThread();
Cursor cursor = mResolver.query(
uri, mProjection, mWhereClause,
new String[]{String.valueOf(mBucketId)},
@@ -116,6 +117,7 @@
@Override
public int getMediaItemCount() {
+ Utils.assertNotInRenderThread();
Cursor cursor = mResolver.query(
mBaseUri, COUNT_PROJECTION, mWhereClause,
new String[]{String.valueOf(mBucketId)}, null);
@@ -196,6 +198,7 @@
public void delete(long uniqueId) {
Utils.Assert(DataManager.extractParentId(uniqueId) == getMyId());
int itemId = DataManager.extractSelfId(uniqueId);
+ Utils.assertNotInRenderThread();
mResolver.delete(mBaseUri, DELETE_ITEM_WHERE_CLAUSE,
new String[] {String.valueOf(itemId)});
}
@@ -205,6 +208,7 @@
}
public void deleteSelf() {
+ Utils.assertNotInRenderThread();
mResolver.delete(mBaseUri, mWhereClause,
new String[]{String.valueOf(mBucketId)});
}
diff --git a/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java b/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java
index b6333b5..e88dda1 100644
--- a/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java
+++ b/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java
@@ -104,6 +104,7 @@
protected void onLoadFromDatabase() {
Uri uri = mBaseUri.buildUpon().
appendQueryParameter("distinct", "true").build();
+ Utils.assertNotInRenderThread();
Cursor cursor = mResolver.query(
uri, mProjection, null, null, null);
if (cursor == null) throw new NullPointerException();
diff --git a/new3d/src/com/android/gallery3d/data/LocalImage.java b/new3d/src/com/android/gallery3d/data/LocalImage.java
index d8e3394..36e1384 100644
--- a/new3d/src/com/android/gallery3d/data/LocalImage.java
+++ b/new3d/src/com/android/gallery3d/data/LocalImage.java
@@ -33,7 +33,7 @@
private static final int MICRO_TARGET_PIXELS = 128 * 128;
private static final int FULLIMAGE_TARGET_SIZE = 2048;
- private static final int FULLIMAGE_MAX_NUM_PIXELS = 5 * 1024 * 1024;
+ private static final int FULLIMAGE_MAX_NUM_PIXELS = 3 * 1024 * 1024;
private static final String TAG = "LocalImage";
// Must preserve order between these indices and the order of the terms in
diff --git a/new3d/src/com/android/gallery3d/data/PicasaAlbum.java b/new3d/src/com/android/gallery3d/data/PicasaAlbum.java
index c560aca..bc989fd 100644
--- a/new3d/src/com/android/gallery3d/data/PicasaAlbum.java
+++ b/new3d/src/com/android/gallery3d/data/PicasaAlbum.java
@@ -65,6 +65,7 @@
.appendQueryParameter("limit", start + "," + count).build();
ArrayList<MediaItem> list = new ArrayList<MediaItem>();
+ Utils.assertNotInRenderThread();
Cursor cursor = mResolver.query(uri,
SCHEMA.getProjection(), WHERE_CLAUSE,
new String[]{String.valueOf(mData.id)},
@@ -86,6 +87,7 @@
@Override
public int getMediaItemCount() {
+ Utils.assertNotInRenderThread();
Cursor cursor = mResolver.query(
PicasaContentProvider.PHOTOS_URI,
COUNT_PROJECTION, WHERE_CLAUSE,
diff --git a/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java b/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java
index 017fd22..d4db0fa 100644
--- a/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java
+++ b/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java
@@ -24,6 +24,7 @@
import com.android.gallery3d.picasa.AlbumEntry;
import com.android.gallery3d.picasa.EntrySchema;
import com.android.gallery3d.picasa.PicasaContentProvider;
+import com.android.gallery3d.util.Utils;
import java.util.ArrayList;
@@ -72,6 +73,7 @@
@Override
protected void onLoadFromDatabase() {
+ Utils.assertNotInRenderThread();
Cursor cursor = mResolver.query(
PicasaContentProvider.ALBUMS_URI,
SCHEMA.getProjection(), null, null, null);
diff --git a/new3d/src/com/android/gallery3d/ui/AlbumSlidingWindow.java b/new3d/src/com/android/gallery3d/ui/AlbumSlidingWindow.java
index ec65446..fde83da 100644
--- a/new3d/src/com/android/gallery3d/ui/AlbumSlidingWindow.java
+++ b/new3d/src/com/android/gallery3d/ui/AlbumSlidingWindow.java
@@ -231,7 +231,9 @@
if (mActiveRequestCount == 0) requestNonactiveImages();
}
if (bitmap != null) {
- updateContent(new BitmapTexture(bitmap));
+ BitmapTexture texture = new BitmapTexture(bitmap);
+ texture.setThrottled(true);
+ updateContent(texture);
if (mListener != null) mListener.onContentInvalidated();
}
}
diff --git a/new3d/src/com/android/gallery3d/ui/BasicTexture.java b/new3d/src/com/android/gallery3d/ui/BasicTexture.java
index 276d949..35b633a 100644
--- a/new3d/src/com/android/gallery3d/ui/BasicTexture.java
+++ b/new3d/src/com/android/gallery3d/ui/BasicTexture.java
@@ -109,7 +109,7 @@
// onBind is called before GLCanvas binds this texture.
// It should make sure the data is uploaded to GL memory.
- abstract protected void onBind(GLCanvas canvas);
+ abstract protected boolean onBind(GLCanvas canvas);
public boolean isLoaded(GLCanvas canvas) {
return mState == STATE_LOADED && mCanvasRef.get() == canvas;
diff --git a/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java b/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java
index 0fe08fb..0079802 100644
--- a/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java
+++ b/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java
@@ -227,7 +227,7 @@
if (chunk.mDivX.length != 2 || chunk.mDivY.length != 2) {
throw new RuntimeException("unsupported nine patch");
}
- bindTexture(tex);
+ if (!bindTexture(tex)) return;
if (width <= 0 || height <= 0) return;
int divX[] = mNinePatchX;
@@ -476,7 +476,7 @@
if (width <= 0 || height <= 0) return;
mGLState.setBlendEnabled(!texture.isOpaque() || alpha < OPAQUE_ALPHA);
- bindTexture(texture);
+ if (!bindTexture(texture)) return;
mGLState.setTextureAlpha(alpha);
drawBoundTexture(texture, x, y, width, height);
}
@@ -491,7 +491,7 @@
target = mDrawTextureTargetRect;
mGLState.setBlendEnabled(!texture.isOpaque() || mAlpha < OPAQUE_ALPHA);
- bindTexture(texture);
+ if (!bindTexture(texture)) return;
convertCoordinate(source, target, texture);
setTextureCoords(source);
mGLState.setTextureAlpha(mAlpha);
@@ -538,10 +538,11 @@
drawMixed(from, to, ratio, x, y, w, h, mAlpha);
}
- private void bindTexture(BasicTexture texture) {
- texture.onBind(this);
+ private boolean bindTexture(BasicTexture texture) {
+ if (!texture.onBind(this)) return false;
mGLState.setTexture2DEnabled(true);
mGL.glBindTexture(GL11.GL_TEXTURE_2D, texture.getId());
+ return true;
}
private void setTextureColor(float r, float g, float b, float alpha) {
@@ -572,7 +573,7 @@
|| !to.isOpaque() || alpha < OPAQUE_ALPHA);
final GL11 gl = mGL;
- bindTexture(from);
+ if (!bindTexture(from)) return;
//
// The formula we want:
@@ -593,7 +594,13 @@
}
gl.glActiveTexture(GL11.GL_TEXTURE1);
- bindTexture(to);
+ if (!bindTexture(to)) {
+ // Disable TEXTURE1.
+ gl.glDisable(GL11.GL_TEXTURE_2D);
+ // Switch back to the default texture unit.
+ gl.glActiveTexture(GL11.GL_TEXTURE0);
+ return;
+ }
gl.glEnable(GL11.GL_TEXTURE_2D);
// Interpolate the RGB and alpha values between both textures.
diff --git a/new3d/src/com/android/gallery3d/ui/GLRootView.java b/new3d/src/com/android/gallery3d/ui/GLRootView.java
index 0917b53..8d6f917 100644
--- a/new3d/src/com/android/gallery3d/ui/GLRootView.java
+++ b/new3d/src/com/android/gallery3d/ui/GLRootView.java
@@ -21,6 +21,7 @@
import android.graphics.Rect;
import android.opengl.GLSurfaceView;
import android.os.SystemClock;
+import android.os.Process;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -86,6 +87,9 @@
private ReentrantLock mRenderLock = new ReentrantLock();
+ private static final int TARGET_FRAME_TIME = 33;
+ private long mLastDrawFinishTime;
+
public GLRootView(Context context) {
this(context, null);
}
@@ -219,6 +223,8 @@
public void onSurfaceChanged(GL10 gl1, int width, int height) {
Log.v(TAG, "onSurfaceChanged: " + width + "x" + height
+ ", gl10: " + gl1.toString());
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
+ Utils.setRenderThread();
GL11 gl = (GL11) gl1;
Utils.Assert(mGL == gl);
@@ -242,12 +248,22 @@
}
public void onDrawFrame(GL10 gl) {
+ long begin = SystemClock.uptimeMillis();
mRenderLock.lock();
try {
onDrawFrameLocked(gl);
} finally {
mRenderLock.unlock();
}
+ long end = SystemClock.uptimeMillis();
+
+ if (mLastDrawFinishTime != 0) {
+ long wait = mLastDrawFinishTime + TARGET_FRAME_TIME - end;
+ if (wait > 0) {
+ SystemClock.sleep(wait);
+ }
+ }
+ mLastDrawFinishTime = SystemClock.uptimeMillis();
}
private void onDrawFrameLocked(GL10 gl) {
@@ -256,6 +272,9 @@
// release the unbound textures
mCanvas.deleteRecycledTextures();
+ // reset texture upload limit
+ UploadedTexture.resetUploadLimit();
+
mRenderRequested = false;
if ((mFlags & FLAG_NEED_LAYOUT) != 0) layoutContentPane();
@@ -282,6 +301,10 @@
mAnimations.clear();
}
+ if (UploadedTexture.uploadLimitReached()) {
+ requestRender();
+ }
+
if (!mRenderRequested
&& !mIdleRunner.mActive && !mIdleListeners.isEmpty()) {
mIdleRunner.mActive = true;
diff --git a/new3d/src/com/android/gallery3d/ui/GallerySlidingWindow.java b/new3d/src/com/android/gallery3d/ui/GallerySlidingWindow.java
index 02f84bc..ce8e282 100644
--- a/new3d/src/com/android/gallery3d/ui/GallerySlidingWindow.java
+++ b/new3d/src/com/android/gallery3d/ui/GallerySlidingWindow.java
@@ -291,7 +291,9 @@
if (mActiveRequestCount == 0) requestNonactiveImages();
}
if (bitmap != null) {
- updateContent(new BitmapTexture(bitmap));
+ BitmapTexture texture = new BitmapTexture(bitmap);
+ texture.setThrottled(true);
+ updateContent(texture);
if (mListener != null) mListener.onContentInvalidated();
}
}
diff --git a/new3d/src/com/android/gallery3d/ui/RawTexture.java b/new3d/src/com/android/gallery3d/ui/RawTexture.java
index eee3a10..c1be435 100644
--- a/new3d/src/com/android/gallery3d/ui/RawTexture.java
+++ b/new3d/src/com/android/gallery3d/ui/RawTexture.java
@@ -36,10 +36,11 @@
}
@Override
- protected void onBind(GLCanvas canvas) {
+ protected boolean onBind(GLCanvas canvas) {
if (mCanvasRef.get() != canvas) {
throw new RuntimeException("cannot bind to different canvas");
}
+ return true;
}
public boolean isOpaque() {
diff --git a/new3d/src/com/android/gallery3d/ui/UploadedTexture.java b/new3d/src/com/android/gallery3d/ui/UploadedTexture.java
index 5121ec1..f9248e5 100644
--- a/new3d/src/com/android/gallery3d/ui/UploadedTexture.java
+++ b/new3d/src/com/android/gallery3d/ui/UploadedTexture.java
@@ -44,6 +44,9 @@
private static final String TAG = "Texture";
private boolean mContentValid = true;
private boolean mOpaque = true;
+ private boolean mThrottled = false;
+ private static int sUploadedCount;
+ private static final int UPLOAD_LIMIT = 1;
protected Bitmap mBitmap;
@@ -51,6 +54,10 @@
super(null, 0, STATE_UNLOADED);
}
+ protected void setThrottled(boolean throttled) {
+ mThrottled = throttled;
+ }
+
private Bitmap getBitmap() {
if (mBitmap == null) {
mBitmap = onGetBitmap();
@@ -104,6 +111,9 @@
*/
public void updateContent(GLCanvas canvas) {
if (!isLoaded(canvas)) {
+ if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) {
+ return;
+ }
uploadToCanvas(canvas);
} else if (!mContentValid) {
Bitmap bitmap = getBitmap();
@@ -117,6 +127,14 @@
}
}
+ public static void resetUploadLimit() {
+ sUploadedCount = 0;
+ }
+
+ public static boolean uploadLimitReached() {
+ return sUploadedCount > UPLOAD_LIMIT;
+ }
+
static int[] sTextureId = new int[1];
static int[] sCropRect = new int[4];
@@ -175,8 +193,9 @@
}
@Override
- protected void onBind(GLCanvas canvas) {
+ protected boolean onBind(GLCanvas canvas) {
updateContent(canvas);
+ return isContentValid(canvas);
}
public void setOpaque(boolean isOpaque) {
diff --git a/new3d/src/com/android/gallery3d/util/Utils.java b/new3d/src/com/android/gallery3d/util/Utils.java
index abdbe71..691813e 100644
--- a/new3d/src/com/android/gallery3d/util/Utils.java
+++ b/new3d/src/com/android/gallery3d/util/Utils.java
@@ -6,7 +6,9 @@
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Bitmap.Config;
+import android.os.SystemClock;
import android.util.DisplayMetrics;
+import android.util.Log;
import java.nio.charset.Charset;
@@ -221,4 +223,23 @@
public static byte[] getBytesInUtf8(String in) {
return sUtf8Codec.encode(in).array();
}
+
+ // Below are used the detect using database in the render thread. It only
+ // works most of the time, but that's ok because it's for debugging only.
+
+ private static volatile Thread sCurrentThread;
+ private static volatile boolean sWarned;
+
+ public static void setRenderThread() {
+ sCurrentThread = Thread.currentThread();
+ }
+
+ public static void assertNotInRenderThread() {
+ if (!sWarned) {
+ if (Thread.currentThread() == sCurrentThread) {
+ sWarned = true;
+ Log.w(TAG, new Throwable("Should not do this in render thread"));
+ }
+ }
+ }
}
diff --git a/new3d/tests/src/com/android/gallery3d/ui/GLCanvasTest.java b/new3d/tests/src/com/android/gallery3d/ui/GLCanvasTest.java
index 5f0ea80..ce4d0bc 100644
--- a/new3d/tests/src/com/android/gallery3d/ui/GLCanvasTest.java
+++ b/new3d/tests/src/com/android/gallery3d/ui/GLCanvasTest.java
@@ -498,8 +498,9 @@
}
@Override
- protected void onBind(GLCanvas canvas) {
+ protected boolean onBind(GLCanvas canvas) {
mBindCalled++;
+ return true;
}
public boolean isOpaque() {
diff --git a/new3d/tests/src/com/android/gallery3d/ui/TextureTest.java b/new3d/tests/src/com/android/gallery3d/ui/TextureTest.java
index fcc4a6c..bee401a 100644
--- a/new3d/tests/src/com/android/gallery3d/ui/TextureTest.java
+++ b/new3d/tests/src/com/android/gallery3d/ui/TextureTest.java
@@ -21,8 +21,9 @@
}
@Override
- protected void onBind(GLCanvas canvas) {
+ protected boolean onBind(GLCanvas canvas) {
mOnBindCalled++;
+ return true;
}
public boolean isOpaque() {
@@ -167,7 +168,8 @@
}
@Override
- protected void onBind(GLCanvas canvas) {
+ protected boolean onBind(GLCanvas canvas) {
+ return true;
}
public boolean isOpaque() {