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

Commit 04fc583c authored by John Reck's avatar John Reck
Browse files

Refactor HardwareLayer

 Defer all the things!
 Groundwork to allow hardware layers to work in a renderthread world

Change-Id: Ib3aa47525f393083621254a743dbaa6352f933bd
parent 740dfefc
Loading
Loading
Loading
Loading
+3 −31
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.SurfaceTexture;
import android.graphics.TemporaryBuffer;
import android.text.GraphicsOperations;
import android.text.SpannableString;
@@ -88,15 +87,6 @@ class GLES20Canvas extends HardwareCanvas {
        this(false, translucent);
    }
    
    /**
     * Creates a canvas to render into an FBO.
     */
    GLES20Canvas(long layer, boolean translucent) {
        mOpaque = !translucent;
        mRenderer = nCreateLayerRenderer(layer);
        setupFinalizer();
    }
    
    protected GLES20Canvas(boolean record, boolean translucent) {
        mOpaque = !translucent;

@@ -122,7 +112,6 @@ class GLES20Canvas extends HardwareCanvas {
    }

    private static native long nCreateRenderer();
    private static native long nCreateLayerRenderer(long layer);
    private static native long nCreateDisplayListRenderer();
    private static native void nResetDisplayListRenderer(long renderer);
    private static native void nDestroyRenderer(long renderer);
@@ -156,12 +145,12 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    void pushLayerUpdate(HardwareLayer layer) {
        nPushLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
        nPushLayerUpdate(mRenderer, layer.getLayer());
    }

    @Override
    void cancelLayerUpdate(HardwareLayer layer) {
        nCancelLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
        nCancelLayerUpdate(mRenderer, layer.getLayer());
    }

    @Override
@@ -174,22 +163,7 @@ class GLES20Canvas extends HardwareCanvas {
        nClearLayerUpdates(mRenderer);
    }

    static native long nCreateTextureLayer(boolean opaque, int[] layerInfo);
    static native long nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
    static native boolean nResizeLayer(long layerId, int width, int height, int[] layerInfo);
    static native void nSetOpaqueLayer(long layerId, boolean isOpaque);
    static native void nSetLayerPaint(long layerId, long nativePaint);
    static native void nSetLayerColorFilter(long layerId, long nativeColorFilter);
    static native void nUpdateTextureLayer(long layerId, int width, int height, boolean opaque,
            SurfaceTexture surface);
    static native void nClearLayerTexture(long layerId);
    static native void nSetTextureLayerTransform(long layerId, long matrix);
    static native void nDestroyLayer(long layerId);
    static native void nDestroyLayerDeferred(long layerId);
    static native void nUpdateRenderLayer(long layerId, long renderer, long displayList,
            int left, int top, int right, int bottom);
    static native boolean nCopyLayer(long layerId, long bitmap);

    private static native void nClearLayerUpdates(long renderer);
    private static native void nFlushLayerUpdates(long renderer);
    private static native void nPushLayerUpdate(long renderer, long layer);
@@ -408,9 +382,7 @@ class GLES20Canvas extends HardwareCanvas {
    
    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
        layer.setLayerPaint(paint);

        final GLES20Layer glLayer = (GLES20Layer) layer;
        nDrawLayer(mRenderer, glLayer.getLayer(), x, y);
        nDrawLayer(mRenderer, layer.getLayer(), x, y);
    }

    private static native void nDrawLayer(long renderer, long layer, float x, float y);
+0 −100
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package android.view;

import android.graphics.Bitmap;
import android.graphics.Paint;

/**
 * An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
 */
abstract class GLES20Layer extends HardwareLayer {
    long mLayer;
    Finalizer mFinalizer;

    GLES20Layer() {
    }

    GLES20Layer(int width, int height, boolean opaque) {
        super(width, height, opaque);
    }

    /**
     * Returns the native layer object used to render this layer.
     * 
     * @return A pointer to the native layer object, or 0 if the object is NULL
     */
    public long getLayer() {
        return mLayer;
    }

    @Override
    void setLayerPaint(Paint paint) {
        if (paint != null) {
            GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint);
            GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ?
                    paint.getColorFilter().native_instance : 0);
        }
    }

    @Override
    public boolean copyInto(Bitmap bitmap) {
        return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
    }

    @Override
    public void destroy() {
        if (mDisplayList != null) {
            mDisplayList.reset();
        }
        if (mFinalizer != null) {
            mFinalizer.destroy();
            mFinalizer = null;
        }
        mLayer = 0;
    }

    @Override
    void clearStorage() {
        if (mLayer != 0) GLES20Canvas.nClearLayerTexture(mLayer);
    }

    static class Finalizer {
        private long mLayerId;

        public Finalizer(long layerId) {
            mLayerId = layerId;
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                if (mLayerId != 0) {
                    GLES20Canvas.nDestroyLayerDeferred(mLayerId);
                }
            } finally {
                super.finalize();
            }
        }

        void destroy() {
            GLES20Canvas.nDestroyLayer(mLayerId);
            mLayerId = 0;
        }
    }
}
+0 −130
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;

/**
 * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
 * implementation can be used a rendering target. It generates a
 * {@link Canvas} that can be used to render into an FBO using OpenGL.
 */
class GLES20RenderLayer extends GLES20Layer {
    private int mLayerWidth;
    private int mLayerHeight;

    private final GLES20Canvas mCanvas;

    GLES20RenderLayer(int width, int height, boolean isOpaque) {
        super(width, height, isOpaque);

        int[] layerInfo = new int[2];
        mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
        if (mLayer != 0) {
            mLayerWidth = layerInfo[0];
            mLayerHeight = layerInfo[1];

            mCanvas = new GLES20Canvas(mLayer, !isOpaque);
            mFinalizer = new Finalizer(mLayer);
        } else {
            mCanvas = null;
            mFinalizer = null;
        }
    }

    @Override
    boolean isValid() {
        return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
    }

    @Override
    boolean resize(int width, int height) {
        if (!isValid() || width <= 0 || height <= 0) return false;

        mWidth = width;
        mHeight = height;
        
        if (width != mLayerWidth || height != mLayerHeight) {
            int[] layerInfo = new int[2];

            if (GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo)) {
                mLayerWidth = layerInfo[0];
                mLayerHeight = layerInfo[1];
            } else {
                // Failure: not enough GPU resources for requested size
                mLayer = 0;
                mLayerWidth = 0;
                mLayerHeight = 0;
            }
        }
        return isValid();
    }

    @Override
    void setOpaque(boolean isOpaque) {
        mOpaque = isOpaque;
        GLES20Canvas.nSetOpaqueLayer(mLayer, isOpaque);
    }

    @Override
    HardwareCanvas getCanvas() {
        return mCanvas;
    }

    @Override
    void end(Canvas currentCanvas) {
        HardwareCanvas canvas = getCanvas();
        if (canvas != null) {
            canvas.onPostDraw();
        }
        if (currentCanvas instanceof GLES20Canvas) {
            ((GLES20Canvas) currentCanvas).resume();
        }
    }

    @Override
    HardwareCanvas start(Canvas currentCanvas) {
        return start(currentCanvas, null);
    }

    @Override
    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
        if (currentCanvas instanceof GLES20Canvas) {
            ((GLES20Canvas) currentCanvas).interrupt();
        }
        HardwareCanvas canvas = getCanvas();
        canvas.setViewport(mWidth, mHeight);
        canvas.onPreDraw(dirty);
        return canvas;
    }

    /**
     * Ignored
     */
    @Override
    void setTransform(Matrix matrix) {
    }

    @Override
    void redrawLater(DisplayList displayList, Rect dirtyRect) {
        GLES20Canvas.nUpdateRenderLayer(mLayer, mCanvas.getRenderer(),
                displayList.getNativeDisplayList(),
                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
    }
}
+0 −108
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;

/**
 * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
 * implementation can be used as a texture. Rendering into this
 * layer is not controlled by a {@link HardwareCanvas}.
 */
class GLES20TextureLayer extends GLES20Layer {
    private int mTexture;
    private SurfaceTexture mSurface;

    GLES20TextureLayer(boolean isOpaque) {
        int[] layerInfo = new int[2];
        mLayer = GLES20Canvas.nCreateTextureLayer(isOpaque, layerInfo);

        if (mLayer != 0) {
            mTexture = layerInfo[0];
            mFinalizer = new Finalizer(mLayer);
        } else {
            mFinalizer = null;
        }
    }

    @Override
    boolean isValid() {
        return mLayer != 0 && mTexture != 0;
    }

    @Override
    boolean resize(int width, int height) {
        return isValid();
    }

    @Override
    HardwareCanvas getCanvas() {
        return null;
    }

    @Override
    HardwareCanvas start(Canvas currentCanvas) {
        return null;
    }

    @Override
    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
        return null;
    }

    @Override
    void end(Canvas currentCanvas) {
    }

    SurfaceTexture getSurfaceTexture() {
        if (mSurface == null) {
            mSurface = new SurfaceTexture(mTexture);
        }
        return mSurface;
    }

    void setSurfaceTexture(SurfaceTexture surfaceTexture) {
        if (mSurface != null) {
            mSurface.release();
        }
        mSurface = surfaceTexture;
        mSurface.attachToGLContext(mTexture);
    }

    @Override
    void update(int width, int height, boolean isOpaque) {
        super.update(width, height, isOpaque);
        GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, isOpaque, mSurface);
    }

    @Override
    void setOpaque(boolean isOpaque) {
        throw new UnsupportedOperationException("Use update(int, int, boolean) instead");
    }

    @Override
    void setTransform(Matrix matrix) {
        GLES20Canvas.nSetTextureLayerTransform(mLayer, matrix.native_instance);
    }

    @Override
    void redrawLater(DisplayList displayList, Rect dirtyRect) {
    }
}
+39 −12
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ import static javax.microedition.khronos.egl.EGL10.EGL_WIDTH;
import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT;

import android.content.ComponentCallbacks2;
import android.graphics.Color;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
@@ -62,6 +62,8 @@ import android.view.Surface.OutOfResourcesException;
import com.google.android.gles_jni.EGLImpl;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import javax.microedition.khronos.egl.EGL10;
@@ -177,6 +179,8 @@ public class GLRenderer extends HardwareRenderer {
    private static EGLSurface sPbuffer;
    private static final Object[] sPbufferLock = new Object[0];

    private List<HardwareLayer> mAttachedLayers = new ArrayList<HardwareLayer>();

    private static class GLRendererEglContext extends ManagedEGLContext {
        final Handler mHandler = new Handler();

@@ -472,33 +476,40 @@ public class GLRenderer extends HardwareRenderer {
    }

    @Override
    void cancelLayerUpdate(HardwareLayer layer) {
        mGlCanvas.cancelLayerUpdate(layer);
    void flushLayerUpdates() {
        mGlCanvas.flushLayerUpdates();
    }

    @Override
    void flushLayerUpdates() {
        mGlCanvas.flushLayerUpdates();
    HardwareLayer createTextureLayer() {
        return HardwareLayer.createTextureLayer(this);
    }

    @Override
    HardwareLayer createHardwareLayer(boolean isOpaque) {
        return new GLES20TextureLayer(isOpaque);
    public HardwareLayer createDisplayListLayer(int width, int height) {
        return HardwareLayer.createRenderLayer(this, width, height);
    }

    @Override
    public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
        return new GLES20RenderLayer(width, height, isOpaque);
    void onLayerCreated(HardwareLayer hardwareLayer) {
        mAttachedLayers.add(hardwareLayer);
    }

    @Override
    void onLayerDestroyed(HardwareLayer layer) {
        mGlCanvas.cancelLayerUpdate(layer);
        mAttachedLayers.remove(layer);
    }

    @Override
    public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
        return ((GLES20TextureLayer) layer).getSurfaceTexture();
        return layer.createSurfaceTexture();
    }

    @Override
    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
        ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
        layer.flushChanges();
        return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
    }

    @Override
@@ -1127,6 +1138,8 @@ public class GLRenderer extends HardwareRenderer {

                DisplayList displayList = buildDisplayList(view, canvas);

                flushLayerChanges();

                // buildDisplayList() calls into user code which can cause
                // an eglMakeCurrent to happen with a different surface/context.
                // We must therefore check again here.
@@ -1180,6 +1193,20 @@ public class GLRenderer extends HardwareRenderer {
        }
    }

    private void flushLayerChanges() {
        // Loop through and apply any pending layer changes
        for (int i = 0; i < mAttachedLayers.size(); i++) {
            HardwareLayer layer = mAttachedLayers.get(i);
            layer.flushChanges();
            if (!layer.isValid()) {
                // The layer was removed from mAttachedLayers, rewind i by 1
                // Note that this shouldn't actually happen as View.getHardwareLayer()
                // is already flushing for error checking reasons
                i--;
            }
        }
    }

    private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
        if (mDrawDelta <= 0) {
            return view.mDisplayList;
Loading