Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e29fc4a5 authored by Owen Lin's avatar Owen Lin
Browse files

Upload screennails in tiles to prevent jank

bug: 6399444

Change-Id: Id2338db34d7f87fbabd7861f78b42f2a81d9794b
parent 9bcba5b0
Loading
Loading
Loading
Loading
+39 −2
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.gallery3d.ui.PhotoView;
import com.android.gallery3d.ui.ScreenNail;
import com.android.gallery3d.ui.SynchronizedHandler;
import com.android.gallery3d.ui.TileImageViewAdapter;
import com.android.gallery3d.ui.TiledTexture;
import com.android.gallery3d.util.Future;
import com.android.gallery3d.util.FutureListener;
import com.android.gallery3d.util.MediaSetUtils;
@@ -59,8 +60,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
    private static final int MSG_RUN_OBJECT = 3;
    private static final int MSG_UPDATE_IMAGE_REQUESTS = 4;

    private static final int MIN_LOAD_COUNT = 8;
    private static final int DATA_CACHE_SIZE = 32;
    private static final int MIN_LOAD_COUNT = 16;
    private static final int DATA_CACHE_SIZE = 256;
    private static final int SCREEN_NAIL_MAX = PhotoView.SCREEN_NAIL_MAX;
    private static final int IMAGE_CACHE_SIZE = 2 * SCREEN_NAIL_MAX + 1;

@@ -162,6 +163,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
    private DataListener mDataListener;

    private final SourceListener mSourceListener = new SourceListener();
    private final TiledTexture.Uploader mUploader;

    // The path of the current viewing item will be stored in mItemPath.
    // If mItemPath is not null, mCurrentIndex is only a hint for where we
@@ -183,6 +185,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {

        Arrays.fill(mChanges, MediaObject.INVALID_DATA_VERSION);

        mUploader = new TiledTexture.Uploader(activity.getGLRoot());

        mMainHandler = new SynchronizedHandler(activity.getGLRoot()) {
            @SuppressWarnings("unchecked")
            @Override
@@ -321,6 +325,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
            }
        }
        updateImageRequests();
        updateScreenNailUploadQueue();
    }

    private void updateFullImage(Path path, Future<BitmapRegionDecoder> future) {
@@ -345,6 +350,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
    @Override
    public void resume() {
        mIsActive = true;
        TiledTexture.prepareResources();

        mSource.addContentListener(mSourceListener);
        updateImageCache();
        updateImageRequests();
@@ -371,6 +378,9 @@ public class PhotoDataAdapter implements PhotoPage.Model {
        }
        mImageCache.clear();
        mTileProvider.clear();

        mUploader.clear();
        TiledTexture.freeResources();
    }

    private MediaItem getItem(int index) {
@@ -394,6 +404,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
        updateImageCache();
        updateImageRequests();
        updateTileProvider();
        updateScreenNailUploadQueue();

        if (mDataListener != null) {
            mDataListener.onPhotoChanged(index, mItemPath);
@@ -402,6 +413,32 @@ public class PhotoDataAdapter implements PhotoPage.Model {
        fireDataChange();
    }

    private void uploadScreenNail(int offset) {
        int index = mCurrentIndex + offset;
        if (index < mActiveStart || index >= mActiveEnd) return;

        MediaItem item = getItem(index);
        if (item == null) return;

        ImageEntry e = mImageCache.get(item.getPath());
        if (e == null) return;

        ScreenNail s = e.screenNail;
        if (s instanceof BitmapScreenNail) {
            TiledTexture t = ((BitmapScreenNail) s).getTexture();
            if (t != null && !t.isReady()) mUploader.addTexture(t);
        }
    }

    private void updateScreenNailUploadQueue() {
        mUploader.clear();
        uploadScreenNail(0);
        for (int i = 1; i < IMAGE_CACHE_SIZE; ++i) {
            uploadScreenNail(i);
            uploadScreenNail(-i);
        }
    }

    @Override
    public void moveTo(int index) {
        updateCurrentIndex(index);
+2 −2
Original line number Diff line number Diff line
@@ -42,8 +42,8 @@ abstract class BasicTexture implements Texture {
    protected int mWidth = UNSPECIFIED;
    protected int mHeight = UNSPECIFIED;

    private int mTextureWidth;
    private int mTextureHeight;
    protected int mTextureWidth;
    protected int mTextureHeight;

    private boolean mHasBorder;

+19 −30
Original line number Diff line number Diff line
@@ -46,16 +46,16 @@ public class BitmapScreenNail implements ScreenNail {

    private int mWidth;
    private int mHeight;
    private Bitmap mBitmap;
    private BitmapTexture mTexture;
    private long mAnimationStartTime = ANIMATION_NOT_NEEDED;

    private Bitmap mBitmap;
    private TiledTexture mTexture;

    public BitmapScreenNail(Bitmap bitmap) {
        mWidth = bitmap.getWidth();
        mHeight = bitmap.getHeight();
        mBitmap = bitmap;
        // We create mTexture lazily, so we don't incur the cost if we don't
        // actually need it.
        mTexture = new TiledTexture(bitmap);
    }

    public BitmapScreenNail(int width, int height) {
@@ -103,17 +103,14 @@ public class BitmapScreenNail implements ScreenNail {
        BitmapScreenNail newer = (BitmapScreenNail) other;
        mWidth = newer.mWidth;
        mHeight = newer.mHeight;
        if (newer.mBitmap != null) {
        if (newer.mTexture != null) {
            recycleBitmap(MediaItem.getThumbPool(), mBitmap);
            if (mTexture != null) mTexture.recycle();
            mBitmap = newer.mBitmap;
            mTexture = newer.mTexture;
            newer.mBitmap = null;

            if (mTexture != null) {
                mTexture.recycle();
                mTexture = null;
            newer.mTexture = null;
        }
        }

        newer.recycle();
        return this;
    }
@@ -158,7 +155,7 @@ public class BitmapScreenNail implements ScreenNail {

    @Override
    public void draw(GLCanvas canvas, int x, int y, int width, int height) {
        if (mBitmap == null) {
        if (mTexture == null || !mTexture.isReady()) {
            if (mAnimationStartTime == ANIMATION_NOT_NEEDED) {
                mAnimationStartTime = ANIMATION_NEEDED;
            }
@@ -168,16 +165,12 @@ public class BitmapScreenNail implements ScreenNail {
            return;
        }

        if (mTexture == null) {
            mTexture = new BitmapTexture(mBitmap);
        }

        if (mAnimationStartTime == ANIMATION_NEEDED) {
            mAnimationStartTime = now();
            mAnimationStartTime = AnimationTime.get();
        }

        if (isAnimating()) {
            canvas.drawMixed(mTexture, mPlaceholderColor, getRatio(), x, y,
            mTexture.drawMixed(canvas, mPlaceholderColor, getRatio(), x, y,
                    width, height);
        } else {
            mTexture.draw(canvas, x, y, width, height);
@@ -186,38 +179,34 @@ public class BitmapScreenNail implements ScreenNail {

    @Override
    public void draw(GLCanvas canvas, RectF source, RectF dest) {
        if (mBitmap == null) {
        if (mTexture == null || !mTexture.isReady()) {
            canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(),
                    mPlaceholderColor);
            return;
        }

        if (mTexture == null) {
            mTexture = new BitmapTexture(mBitmap);
        }

        canvas.drawTexture(mTexture, source, dest);
        mTexture.draw(canvas, source, dest);
    }

    public boolean isAnimating() {
        if (mAnimationStartTime < 0) return false;
        if (now() - mAnimationStartTime >= DURATION) {
        if (AnimationTime.get() - mAnimationStartTime >= DURATION) {
            mAnimationStartTime = ANIMATION_DONE;
            return false;
        }
        return true;
    }

    private static long now() {
        return AnimationTime.get();
    }

    private float getRatio() {
        float r = (float)(now() - mAnimationStartTime) / DURATION;
        float r = (float) (AnimationTime.get() - mAnimationStartTime) / DURATION;
        return Utils.clamp(1.0f - r, 0.0f, 1.0f);
    }

    public boolean isShowingPlaceholder() {
        return (mBitmap == null) || isAnimating();
    }

    public TiledTexture getTexture() {
        return mTexture;
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -99,6 +99,13 @@ public interface GLCanvas {
    public void drawMixed(BasicTexture from, int toColor,
            float ratio, int x, int y, int w, int h);

    // Draw a region of a texture and a specified color to the specified
    // rectangle. The actual color used is from * (1 - ratio) + to * ratio.
    // The region of the texture is defined by parameter "src". The target
    // rectangle is specified by parameter "target".
    public void drawMixed(BasicTexture from, int toColor,
            float ratio, RectF src, RectF target);

    // Gets the underlying GL instance. This is used only when direct access to
    // GL is needed.
    public GL11 getGLInstance();
+61 −21
Original line number Diff line number Diff line
@@ -415,7 +415,7 @@ public class GLCanvasImpl implements GLCanvas {
    // This function changes the source coordinate to the texture coordinates.
    // It also clips the source and target coordinates if it is beyond the
    // bound of the texture.
    private void convertCoordinate(RectF source, RectF target,
    private static void convertCoordinate(RectF source, RectF target,
            BasicTexture texture) {

        int width = texture.getWidth();
@@ -465,23 +465,7 @@ public class GLCanvasImpl implements GLCanvas {
        color[3] = alpha;
    }

    private void drawMixed(BasicTexture from, int toColor,
            float ratio, int x, int y, int width, int height, float alpha) {
        // change from 0 to 0.01f to prevent getting divided by zero below
        if (ratio <= 0.01f) {
            drawTexture(from, x, y, width, height, alpha);
            return;
        } else if (ratio >= 1) {
            fillRect(x, y, width, height, toColor);
            return;
        }

        mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque()
                || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA));

        final GL11 gl = mGL;
        if (!bindTexture(from)) return;

    private void setMixedColor(int toColor, float ratio, float alpha) {
        //
        // The formula we want:
        //     alpha * ((1 - ratio) * from + ratio * to)
@@ -495,9 +479,6 @@ public class GLCanvasImpl implements GLCanvas {
        float combo = alpha * (1 - ratio);
        float scale = alpha * ratio / (1 - combo);

        // Interpolate the RGB and alpha values between both textures.
        mGLState.setTexEnvMode(GL11.GL_COMBINE);

        // Specify the interpolation factor via the alpha component of
        // GL_TEXTURE_ENV_COLORs.
        // RGB component are get from toColor and will used as SRC1
@@ -505,6 +486,7 @@ public class GLCanvasImpl implements GLCanvas {
        setTextureColor(((toColor >>> 16) & 0xff) * colorScale,
                ((toColor >>> 8) & 0xff) * colorScale,
                (toColor & 0xff) * colorScale, combo);
        GL11 gl = mGL;
        gl.glTexEnvfv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, mTextureColor, 0);

        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_RGB, GL11.GL_INTERPOLATE);
@@ -522,6 +504,64 @@ public class GLCanvasImpl implements GLCanvas {
        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_ALPHA, GL11.GL_CONSTANT);
        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_ALPHA, GL11.GL_SRC_ALPHA);

    }

    @Override
    public void drawMixed(BasicTexture from, int toColor, float ratio,
            RectF source, RectF target) {
        if (target.width() <= 0 || target.height() <= 0) return;

        if (ratio <= 0.01f) {
            drawTexture(from, source, target);
            return;
        } else if (ratio >= 1) {
            fillRect(target.left, target.top, target.width(), target.height(), toColor);
            return;
        }

        float alpha = mAlpha;

        // Copy the input to avoid changing it.
        mDrawTextureSourceRect.set(source);
        mDrawTextureTargetRect.set(target);
        source = mDrawTextureSourceRect;
        target = mDrawTextureTargetRect;

        mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque()
                || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA));

        if (!bindTexture(from)) return;

        // Interpolate the RGB and alpha values between both textures.
        mGLState.setTexEnvMode(GL11.GL_COMBINE);
        setMixedColor(toColor, ratio, alpha);
        convertCoordinate(source, target, from);
        setTextureCoords(source);
        textureRect(target.left, target.top, target.width(), target.height());
        mGLState.setTexEnvMode(GL11.GL_REPLACE);
    }

    private void drawMixed(BasicTexture from, int toColor,
            float ratio, int x, int y, int width, int height, float alpha) {
        // change from 0 to 0.01f to prevent getting divided by zero below
        if (ratio <= 0.01f) {
            drawTexture(from, x, y, width, height, alpha);
            return;
        } else if (ratio >= 1) {
            fillRect(x, y, width, height, toColor);
            return;
        }

        mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque()
                || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA));

        final GL11 gl = mGL;
        if (!bindTexture(from)) return;

        // Interpolate the RGB and alpha values between both textures.
        mGLState.setTexEnvMode(GL11.GL_COMBINE);
        setMixedColor(toColor, ratio, alpha);

        drawBoundTexture(from, x, y, width, height);
        mGLState.setTexEnvMode(GL11.GL_REPLACE);
    }
Loading