diff options
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 34 | ||||
-rw-r--r-- | core/java/android/view/GLES20Layer.java | 100 | ||||
-rw-r--r-- | core/java/android/view/GLES20RenderLayer.java | 130 | ||||
-rw-r--r-- | core/java/android/view/GLES20TextureLayer.java | 108 | ||||
-rw-r--r-- | core/java/android/view/GLRenderer.java | 51 | ||||
-rw-r--r-- | core/java/android/view/HardwareLayer.java | 328 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 34 | ||||
-rw-r--r-- | core/java/android/view/TextureView.java | 9 | ||||
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 14 | ||||
-rw-r--r-- | core/java/android/view/View.java | 56 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 6 |
11 files changed, 281 insertions, 589 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index b763888..2ed0cba 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -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; @@ -87,15 +86,6 @@ class GLES20Canvas extends HardwareCanvas { GLES20Canvas(boolean translucent) { 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); diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java deleted file mode 100644 index 1d30824..0000000 --- a/core/java/android/view/GLES20Layer.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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; - } - } -} diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java deleted file mode 100644 index 8c97867..0000000 --- a/core/java/android/view/GLES20RenderLayer.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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); - } -} diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java deleted file mode 100644 index bb5a6eb..0000000 --- a/core/java/android/view/GLES20TextureLayer.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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) { - } -} diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index 5002fe5..40ad72c 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -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; diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index 23383d9..9bbcf7c 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; + } + } + } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 352ab83..93cc9d1 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -16,6 +16,7 @@ package android.view; +import android.graphics.Bitmap; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.SurfaceTexture; @@ -344,19 +345,20 @@ public abstract class HardwareRenderer { * @param layer The hardware layer that needs an update * * @see #flushLayerUpdates() - * @see #cancelLayerUpdate(HardwareLayer) */ abstract void pushLayerUpdate(HardwareLayer layer); /** - * Cancels a queued layer update. If the specified layer was not - * queued for update, this method has no effect. - * - * @param layer The layer whose update to cancel - * - * @see #pushLayerUpdate(HardwareLayer) + * Tells the HardwareRenderer that a layer was created. The renderer should + * make sure to apply any pending layer changes at the start of a new frame + */ + abstract void onLayerCreated(HardwareLayer hardwareLayer); + + /** + * Tells the HardwareRenderer that the layer is destroyed. The renderer + * should remove the layer from any update queues. */ - abstract void cancelLayerUpdate(HardwareLayer layer); + abstract void onLayerDestroyed(HardwareLayer layer); /** * Forces all enqueued layer updates to be executed immediately. @@ -403,22 +405,19 @@ public abstract class HardwareRenderer { * Creates a new hardware layer. A hardware layer built by calling this * method will be treated as a texture layer, instead of as a render target. * - * @param isOpaque Whether the layer should be opaque or not - * * @return A hardware layer */ - abstract HardwareLayer createHardwareLayer(boolean isOpaque); + abstract HardwareLayer createTextureLayer(); /** * Creates a new hardware layer. * * @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 * * @return A hardware layer */ - abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque); + abstract HardwareLayer createDisplayListLayer(int width, int height); /** * Creates a new {@link SurfaceTexture} that can be used to render into the @@ -430,14 +429,7 @@ public abstract class HardwareRenderer { */ abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer); - /** - * Sets the {@link android.graphics.SurfaceTexture} that will be used to - * render into the specified hardware layer. - * - * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture} - * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer - */ - abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture); + abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap); /** * Detaches the specified functor from the current functor execution queue. diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 161fe33..e789407 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -250,7 +250,7 @@ public class TextureView extends View { mSurface.detachFromGLContext(); // SurfaceTexture owns the texture name and detachFromGLContext // should have deleted it - mLayer.clearStorage(); + mLayer.onTextureDestroyed(); boolean shouldRelease = true; if (mListener != null) { @@ -375,7 +375,7 @@ public class TextureView extends View { return null; } - mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque); + mLayer = mAttachInfo.mHardwareRenderer.createTextureLayer(); if (!mUpdateSurface) { // Create a new SurfaceTexture for the layer. mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer); @@ -416,7 +416,7 @@ public class TextureView extends View { updateLayer(); mMatrixChanged = true; - mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface); + mLayer.setSurfaceTexture(mSurface); mSurface.setDefaultBufferSize(getWidth(), getHeight()); } @@ -469,7 +469,8 @@ public class TextureView extends View { } } - mLayer.update(getWidth(), getHeight(), mOpaque); + mLayer.prepare(getWidth(), getHeight(), mOpaque); + mLayer.updateSurfaceTexture(); if (mListener != null) { mListener.onSurfaceTextureUpdated(mSurface); diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 2c9f1d9..1c20923 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -16,6 +16,7 @@ package android.view; +import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.os.SystemClock; @@ -155,7 +156,12 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override - void cancelLayerUpdate(HardwareLayer layer) { + void onLayerCreated(HardwareLayer layer) { + throw new NoSuchMethodError(); + } + + @Override + void onLayerDestroyed(HardwareLayer layer) { throw new NoSuchMethodError(); } @@ -197,12 +203,12 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override - HardwareLayer createHardwareLayer(boolean isOpaque) { + HardwareLayer createTextureLayer() { throw new NoSuchMethodError(); } @Override - HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) { + HardwareLayer createDisplayListLayer(int width, int height) { throw new NoSuchMethodError(); } @@ -212,7 +218,7 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override - void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) { + boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) { throw new NoSuchMethodError(); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index fbeddc8..393b166 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -87,7 +87,6 @@ import static java.lang.Math.max; import com.android.internal.R; import com.android.internal.util.Predicate; import com.android.internal.view.menu.MenuBuilder; - import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -13629,16 +13628,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) { if (mHardwareLayer == null) { - mHardwareLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer( - width, height, isOpaque()); + mHardwareLayer = mAttachInfo.mHardwareRenderer.createDisplayListLayer( + width, height); mLocalDirtyRect.set(0, 0, width, height); - } else { - if (mHardwareLayer.getWidth() != width || mHardwareLayer.getHeight() != height) { - if (mHardwareLayer.resize(width, height)) { - mLocalDirtyRect.set(0, 0, width, height); - } - } - + } else if (mHardwareLayer.isValid()) { // This should not be necessary but applications that change // the parameters of their background drawable without calling // this.setBackground(Drawable) can leave the view in a bad state @@ -13646,23 +13639,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // not opaque.) computeOpaqueFlags(); - final boolean opaque = isOpaque(); - if (mHardwareLayer.isValid() && mHardwareLayer.isOpaque() != opaque) { - mHardwareLayer.setOpaque(opaque); + if (mHardwareLayer.prepare(width, height, isOpaque())) { mLocalDirtyRect.set(0, 0, width, height); } } // The layer is not valid if the underlying GPU resources cannot be allocated + mHardwareLayer.flushChanges(); if (!mHardwareLayer.isValid()) { return null; } mHardwareLayer.setLayerPaint(mLayerPaint); - mHardwareLayer.redrawLater(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect); - ViewRootImpl viewRoot = getViewRootImpl(); - if (viewRoot != null) viewRoot.pushHardwareLayerUpdate(mHardwareLayer); - + DisplayList displayList = mHardwareLayer.startRecording(); + if (getDisplayList(displayList, true) != displayList) { + throw new IllegalStateException("getDisplayList() didn't return" + + " the input displaylist for a hardware layer!"); + } + mHardwareLayer.endRecording(mLocalDirtyRect); mLocalDirtyRect.setEmpty(); } @@ -13679,18 +13673,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ boolean destroyLayer(boolean valid) { if (mHardwareLayer != null) { - AttachInfo info = mAttachInfo; - if (info != null && info.mHardwareRenderer != null && - info.mHardwareRenderer.isEnabled() && - (valid || info.mHardwareRenderer.validate())) { - - info.mHardwareRenderer.cancelLayerUpdate(mHardwareLayer); - mHardwareLayer.destroy(); - mHardwareLayer = null; + mHardwareLayer.destroy(); + mHardwareLayer = null; - invalidate(true); - invalidateParentCaches(); - } + invalidate(true); + invalidateParentCaches(); return true; } return false; @@ -13911,19 +13898,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Get the DisplayList for the HardwareLayer - * - * @param layer The HardwareLayer whose DisplayList we want - * @return A DisplayList fopr the specified HardwareLayer - */ - private DisplayList getHardwareLayerDisplayList(HardwareLayer layer) { - DisplayList displayList = getDisplayList(layer.getDisplayList(), true); - layer.setDisplayList(displayList); - return displayList; - } - - - /** * <p>Returns a display list that can be used to draw this view again * without executing its draw method.</p> * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index ccb85a6..ef69948 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -642,12 +642,6 @@ public final class ViewRootImpl implements ViewParent, } } - void pushHardwareLayerUpdate(HardwareLayer layer) { - if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { - mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer); - } - } - void flushHardwareLayerUpdates() { if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() && mAttachInfo.mHardwareRenderer.validate()) { |