diff options
| author | John Reck <jreck@google.com> | 2014-02-05 16:38:25 -0800 |
|---|---|---|
| committer | John Reck <jreck@google.com> | 2014-02-10 20:55:39 -0800 |
| commit | 04fc583c3dd3144bc6b718fcac4b3e1afdfdb067 (patch) | |
| tree | 4682660942c57456293a88bd3e78a28569ae9c71 /core/java/android/view/HardwareLayer.java | |
| parent | 740dfefcfcba7a254e65bda3ac0d965ca161458b (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.java | 328 |
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; + } + } + } } |
