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

Commit 08695111 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Decouple GLES20RecordingCanvas lifetime from GLES20DisplayList. Bug: 5062011"

parents 45db96d0 162a0217
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -40,15 +40,6 @@ public abstract class DisplayList {
     */
    abstract void end();

    /**
     * Indicates whether this display list can be replayed or not.
     * 
     * @return True if the display list can be replayed, false otherwise.
     * 
     * @see android.view.HardwareCanvas#drawDisplayList(DisplayList) 
     */
    abstract boolean isReady();

    /**
     * Invalidates the display list, indicating that it should be repopulated
     * with new drawing commands prior to being used again. Calling this method
+18 −33
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ class GLES20Canvas extends HardwareCanvas {

    // The native renderer will be destroyed when this object dies.
    // DO NOT overwrite this reference once it is set.
    @SuppressWarnings("unused")
    private CanvasFinalizer mFinalizer;

    private int mWidth;
@@ -97,12 +98,8 @@ class GLES20Canvas extends HardwareCanvas {
    protected GLES20Canvas(boolean record, boolean translucent) {
        mOpaque = !translucent;

        setupRenderer(record);
    }

    protected void setupRenderer(boolean record) {
        if (record) {
            mRenderer = nGetDisplayListRenderer(mRenderer);
            mRenderer = nCreateDisplayListRenderer();
        } else {
            mRenderer = nCreateRenderer();
        }
@@ -114,43 +111,31 @@ class GLES20Canvas extends HardwareCanvas {
        if (mRenderer == 0) {
            throw new IllegalStateException("Could not create GLES20Canvas renderer");
        } else {
            mFinalizer = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer);
            mFinalizer = new CanvasFinalizer(mRenderer);
        }
    }

    protected void resetDisplayListRenderer() {
        nResetDisplayListRenderer(mRenderer);
    }

    private static native int nCreateRenderer();
    private static native int nCreateLayerRenderer(int layer);
    private static native int nGetDisplayListRenderer(int renderer);
    private static native int nCreateDisplayListRenderer();
    private static native void nResetDisplayListRenderer(int renderer);
    private static native void nDestroyRenderer(int renderer);

    private static class CanvasFinalizer {
        int mRenderer;

        // Factory method returns new instance if old one is null, or old instance
        // otherwise, destroying native renderer along the way as necessary
        static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) {
            if (oldFinalizer == null) {
                return new CanvasFinalizer(renderer);
            }
            oldFinalizer.replaceNativeObject(renderer);
            return oldFinalizer;
        }
    private static final class CanvasFinalizer {
        private final int mRenderer;

        private CanvasFinalizer(int renderer) {
        public CanvasFinalizer(int renderer) {
            mRenderer = renderer;
        }

        private void replaceNativeObject(int newRenderer) {
            if (mRenderer != 0 && newRenderer != mRenderer) {
                nDestroyRenderer(mRenderer);
            }
            mRenderer = newRenderer;
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                replaceNativeObject(0);
                nDestroyRenderer(mRenderer);
            } finally {
                super.finalize();
            }
@@ -322,11 +307,11 @@ class GLES20Canvas extends HardwareCanvas {
    // Display list
    ///////////////////////////////////////////////////////////////////////////

    int getDisplayList() {
        return nGetDisplayList(mRenderer);
    int getDisplayList(int displayList) {
        return nGetDisplayList(mRenderer, displayList);
    }

    private static native int nGetDisplayList(int renderer);
    private static native int nGetDisplayList(int renderer, int displayList);
    
    static void destroyDisplayList(int displayList) {
        nDestroyDisplayList(displayList);
@@ -337,7 +322,7 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
        return nDrawDisplayList(mRenderer,
                ((GLES20DisplayList) displayList).mNativeDisplayList, width, height, dirty);
                ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
    }

    private static native boolean nDrawDisplayList(int renderer, int displayList,
@@ -345,7 +330,7 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    void outputDisplayList(DisplayList displayList) {
        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
    }

    private static native void nOutputDisplayList(int renderer, int displayList);
+32 −54
Original line number Diff line number Diff line
@@ -16,52 +16,50 @@

package android.view;

import java.lang.ref.WeakReference;
import android.graphics.Bitmap;

import java.util.ArrayList;

/**
 * An implementation of display list for OpenGL ES 2.0.
 */
class GLES20DisplayList extends DisplayList {
    private GLES20Canvas mCanvas;

    private boolean mStarted = false;
    private boolean mRecorded = false;
    private boolean mValid = false;
    // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long
    // as the DisplayList is alive.  The Bitmaps are populated by the GLES20RecordingCanvas.
    final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);

    int mNativeDisplayList;
    WeakReference<View> hostView;
    private GLES20RecordingCanvas mCanvas;
    private boolean mValid;

    // The native display list will be destroyed when this object dies.
    // DO NOT overwrite this reference once it is set.
    @SuppressWarnings("unused")
    private DisplayListFinalizer mFinalizer;

    public GLES20DisplayList(View view) {
        hostView = new WeakReference<View>(view);
    int getNativeDisplayList() {
        if (!mValid || mFinalizer == null) {
            throw new IllegalStateException("The display list is not valid.");
        }
        return mFinalizer.mNativeDisplayList;
    }

    @Override
    HardwareCanvas start() {
        if (mStarted) {
            throw new IllegalStateException("Recording has already started");
        }

        if (mCanvas != null) {
            ((GLES20RecordingCanvas) mCanvas).reset();
        } else {
            mCanvas = new GLES20RecordingCanvas(true);
            throw new IllegalStateException("Recording has already started");
        }
        mStarted = true;
        mRecorded = false;
        mValid = true;

        mValid = false;
        mCanvas = GLES20RecordingCanvas.obtain(this);
        mCanvas.start();
        return mCanvas;
    }

    @Override
    void invalidate() {
        mStarted = false;
        mRecorded = false;
        if (mCanvas != null) {
            mCanvas.recycle();
            mCanvas = null;
        }
        mValid = false;
    }

@@ -73,48 +71,28 @@ class GLES20DisplayList extends DisplayList {
    @Override
    void end() {
        if (mCanvas != null) {
            mStarted = false;
            mRecorded = true;

            mNativeDisplayList = mCanvas.getDisplayList();
            mFinalizer = DisplayListFinalizer.getFinalizer(mFinalizer, mNativeDisplayList);
            if (mFinalizer != null) {
                mCanvas.end(mFinalizer.mNativeDisplayList);
            } else {
                mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
            }
            mCanvas.recycle();
            mCanvas = null;
            mValid = true;
        }

    @Override
    boolean isReady() {
        return !mStarted && mRecorded;
    }

    private static class DisplayListFinalizer {
        int mNativeDisplayList;

        // Factory method returns new instance if old one is null, or old instance
        // otherwise, destroying native display list along the way as necessary
        static DisplayListFinalizer getFinalizer(DisplayListFinalizer oldFinalizer,
                int nativeDisplayList) {
            if (oldFinalizer == null) {
                return new DisplayListFinalizer(nativeDisplayList);
            }
            oldFinalizer.replaceNativeObject(nativeDisplayList);
            return oldFinalizer;
        }
        final int mNativeDisplayList;

        private DisplayListFinalizer(int nativeDisplayList) {
        public DisplayListFinalizer(int nativeDisplayList) {
            mNativeDisplayList = nativeDisplayList;
        }

        private void replaceNativeObject(int newNativeDisplayList) {
            if (mNativeDisplayList != 0 && mNativeDisplayList != newNativeDisplayList) {
                GLES20Canvas.destroyDisplayList(mNativeDisplayList);
            }
            mNativeDisplayList = newNativeDisplayList;
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                replaceNativeObject(0);
                GLES20Canvas.destroyDisplayList(mNativeDisplayList);
            } finally {
                super.finalize();
            }
+75 −21
Original line number Diff line number Diff line
@@ -24,8 +24,10 @@ import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;

import java.util.ArrayList;
import android.util.Pool;
import android.util.Poolable;
import android.util.PoolableManager;
import android.util.Pools;

/**
 * An implementation of a GL canvas that records drawing operations.
@@ -33,62 +35,94 @@ import java.util.ArrayList;
 * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
 * the DisplayList is still holding a native reference to the memory.
 */
class GLES20RecordingCanvas extends GLES20Canvas {
    // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long
    // as the DisplayList is alive.
    @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
    private final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);
class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> {
    // The recording canvas pool should be large enough to handle a deeply nested
    // view hierarchy because display lists are generated recursively.
    private static final int POOL_LIMIT = 50;

    private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool(
            Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() {
                public GLES20RecordingCanvas newInstance() {
                    return new GLES20RecordingCanvas();
                }
                @Override
                public void onAcquired(GLES20RecordingCanvas element) {
                }
                @Override
                public void onReleased(GLES20RecordingCanvas element) {
                }
            }, POOL_LIMIT));

    private GLES20RecordingCanvas mNextPoolable;
    private boolean mIsPooled;

    GLES20RecordingCanvas(boolean translucent) {
        super(true, translucent);
    private GLES20DisplayList mDisplayList;

    private GLES20RecordingCanvas() {
        super(true /*record*/, true /*translucent*/);
    }

    static GLES20RecordingCanvas obtain(GLES20DisplayList displayList) {
        GLES20RecordingCanvas canvas = sPool.acquire();
        canvas.mDisplayList = displayList;
        return canvas;
    }

    void recycle() {
        mDisplayList = null;
        resetDisplayListRenderer();
        sPool.release(this);
    }

    void start() {
        mDisplayList.mBitmaps.clear();
    }

    int end(int nativeDisplayList) {
        return getDisplayList(nativeDisplayList);
    }

    private void recordShaderBitmap(Paint paint) {
        if (paint != null) {
            final Shader shader = paint.getShader();
            if (shader instanceof BitmapShader) {
                mBitmaps.add(((BitmapShader) shader).mBitmap);
            }
                mDisplayList.mBitmaps.add(((BitmapShader) shader).mBitmap);
            }
        }

    void reset() {
        mBitmaps.clear();
        setupRenderer(true);
    }

    @Override
    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
        super.drawPatch(bitmap, chunks, dst, paint);
        mBitmaps.add(bitmap);
        mDisplayList.mBitmaps.add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
        super.drawBitmap(bitmap, left, top, paint);
        mBitmaps.add(bitmap);
        mDisplayList.mBitmaps.add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
        super.drawBitmap(bitmap, matrix, paint);
        mBitmaps.add(bitmap);
        mDisplayList.mBitmaps.add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
        super.drawBitmap(bitmap, src, dst, paint);
        mBitmaps.add(bitmap);
        mDisplayList.mBitmaps.add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
        super.drawBitmap(bitmap, src, dst, paint);
        mBitmaps.add(bitmap);
        mDisplayList.mBitmaps.add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

@@ -111,7 +145,7 @@ class GLES20RecordingCanvas extends GLES20Canvas {
            int vertOffset, int[] colors, int colorOffset, Paint paint) {
        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset,
                paint);
        mBitmaps.add(bitmap);
        mDisplayList.mBitmaps.add(bitmap);
        // Shaders in the Paint are ignored when drawing a Bitmap
    }

@@ -270,4 +304,24 @@ class GLES20RecordingCanvas extends GLES20Canvas {
                colorOffset, indices, indexOffset, indexCount, paint);
        recordShaderBitmap(paint);
    }

    @Override
    public GLES20RecordingCanvas getNextPoolable() {
        return mNextPoolable;
    }

    @Override
    public void setNextPoolable(GLES20RecordingCanvas element) {
        mNextPoolable = element;
    }

    @Override
    public boolean isPooled() {
        return mIsPooled;
    }

    @Override
    public void setPooled(boolean isPooled) {
        mIsPooled = isPooled;
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ public abstract class HardwareRenderer {
     * 
     * @return A new display list.
     */
    abstract DisplayList createDisplayList(View v);
    abstract DisplayList createDisplayList();

    /**
     * Creates a new hardware layer. A hardware layer built by calling this
@@ -852,8 +852,8 @@ public abstract class HardwareRenderer {
        }

        @Override
        DisplayList createDisplayList(View v) {
            return new GLES20DisplayList(v);
        DisplayList createDisplayList() {
            return new GLES20DisplayList();
        }

        @Override
Loading