summaryrefslogtreecommitdiff
path: root/core/java/android/view/HardwareLayer.java
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2014-02-05 16:38:25 -0800
committerJohn Reck <jreck@google.com>2014-02-10 20:55:39 -0800
commit04fc583c3dd3144bc6b718fcac4b3e1afdfdb067 (patch)
tree4682660942c57456293a88bd3e78a28569ae9c71 /core/java/android/view/HardwareLayer.java
parent740dfefcfcba7a254e65bda3ac0d965ca161458b (diff)
Refactor HardwareLayer
Defer all the things! Groundwork to allow hardware layers to work in a renderthread world Change-Id: Ib3aa47525f393083621254a743dbaa6352f933bd
Diffstat (limited to 'core/java/android/view/HardwareLayer.java')
-rw-r--r--core/java/android/view/HardwareLayer.java328
1 files changed, 196 insertions, 132 deletions
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 23383d9c0473..9bbcf7ce5963 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -17,10 +17,10 @@
package android.view;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
/**
* A hardware layer can be used to render graphics operations into a hardware
@@ -28,38 +28,35 @@ import android.graphics.Rect;
* would use a Frame Buffer Object (FBO.) The hardware layer can be used as
* a drawing cache when a complex set of graphics operations needs to be
* drawn several times.
+ *
+ * @hide
*/
-abstract class HardwareLayer {
- /**
- * Indicates an unknown dimension (width or height.)
- */
- static final int DIMENSION_UNDEFINED = -1;
-
- int mWidth;
- int mHeight;
- DisplayList mDisplayList;
+final class HardwareLayer {
+ private static final int LAYER_TYPE_TEXTURE = 1;
+ private static final int LAYER_TYPE_RENDER = 2;
- boolean mOpaque;
+ private HardwareRenderer mRenderer;
+ private Finalizer mFinalizer;
+ private DisplayList mDisplayList;
+ private final int mLayerType;
- /**
- * Creates a new hardware layer with undefined dimensions.
- */
- HardwareLayer() {
- this(DIMENSION_UNDEFINED, DIMENSION_UNDEFINED, false);
+ private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
+ if (renderer == null || deferredUpdater == 0) {
+ throw new IllegalArgumentException("Either hardware renderer: " + renderer
+ + " or deferredUpdater: " + deferredUpdater + " is invalid");
+ }
+ mRenderer = renderer;
+ mLayerType = type;
+ mFinalizer = new Finalizer(deferredUpdater);
+
+ // Layer is considered initialized at this point, notify the HardwareRenderer
+ mRenderer.onLayerCreated(this);
}
- /**
- * Creates a new hardware layer at least as large as the supplied
- * dimensions.
- *
- * @param width The minimum width of the layer
- * @param height The minimum height of the layer
- * @param isOpaque Whether the layer should be opaque or not
- */
- HardwareLayer(int width, int height, boolean isOpaque) {
- mWidth = width;
- mHeight = height;
- mOpaque = isOpaque;
+ private void assertType(int type) {
+ if (mLayerType != type) {
+ throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
+ }
}
/**
@@ -68,158 +65,225 @@ abstract class HardwareLayer {
* @param paint The paint used when the layer is drawn into the destination canvas.
* @see View#setLayerPaint(android.graphics.Paint)
*/
- void setLayerPaint(Paint paint) { }
+ public void setLayerPaint(Paint paint) {
+ nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint,
+ paint.getColorFilter() != null ? paint.getColorFilter().native_instance : 0);
+ }
/**
- * Returns the minimum width of the layer.
- *
- * @return The minimum desired width of the hardware layer
+ * Indicates whether this layer can be rendered.
+ *
+ * @return True if the layer can be rendered into, false otherwise
*/
- int getWidth() {
- return mWidth;
+ public boolean isValid() {
+ return mFinalizer != null && mFinalizer.mDeferredUpdater != 0;
}
/**
- * Returns the minimum height of the layer.
- *
- * @return The minimum desired height of the hardware layer
+ * Destroys resources without waiting for a GC.
*/
- int getHeight() {
- return mHeight;
+ public void destroy() {
+ if (!isValid()) {
+ // Already destroyed
+ return;
+ }
+
+ if (mDisplayList != null) {
+ mDisplayList.reset();
+ mDisplayList = null;
+ }
+ if (mRenderer != null) {
+ mRenderer.onLayerDestroyed(this);
+ mRenderer = null;
+ }
+ doDestroyLayerUpdater();
}
/**
- * Returns the DisplayList for the layer.
+ * Destroys the deferred layer updater but not the backing layer. The
+ * backing layer is instead returned and is the caller's responsibility
+ * to destroy/recycle as appropriate.
*
- * @return The DisplayList of the hardware layer
+ * It is safe to call this in onLayerDestroyed only
*/
- DisplayList getDisplayList() {
+ public long detachBackingLayer() {
+ long backingLayer = nDetachBackingLayer(mFinalizer.mDeferredUpdater);
+ doDestroyLayerUpdater();
+ return backingLayer;
+ }
+
+ private void doDestroyLayerUpdater() {
+ if (mFinalizer != null) {
+ mFinalizer.destroy();
+ mFinalizer = null;
+ }
+ }
+
+ public DisplayList startRecording() {
+ assertType(LAYER_TYPE_RENDER);
+
+ if (mDisplayList == null) {
+ mDisplayList = DisplayList.create("HardwareLayer");
+ }
return mDisplayList;
}
+ public void endRecording(Rect dirtyRect) {
+ nUpdateRenderLayer(mFinalizer.mDeferredUpdater, mDisplayList.getNativeDisplayList(),
+ dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
+ mRenderer.pushLayerUpdate(this);
+ }
+
/**
- * Sets the DisplayList for the layer.
+ * Copies this layer into the specified bitmap.
*
- * @param displayList The new DisplayList for this layer
+ * @param bitmap The bitmap to copy they layer into
+ *
+ * @return True if the copy was successful, false otherwise
*/
- void setDisplayList(DisplayList displayList) {
- mDisplayList = displayList;
+ public boolean copyInto(Bitmap bitmap) {
+ return mRenderer.copyLayerInto(this, bitmap);
}
/**
- * Returns whether or not this layer is opaque.
- *
- * @return True if the layer is opaque, false otherwise
+ * Update the layer's properties. Note that after calling this isValid() may
+ * return false if the requested width/height cannot be satisfied
+ *
+ * @param width The new width of this layer
+ * @param height The new height of this layer
+ * @param isOpaque Whether this layer is opaque
+ *
+ * @return true if the layer's properties will change, false if they already
+ * match the desired values.
*/
- boolean isOpaque() {
- return mOpaque;
+ public boolean prepare(int width, int height, boolean isOpaque) {
+ return nPrepare(mFinalizer.mDeferredUpdater, width, height, isOpaque);
}
/**
- * Sets whether or not this layer should be considered opaque.
- *
- * @param isOpaque True if the layer is opaque, false otherwise
+ * Sets an optional transform on this layer.
+ *
+ * @param matrix The transform to apply to the layer.
*/
- abstract void setOpaque(boolean isOpaque);
+ public void setTransform(Matrix matrix) {
+ nSetTransform(mFinalizer.mDeferredUpdater, matrix.native_instance);
+ }
/**
- * Indicates whether this layer can be rendered.
- *
- * @return True if the layer can be rendered into, false otherwise
+ * Indicates that this layer has lost its texture.
*/
- abstract boolean isValid();
+ public void onTextureDestroyed() {
+ assertType(LAYER_TYPE_TEXTURE);
+ nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+ }
/**
- * Resize the layer, if necessary, to be at least as large
- * as the supplied dimensions.
- *
- * @param width The new desired minimum width for this layer
- * @param height The new desired minimum height for this layer
- * @return True if the resulting layer is valid, false otherwise
+ * This exists to minimize impact into the current HardwareLayer paths as
+ * some of the specifics of how to handle error cases in the fully
+ * deferred model will work
*/
- abstract boolean resize(int width, int height);
+ @Deprecated
+ public void flushChanges() {
+ if (HardwareRenderer.sUseRenderThread) {
+ // Not supported, don't try.
+ return;
+ }
- /**
- * Returns a hardware canvas that can be used to render onto
- * this layer.
- *
- * @return A hardware canvas, or null if a canvas cannot be created
- *
- * @see #start(android.graphics.Canvas)
- * @see #end(android.graphics.Canvas)
- */
- abstract HardwareCanvas getCanvas();
+ boolean success = nFlushChanges(mFinalizer.mDeferredUpdater);
+ if (!success) {
+ destroy();
+ }
+ }
- /**
- * Destroys resources without waiting for a GC.
- */
- abstract void destroy();
+ public long getLayer() {
+ return nGetLayer(mFinalizer.mDeferredUpdater);
+ }
- /**
- * This must be invoked before drawing onto this layer.
- *
- * @param currentCanvas The canvas whose rendering needs to be interrupted
- */
- abstract HardwareCanvas start(Canvas currentCanvas);
+ public void setSurfaceTexture(SurfaceTexture surface) {
+ assertType(LAYER_TYPE_TEXTURE);
+ nSetSurfaceTexture(mFinalizer.mDeferredUpdater, surface, false);
+ }
- /**
- * This must be invoked before drawing onto this layer.
- *
- * @param dirty The dirty area to repaint
- * @param currentCanvas The canvas whose rendering needs to be interrupted
- */
- abstract HardwareCanvas start(Canvas currentCanvas, Rect dirty);
+ public void updateSurfaceTexture() {
+ assertType(LAYER_TYPE_TEXTURE);
+ nUpdateSurfaceTexture(mFinalizer.mDeferredUpdater);
+ }
/**
- * This must be invoked after drawing onto this layer.
- *
- * @param currentCanvas The canvas whose rendering needs to be resumed
+ * This should only be used by HardwareRenderer! Do not call directly
*/
- abstract void end(Canvas currentCanvas);
+ SurfaceTexture createSurfaceTexture() {
+ assertType(LAYER_TYPE_TEXTURE);
+ SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.mDeferredUpdater));
+ nSetSurfaceTexture(mFinalizer.mDeferredUpdater, st, true);
+ return st;
+ }
/**
- * Copies this layer into the specified bitmap.
- *
- * @param bitmap The bitmap to copy they layer into
- *
- * @return True if the copy was successful, false otherwise
+ * This should only be used by HardwareRenderer! Do not call directly
*/
- abstract boolean copyInto(Bitmap bitmap);
+ static HardwareLayer createTextureLayer(HardwareRenderer renderer) {
+ return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
+ }
/**
- * Update the layer's properties. This method should be used
- * when the underlying storage is modified by an external entity.
- * To change the underlying storage, use the {@link #resize(int, int)}
- * method instead.
- *
- * @param width The new width of this layer
- * @param height The new height of this layer
- * @param isOpaque Whether this layer is opaque
+ * This should only be used by HardwareRenderer! Do not call directly
*/
- void update(int width, int height, boolean isOpaque) {
- mWidth = width;
- mHeight = height;
- mOpaque = isOpaque;
+ static HardwareLayer createRenderLayer(HardwareRenderer renderer,
+ int width, int height) {
+ return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
}
- /**
- * Sets an optional transform on this layer.
- *
- * @param matrix The transform to apply to the layer.
- */
- abstract void setTransform(Matrix matrix);
+ /** This also creates the underlying layer */
+ private static native long nCreateTextureLayer();
+ private static native long nCreateRenderLayer(int width, int height);
- /**
- * Specifies the display list to use to refresh the layer.
- *
- * @param displayList The display list containing the drawing commands to
- * execute in this layer
- * @param dirtyRect The dirty region of the layer that needs to be redrawn
- */
- abstract void redrawLater(DisplayList displayList, Rect dirtyRect);
+ private static native void nOnTextureDestroyed(long layerUpdater);
+ private static native long nDetachBackingLayer(long layerUpdater);
- /**
- * Indicates that this layer has lost its underlying storage.
+ /** This also destroys the underlying layer if it is still attached.
+ * Note it does not recycle the underlying layer, but instead queues it
+ * for deferred deletion.
+ * The HardwareRenderer should use detachBackingLayer() in the
+ * onLayerDestroyed() callback to do recycling if desired.
*/
- abstract void clearStorage();
+ private static native void nDestroyLayerUpdater(long layerUpdater);
+
+ private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
+ private static native void nSetLayerPaint(long layerUpdater, long paint, long colorFilter);
+ private static native void nSetTransform(long layerUpdater, long matrix);
+ private static native void nSetSurfaceTexture(long layerUpdater,
+ SurfaceTexture surface, boolean isAlreadyAttached);
+ private static native void nUpdateSurfaceTexture(long layerUpdater);
+ private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
+ int left, int top, int right, int bottom);
+
+ private static native boolean nFlushChanges(long layerUpdater);
+
+ private static native long nGetLayer(long layerUpdater);
+ private static native int nGetTexName(long layerUpdater);
+
+ private static class Finalizer {
+ private long mDeferredUpdater;
+
+ public Finalizer(long deferredUpdater) {
+ mDeferredUpdater = deferredUpdater;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ void destroy() {
+ if (mDeferredUpdater != 0) {
+ nDestroyLayerUpdater(mDeferredUpdater);
+ mDeferredUpdater = 0;
+ }
+ }
+ }
}