Refactor HardwareLayer
Defer all the things! Groundwork to allow hardware layers to work in a renderthread world Change-Id: Ib3aa47525f393083621254a743dbaa6352f933bd
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -471,34 +475,41 @@ public class GLRenderer extends HardwareRenderer {
|
||||
mGlCanvas.pushLayerUpdate(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
void cancelLayerUpdate(HardwareLayer layer) {
|
||||
mGlCanvas.cancelLayerUpdate(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
void flushLayerUpdates() {
|
||||
mGlCanvas.flushLayerUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
HardwareLayer createHardwareLayer(boolean isOpaque) {
|
||||
return new GLES20TextureLayer(isOpaque);
|
||||
HardwareLayer createTextureLayer() {
|
||||
return HardwareLayer.createTextureLayer(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
|
||||
return new GLES20RenderLayer(width, height, isOpaque);
|
||||
public HardwareLayer createDisplayListLayer(int width, int height) {
|
||||
return HardwareLayer.createRenderLayer(this, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
@@ -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) { }
|
||||
|
||||
/**
|
||||
* Returns the minimum width of the layer.
|
||||
*
|
||||
* @return The minimum desired width of the hardware layer
|
||||
*/
|
||||
int getWidth() {
|
||||
return mWidth;
|
||||
public void setLayerPaint(Paint paint) {
|
||||
nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint,
|
||||
paint.getColorFilter() != null ? paint.getColorFilter().native_instance : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum height of the layer.
|
||||
*
|
||||
* @return The minimum desired height of the hardware layer
|
||||
*/
|
||||
int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DisplayList for the layer.
|
||||
*
|
||||
* @return The DisplayList of the hardware layer
|
||||
*/
|
||||
DisplayList getDisplayList() {
|
||||
return mDisplayList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DisplayList for the layer.
|
||||
*
|
||||
* @param displayList The new DisplayList for this layer
|
||||
*/
|
||||
void setDisplayList(DisplayList displayList) {
|
||||
mDisplayList = displayList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this layer is opaque.
|
||||
*
|
||||
* @return True if the layer is opaque, false otherwise
|
||||
*/
|
||||
boolean isOpaque() {
|
||||
return mOpaque;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not this layer should be considered opaque.
|
||||
*
|
||||
* @param isOpaque True if the layer is opaque, false otherwise
|
||||
*/
|
||||
abstract void setOpaque(boolean isOpaque);
|
||||
|
||||
/**
|
||||
* Indicates whether this layer can be rendered.
|
||||
*
|
||||
*
|
||||
* @return True if the layer can be rendered into, false otherwise
|
||||
*/
|
||||
abstract boolean isValid();
|
||||
public boolean isValid() {
|
||||
return mFinalizer != null && mFinalizer.mDeferredUpdater != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Destroys resources without waiting for a GC.
|
||||
*/
|
||||
abstract boolean resize(int width, int height);
|
||||
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 a hardware canvas that can be used to render onto
|
||||
* this layer.
|
||||
*
|
||||
* @return A hardware canvas, or null if a canvas cannot be created
|
||||
* 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.
|
||||
*
|
||||
* @see #start(android.graphics.Canvas)
|
||||
* @see #end(android.graphics.Canvas)
|
||||
* It is safe to call this in onLayerDestroyed only
|
||||
*/
|
||||
abstract HardwareCanvas getCanvas();
|
||||
public long detachBackingLayer() {
|
||||
long backingLayer = nDetachBackingLayer(mFinalizer.mDeferredUpdater);
|
||||
doDestroyLayerUpdater();
|
||||
return backingLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys resources without waiting for a GC.
|
||||
*/
|
||||
abstract void destroy();
|
||||
private void doDestroyLayerUpdater() {
|
||||
if (mFinalizer != null) {
|
||||
mFinalizer.destroy();
|
||||
mFinalizer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 DisplayList startRecording() {
|
||||
assertType(LAYER_TYPE_RENDER);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (mDisplayList == null) {
|
||||
mDisplayList = DisplayList.create("HardwareLayer");
|
||||
}
|
||||
return mDisplayList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be invoked after drawing onto this layer.
|
||||
*
|
||||
* @param currentCanvas The canvas whose rendering needs to be resumed
|
||||
*/
|
||||
abstract void end(Canvas currentCanvas);
|
||||
public void endRecording(Rect dirtyRect) {
|
||||
nUpdateRenderLayer(mFinalizer.mDeferredUpdater, mDisplayList.getNativeDisplayList(),
|
||||
dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
|
||||
mRenderer.pushLayerUpdate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
abstract boolean copyInto(Bitmap bitmap);
|
||||
public boolean copyInto(Bitmap bitmap) {
|
||||
return mRenderer.copyLayerInto(this, bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
void update(int width, int height, boolean isOpaque) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mOpaque = isOpaque;
|
||||
public boolean prepare(int width, int height, boolean isOpaque) {
|
||||
return nPrepare(mFinalizer.mDeferredUpdater, width, height, isOpaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an optional transform on this layer.
|
||||
*
|
||||
*
|
||||
* @param matrix The transform to apply to the layer.
|
||||
*/
|
||||
abstract void setTransform(Matrix matrix);
|
||||
public void setTransform(Matrix matrix) {
|
||||
nSetTransform(mFinalizer.mDeferredUpdater, matrix.native_instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Indicates that this layer has lost its texture.
|
||||
*/
|
||||
abstract void redrawLater(DisplayList displayList, Rect dirtyRect);
|
||||
public void onTextureDestroyed() {
|
||||
assertType(LAYER_TYPE_TEXTURE);
|
||||
nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this layer has lost its underlying storage.
|
||||
* 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 void clearStorage();
|
||||
@Deprecated
|
||||
public void flushChanges() {
|
||||
if (HardwareRenderer.sUseRenderThread) {
|
||||
// Not supported, don't try.
|
||||
return;
|
||||
}
|
||||
|
||||
boolean success = nFlushChanges(mFinalizer.mDeferredUpdater);
|
||||
if (!success) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public long getLayer() {
|
||||
return nGetLayer(mFinalizer.mDeferredUpdater);
|
||||
}
|
||||
|
||||
public void setSurfaceTexture(SurfaceTexture surface) {
|
||||
assertType(LAYER_TYPE_TEXTURE);
|
||||
nSetSurfaceTexture(mFinalizer.mDeferredUpdater, surface, false);
|
||||
}
|
||||
|
||||
public void updateSurfaceTexture() {
|
||||
assertType(LAYER_TYPE_TEXTURE);
|
||||
nUpdateSurfaceTexture(mFinalizer.mDeferredUpdater);
|
||||
}
|
||||
|
||||
/**
|
||||
* This should only be used by HardwareRenderer! Do not call directly
|
||||
*/
|
||||
SurfaceTexture createSurfaceTexture() {
|
||||
assertType(LAYER_TYPE_TEXTURE);
|
||||
SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.mDeferredUpdater));
|
||||
nSetSurfaceTexture(mFinalizer.mDeferredUpdater, st, true);
|
||||
return st;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should only be used by HardwareRenderer! Do not call directly
|
||||
*/
|
||||
static HardwareLayer createTextureLayer(HardwareRenderer renderer) {
|
||||
return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This should only be used by HardwareRenderer! Do not call directly
|
||||
*/
|
||||
static HardwareLayer createRenderLayer(HardwareRenderer renderer,
|
||||
int width, int height) {
|
||||
return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
|
||||
}
|
||||
|
||||
/** This also creates the underlying layer */
|
||||
private static native long nCreateTextureLayer();
|
||||
private static native long nCreateRenderLayer(int width, int height);
|
||||
|
||||
private static native void nOnTextureDestroyed(long layerUpdater);
|
||||
private static native long nDetachBackingLayer(long layerUpdater);
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 cancelLayerUpdate(HardwareLayer layer);
|
||||
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 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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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())) {
|
||||
mHardwareLayer.destroy();
|
||||
mHardwareLayer = null;
|
||||
|
||||
info.mHardwareRenderer.cancelLayerUpdate(mHardwareLayer);
|
||||
mHardwareLayer.destroy();
|
||||
mHardwareLayer = null;
|
||||
|
||||
invalidate(true);
|
||||
invalidateParentCaches();
|
||||
}
|
||||
invalidate(true);
|
||||
invalidateParentCaches();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -13910,19 +13897,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
return displayList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -57,6 +57,7 @@ LOCAL_SRC_FILES:= \
|
||||
android_view_GraphicBuffer.cpp \
|
||||
android_view_GLRenderer.cpp \
|
||||
android_view_GLES20Canvas.cpp \
|
||||
android_view_HardwareLayer.cpp \
|
||||
android_view_ThreadedRenderer.cpp \
|
||||
android_view_MotionEvent.cpp \
|
||||
android_view_PointerIcon.cpp \
|
||||
|
||||
@@ -123,6 +123,7 @@ extern int register_android_view_DisplayList(JNIEnv* env);
|
||||
extern int register_android_view_GraphicBuffer(JNIEnv* env);
|
||||
extern int register_android_view_GLES20Canvas(JNIEnv* env);
|
||||
extern int register_android_view_GLRenderer(JNIEnv* env);
|
||||
extern int register_android_view_HardwareLayer(JNIEnv* env);
|
||||
extern int register_android_view_ThreadedRenderer(JNIEnv* env);
|
||||
extern int register_android_view_Surface(JNIEnv* env);
|
||||
extern int register_android_view_SurfaceControl(JNIEnv* env);
|
||||
@@ -1127,6 +1128,7 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_view_GraphicBuffer),
|
||||
REG_JNI(register_android_view_GLES20Canvas),
|
||||
REG_JNI(register_android_view_GLRenderer),
|
||||
REG_JNI(register_android_view_HardwareLayer),
|
||||
REG_JNI(register_android_view_ThreadedRenderer),
|
||||
REG_JNI(register_android_view_Surface),
|
||||
REG_JNI(register_android_view_SurfaceControl),
|
||||
|
||||
@@ -914,147 +914,6 @@ static void android_view_GLES20Canvas_resume(JNIEnv* env, jobject clazz,
|
||||
renderer->resume();
|
||||
}
|
||||
|
||||
static jint android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env,
|
||||
jobject clazz, jlong layerPtr) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
if (layer) {
|
||||
OpenGLRenderer* renderer = new LayerRenderer(layer);
|
||||
renderer->initProperties();
|
||||
return reinterpret_cast<jint>(renderer);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static jlong android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject clazz,
|
||||
jboolean isOpaque, jintArray layerInfo) {
|
||||
Layer* layer = LayerRenderer::createTextureLayer(isOpaque);
|
||||
|
||||
if (layer) {
|
||||
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
|
||||
storage[0] = layer->getTexture();
|
||||
env->ReleaseIntArrayElements(layerInfo, storage, 0);
|
||||
}
|
||||
|
||||
return reinterpret_cast<jlong>(layer);
|
||||
}
|
||||
|
||||
static jlong android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz,
|
||||
jint width, jint height, jboolean isOpaque, jintArray layerInfo) {
|
||||
Layer* layer = LayerRenderer::createLayer(width, height, isOpaque);
|
||||
|
||||
if (layer) {
|
||||
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
|
||||
storage[0] = layer->getWidth();
|
||||
storage[1] = layer->getHeight();
|
||||
env->ReleaseIntArrayElements(layerInfo, storage, 0);
|
||||
}
|
||||
|
||||
return reinterpret_cast<jlong>(layer);
|
||||
}
|
||||
|
||||
static jboolean android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr, jint width, jint height, jintArray layerInfo) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
if (LayerRenderer::resizeLayer(layer, width, height)) {
|
||||
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
|
||||
storage[0] = layer->getWidth();
|
||||
storage[1] = layer->getHeight();
|
||||
env->ReleaseIntArrayElements(layerInfo, storage, 0);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_setLayerPaint(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr, jlong paintPtr) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
if (layer) {
|
||||
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
|
||||
layer->setPaint(paint);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_setLayerColorFilter(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr, jlong colorFilterPtr) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
if (layer) {
|
||||
SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
|
||||
layer->setColorFilter(colorFilter);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_setOpaqueLayer(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr, jboolean isOpaque) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
if (layer) {
|
||||
layer->setBlend(!isOpaque);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr, jint width, jint height, jboolean isOpaque, jobject surface) {
|
||||
float transform[16];
|
||||
sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
|
||||
|
||||
if (surfaceTexture->updateTexImage() == NO_ERROR) {
|
||||
int64_t frameNumber = surfaceTexture->getFrameNumber();
|
||||
// If the GLConsumer queue is in synchronous mode, need to discard all
|
||||
// but latest frame, using the frame number to tell when we no longer
|
||||
// have newer frames to target. Since we can't tell which mode it is in,
|
||||
// do this unconditionally.
|
||||
int dropCounter = 0;
|
||||
while (surfaceTexture->updateTexImage() == NO_ERROR) {
|
||||
int64_t newFrameNumber = surfaceTexture->getFrameNumber();
|
||||
if (newFrameNumber == frameNumber) break;
|
||||
frameNumber = newFrameNumber;
|
||||
dropCounter++;
|
||||
}
|
||||
#if DEBUG_RENDERER
|
||||
if (dropCounter > 0) {
|
||||
RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
|
||||
}
|
||||
#endif
|
||||
surfaceTexture->getTransformMatrix(transform);
|
||||
GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
|
||||
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, renderTarget, transform);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_updateRenderLayer(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr, jlong rendererPtr, jlong displayListPtr,
|
||||
jint left, jint top, jint right, jint bottom) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
|
||||
DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
|
||||
layer->updateDeferred(renderer, displayList, left, top, right, bottom);
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_clearLayerTexture(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
layer->clearTexture();
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz,
|
||||
jlong layerPtr, jlong matrixPtr) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
|
||||
layer->getTransform().load(*matrix);
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, jlong layerPtr) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
LayerRenderer::destroyLayer(layer);
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_destroyLayerDeferred(JNIEnv* env,
|
||||
jobject clazz, jlong layerPtr) {
|
||||
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
|
||||
LayerRenderer::destroyLayerDeferred(layer);
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
|
||||
jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
|
||||
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
|
||||
@@ -1247,19 +1106,6 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nInterrupt", "(J)V", (void*) android_view_GLES20Canvas_interrupt },
|
||||
{ "nResume", "(J)V", (void*) android_view_GLES20Canvas_resume },
|
||||
|
||||
{ "nCreateLayerRenderer", "(J)J", (void*) android_view_GLES20Canvas_createLayerRenderer },
|
||||
{ "nCreateLayer", "(IIZ[I)J", (void*) android_view_GLES20Canvas_createLayer },
|
||||
{ "nResizeLayer", "(JII[I)Z" , (void*) android_view_GLES20Canvas_resizeLayer },
|
||||
{ "nSetLayerPaint", "(JJ)V", (void*) android_view_GLES20Canvas_setLayerPaint },
|
||||
{ "nSetLayerColorFilter", "(JJ)V", (void*) android_view_GLES20Canvas_setLayerColorFilter },
|
||||
{ "nSetOpaqueLayer", "(JZ)V", (void*) android_view_GLES20Canvas_setOpaqueLayer },
|
||||
{ "nCreateTextureLayer", "(Z[I)J", (void*) android_view_GLES20Canvas_createTextureLayer },
|
||||
{ "nUpdateTextureLayer", "(JIIZLandroid/graphics/SurfaceTexture;)V",
|
||||
(void*) android_view_GLES20Canvas_updateTextureLayer },
|
||||
{ "nUpdateRenderLayer", "(JJJIIII)V", (void*) android_view_GLES20Canvas_updateRenderLayer },
|
||||
{ "nClearLayerTexture", "(J)V", (void*) android_view_GLES20Canvas_clearLayerTexture },
|
||||
{ "nDestroyLayer", "(J)V", (void*) android_view_GLES20Canvas_destroyLayer },
|
||||
{ "nDestroyLayerDeferred", "(J)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
|
||||
{ "nDrawLayer", "(JJFF)V", (void*) android_view_GLES20Canvas_drawLayer },
|
||||
{ "nCopyLayer", "(JJ)Z", (void*) android_view_GLES20Canvas_copyLayer },
|
||||
{ "nClearLayerUpdates", "(J)V", (void*) android_view_GLES20Canvas_clearLayerUpdates },
|
||||
@@ -1267,8 +1113,6 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nPushLayerUpdate", "(JJ)V", (void*) android_view_GLES20Canvas_pushLayerUpdate },
|
||||
{ "nCancelLayerUpdate", "(JJ)V", (void*) android_view_GLES20Canvas_cancelLayerUpdate },
|
||||
|
||||
{ "nSetTextureLayerTransform", "(JJ)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform },
|
||||
|
||||
{ "nGetMaximumTextureWidth", "()I", (void*) android_view_GLES20Canvas_getMaxTextureWidth },
|
||||
{ "nGetMaximumTextureHeight", "()I", (void*) android_view_GLES20Canvas_getMaxTextureHeight },
|
||||
|
||||
|
||||
183
core/jni/android_view_HardwareLayer.cpp
Normal file
183
core/jni/android_view_HardwareLayer.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "OpenGLRenderer"
|
||||
|
||||
#include "jni.h"
|
||||
#include "GraphicsJNI.h"
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
#include <android_runtime/android_graphics_SurfaceTexture.h>
|
||||
|
||||
#include <gui/GLConsumer.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkMatrix.h>
|
||||
#include <SkPaint.h>
|
||||
#include <SkXfermode.h>
|
||||
|
||||
#include <DeferredLayerUpdater.h>
|
||||
#include <DisplayList.h>
|
||||
#include <LayerRenderer.h>
|
||||
#include <SkiaShader.h>
|
||||
#include <Rect.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
using namespace uirenderer;
|
||||
|
||||
#ifdef USE_OPENGL_RENDERER
|
||||
|
||||
static jlong android_view_HardwareLayer_createTextureLayer(JNIEnv* env, jobject clazz) {
|
||||
Layer* layer = LayerRenderer::createTextureLayer();
|
||||
if (!layer) return 0;
|
||||
|
||||
return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) );
|
||||
}
|
||||
|
||||
static jlong android_view_HardwareLayer_createRenderLayer(JNIEnv* env, jobject clazz,
|
||||
jint width, jint height) {
|
||||
Layer* layer = LayerRenderer::createRenderLayer(width, height);
|
||||
if (!layer) return 0;
|
||||
|
||||
OpenGLRenderer* renderer = new LayerRenderer(layer);
|
||||
renderer->initProperties();
|
||||
return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer, renderer) );
|
||||
}
|
||||
|
||||
static void android_view_HardwareLayer_onTextureDestroyed(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
layer->backingLayer()->clearTexture();
|
||||
}
|
||||
|
||||
static jlong android_view_HardwareLayer_detachBackingLayer(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
return reinterpret_cast<jlong>( layer->detachBackingLayer() );
|
||||
}
|
||||
|
||||
static void android_view_HardwareLayer_destroyLayerUpdater(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
delete layer;
|
||||
}
|
||||
|
||||
static jboolean android_view_HardwareLayer_prepare(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr, jint width, jint height, jboolean isOpaque) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
bool changed = false;
|
||||
changed |= layer->setSize(width, height);
|
||||
changed |= layer->setBlend(!isOpaque);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void android_view_HardwareLayer_setLayerPaint(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr, jlong paintPtr, jlong colorFilterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
if (layer) {
|
||||
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
|
||||
SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
|
||||
layer->setPaint(paint);
|
||||
layer->setColorFilter(colorFilter);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_view_HardwareLayer_setTransform(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr, jlong matrixPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
|
||||
layer->setTransform(matrix);
|
||||
}
|
||||
|
||||
static void android_view_HardwareLayer_setSurfaceTexture(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr, jobject surface, jboolean isAlreadyAttached) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
|
||||
layer->setSurfaceTexture(surfaceTexture, !isAlreadyAttached);
|
||||
}
|
||||
|
||||
static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
layer->updateTexImage();
|
||||
}
|
||||
|
||||
static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr, jlong displayListPtr,
|
||||
jint left, jint top, jint right, jint bottom) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
|
||||
layer->setDisplayList(displayList, left, top, right, bottom);
|
||||
}
|
||||
|
||||
static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
return layer->apply();
|
||||
}
|
||||
|
||||
static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
return reinterpret_cast<jlong>( layer->backingLayer() );
|
||||
}
|
||||
|
||||
static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
|
||||
jlong layerUpdaterPtr) {
|
||||
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
|
||||
return layer->backingLayer()->getTexture();
|
||||
}
|
||||
|
||||
#endif // USE_OPENGL_RENDERER
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// JNI Glue
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const char* const kClassPathName = "android/view/HardwareLayer";
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
#ifdef USE_OPENGL_RENDERER
|
||||
|
||||
{ "nCreateTextureLayer", "()J", (void*) android_view_HardwareLayer_createTextureLayer },
|
||||
{ "nCreateRenderLayer", "(II)J", (void*) android_view_HardwareLayer_createRenderLayer },
|
||||
{ "nOnTextureDestroyed", "(J)V", (void*) android_view_HardwareLayer_onTextureDestroyed },
|
||||
{ "nDetachBackingLayer", "(J)J", (void*) android_view_HardwareLayer_detachBackingLayer },
|
||||
{ "nDestroyLayerUpdater", "(J)V", (void*) android_view_HardwareLayer_destroyLayerUpdater },
|
||||
|
||||
{ "nPrepare", "(JIIZ)Z", (void*) android_view_HardwareLayer_prepare },
|
||||
{ "nSetLayerPaint", "(JJJ)V", (void*) android_view_HardwareLayer_setLayerPaint },
|
||||
{ "nSetTransform", "(JJ)V", (void*) android_view_HardwareLayer_setTransform },
|
||||
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
|
||||
(void*) android_view_HardwareLayer_setSurfaceTexture },
|
||||
{ "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture },
|
||||
{ "nUpdateRenderLayer", "(JJIIII)V", (void*) android_view_HardwareLayer_updateRenderLayer },
|
||||
|
||||
{ "nFlushChanges", "(J)Z", (void*) android_view_HardwareLayer_flushChanges },
|
||||
|
||||
{ "nGetLayer", "(J)J", (void*) android_view_HardwareLayer_getLayer },
|
||||
{ "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName },
|
||||
#endif
|
||||
};
|
||||
|
||||
int register_android_view_HardwareLayer(JNIEnv* env) {
|
||||
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
|
||||
}
|
||||
|
||||
};
|
||||
@@ -17,6 +17,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
||||
Caches.cpp \
|
||||
DisplayList.cpp \
|
||||
DeferredDisplayList.cpp \
|
||||
DeferredLayerUpdater.cpp \
|
||||
DisplayListLogBuffer.cpp \
|
||||
DisplayListRenderer.cpp \
|
||||
Dither.cpp \
|
||||
@@ -70,7 +71,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
||||
LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter
|
||||
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
|
||||
LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui
|
||||
LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui libgui
|
||||
LOCAL_MODULE := libhwui
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
|
||||
150
libs/hwui/DeferredLayerUpdater.cpp
Normal file
150
libs/hwui/DeferredLayerUpdater.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
#include "DeferredLayerUpdater.h"
|
||||
|
||||
#include "OpenGLRenderer.h"
|
||||
|
||||
#include "LayerRenderer.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer)
|
||||
: mDisplayList(0)
|
||||
, mSurfaceTexture(0)
|
||||
, mTransform(0)
|
||||
, mNeedsGLContextAttach(false)
|
||||
, mUpdateTexImage(false)
|
||||
, mLayer(layer)
|
||||
, mRenderer(renderer)
|
||||
, mCaches(Caches::getInstance()) {
|
||||
mCaches.resourceCache.incrementRefcount(mLayer);
|
||||
mWidth = mLayer->layer.getWidth();
|
||||
mHeight = mLayer->layer.getHeight();
|
||||
mBlend = mLayer->isBlend();
|
||||
mColorFilter = mLayer->getColorFilter();
|
||||
mAlpha = mLayer->getAlpha();
|
||||
mMode = mLayer->getMode();
|
||||
mDirtyRect.setEmpty();
|
||||
}
|
||||
|
||||
DeferredLayerUpdater::~DeferredLayerUpdater() {
|
||||
setColorFilter(NULL);
|
||||
if (mLayer) {
|
||||
mCaches.resourceCache.decrementRefcount(mLayer);
|
||||
}
|
||||
delete mRenderer;
|
||||
}
|
||||
|
||||
void DeferredLayerUpdater::setColorFilter(SkColorFilter* colorFilter) {
|
||||
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
|
||||
}
|
||||
|
||||
void DeferredLayerUpdater::setDisplayList(DisplayList* displayList,
|
||||
int left, int top, int right, int bottom) {
|
||||
mDisplayList = displayList;
|
||||
if (mDirtyRect.isEmpty()) {
|
||||
mDirtyRect.set(left, top, right, bottom);
|
||||
} else {
|
||||
mDirtyRect.unionWith(Rect(left, top, right, bottom));
|
||||
}
|
||||
}
|
||||
|
||||
bool DeferredLayerUpdater::apply() {
|
||||
bool success = true;
|
||||
// These properties are applied the same to both layer types
|
||||
mLayer->setColorFilter(mColorFilter);
|
||||
mLayer->setAlpha(mAlpha, mMode);
|
||||
|
||||
if (mDisplayList) {
|
||||
if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
|
||||
success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
|
||||
}
|
||||
mLayer->setBlend(mBlend);
|
||||
mLayer->updateDeferred(mRenderer, mDisplayList,
|
||||
mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
|
||||
mDirtyRect.setEmpty();
|
||||
mDisplayList = 0;
|
||||
} else if (mSurfaceTexture.get()) {
|
||||
if (mNeedsGLContextAttach) {
|
||||
mNeedsGLContextAttach = false;
|
||||
mSurfaceTexture->attachToContext(mLayer->getTexture());
|
||||
}
|
||||
if (mUpdateTexImage) {
|
||||
mUpdateTexImage = false;
|
||||
doUpdateTexImage();
|
||||
}
|
||||
if (mTransform) {
|
||||
mLayer->getTransform().load(*mTransform);
|
||||
setTransform(0);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void DeferredLayerUpdater::doUpdateTexImage() {
|
||||
if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
|
||||
float transform[16];
|
||||
|
||||
int64_t frameNumber = mSurfaceTexture->getFrameNumber();
|
||||
// If the GLConsumer queue is in synchronous mode, need to discard all
|
||||
// but latest frame, using the frame number to tell when we no longer
|
||||
// have newer frames to target. Since we can't tell which mode it is in,
|
||||
// do this unconditionally.
|
||||
int dropCounter = 0;
|
||||
while (mSurfaceTexture->updateTexImage() == NO_ERROR) {
|
||||
int64_t newFrameNumber = mSurfaceTexture->getFrameNumber();
|
||||
if (newFrameNumber == frameNumber) break;
|
||||
frameNumber = newFrameNumber;
|
||||
dropCounter++;
|
||||
}
|
||||
#if DEBUG_RENDERER
|
||||
if (dropCounter > 0) {
|
||||
RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
|
||||
}
|
||||
#endif
|
||||
mSurfaceTexture->getTransformMatrix(transform);
|
||||
GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
|
||||
|
||||
LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight, !mBlend,
|
||||
renderTarget, transform);
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredLayerUpdater::applyDeferred(DeferredLayerUpdater* deferredApply) {
|
||||
// Default assignment operator doesn't quite work, and fails due to mCaches anyway
|
||||
deferredApply->mWidth = mWidth;
|
||||
deferredApply->mHeight = mHeight;
|
||||
deferredApply->mBlend = mBlend;
|
||||
deferredApply->mAlpha = mAlpha;
|
||||
deferredApply->mMode = mMode;
|
||||
deferredApply->mDirtyRect.set(mDirtyRect);
|
||||
deferredApply->mDisplayList = mDisplayList;
|
||||
deferredApply->mSurfaceTexture = mSurfaceTexture;
|
||||
deferredApply->mNeedsGLContextAttach = mNeedsGLContextAttach;
|
||||
deferredApply->mUpdateTexImage = mUpdateTexImage;
|
||||
deferredApply->setColorFilter(mColorFilter);
|
||||
deferredApply->setTransform(mTransform);
|
||||
|
||||
mDisplayList = 0;
|
||||
mDirtyRect.setEmpty();
|
||||
mTransform = 0;
|
||||
mNeedsGLContextAttach = false;
|
||||
mUpdateTexImage = false;
|
||||
}
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
124
libs/hwui/DeferredLayerUpdater.h
Normal file
124
libs/hwui/DeferredLayerUpdater.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
#ifndef DEFERREDLAYERUPDATE_H_
|
||||
#define DEFERREDLAYERUPDATE_H_
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
#include <gui/GLConsumer.h>
|
||||
#include <SkColorFilter.h>
|
||||
#include <SkMatrix.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include "DisplayList.h"
|
||||
#include "Layer.h"
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "Rect.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
// Container to hold the properties a layer should be set to at the start
|
||||
// of a render pass
|
||||
class DeferredLayerUpdater {
|
||||
public:
|
||||
ANDROID_API DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer = 0);
|
||||
ANDROID_API ~DeferredLayerUpdater();
|
||||
|
||||
ANDROID_API bool setSize(uint32_t width, uint32_t height) {
|
||||
if (mWidth != width || mHeight != height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ANDROID_API bool setBlend(bool blend) {
|
||||
if (blend != mBlend) {
|
||||
mBlend = blend;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ANDROID_API void setSurfaceTexture(const sp<GLConsumer>& texture, bool needsAttach) {
|
||||
if (texture.get() != mSurfaceTexture.get()) {
|
||||
mNeedsGLContextAttach = needsAttach;
|
||||
mSurfaceTexture = texture;
|
||||
}
|
||||
}
|
||||
|
||||
ANDROID_API void updateTexImage() {
|
||||
mUpdateTexImage = true;
|
||||
}
|
||||
|
||||
ANDROID_API void setTransform(const SkMatrix* matrix) {
|
||||
delete mTransform;
|
||||
mTransform = matrix ? new SkMatrix(*matrix) : 0;
|
||||
}
|
||||
|
||||
ANDROID_API void setDisplayList(DisplayList* displayList,
|
||||
int left, int top, int right, int bottom);
|
||||
|
||||
ANDROID_API void setPaint(const SkPaint* paint) {
|
||||
OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
|
||||
}
|
||||
|
||||
ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
|
||||
|
||||
ANDROID_API bool apply();
|
||||
ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
|
||||
|
||||
ANDROID_API Layer* backingLayer() {
|
||||
return mLayer;
|
||||
}
|
||||
|
||||
ANDROID_API Layer* detachBackingLayer() {
|
||||
Layer* layer = mLayer;
|
||||
mLayer = 0;
|
||||
return layer;
|
||||
}
|
||||
|
||||
private:
|
||||
// Generic properties
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
bool mBlend;
|
||||
SkColorFilter* mColorFilter;
|
||||
int mAlpha;
|
||||
SkXfermode::Mode mMode;
|
||||
|
||||
// Layer type specific properties
|
||||
// displayList and surfaceTexture are mutually exclusive, only 1 may be set
|
||||
// dirtyRect is only valid if displayList is set
|
||||
DisplayList* mDisplayList;
|
||||
Rect mDirtyRect;
|
||||
sp<GLConsumer> mSurfaceTexture;
|
||||
SkMatrix* mTransform;
|
||||
bool mNeedsGLContextAttach;
|
||||
bool mUpdateTexImage;
|
||||
|
||||
Layer* mLayer;
|
||||
OpenGLRenderer* mRenderer;
|
||||
Caches& mCaches;
|
||||
|
||||
void doUpdateTexImage();
|
||||
};
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
#endif /* DEFERREDLAYERUPDATE_H_ */
|
||||
@@ -184,7 +184,7 @@ void LayerRenderer::generateMesh() {
|
||||
// Layers management
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
|
||||
Layer* LayerRenderer::createRenderLayer(uint32_t width, uint32_t height) {
|
||||
LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
|
||||
|
||||
Caches& caches = Caches::getInstance();
|
||||
@@ -221,7 +221,6 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque
|
||||
layer->texCoords.set(0.0f, height / float(layer->getHeight()),
|
||||
width / float(layer->getWidth()), 0.0f);
|
||||
layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
|
||||
layer->setBlend(!isOpaque);
|
||||
layer->setColorFilter(NULL);
|
||||
layer->setDirty(true);
|
||||
layer->region.clear();
|
||||
@@ -270,13 +269,12 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
|
||||
Layer* LayerRenderer::createTextureLayer() {
|
||||
LAYER_RENDERER_LOGD("Creating new texture layer");
|
||||
|
||||
Layer* layer = new Layer(0, 0);
|
||||
layer->setCacheable(false);
|
||||
layer->setTextureLayer(true);
|
||||
layer->setBlend(!isOpaque);
|
||||
layer->setEmpty(true);
|
||||
layer->setFbo(0);
|
||||
layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
|
||||
|
||||
@@ -52,8 +52,8 @@ public:
|
||||
virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
|
||||
virtual void finish();
|
||||
|
||||
ANDROID_API static Layer* createTextureLayer(bool isOpaque);
|
||||
ANDROID_API static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
|
||||
ANDROID_API static Layer* createTextureLayer();
|
||||
ANDROID_API static Layer* createRenderLayer(uint32_t width, uint32_t height);
|
||||
ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
|
||||
ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
|
||||
bool isOpaque, GLenum renderTarget, float* transform);
|
||||
|
||||
@@ -97,7 +97,7 @@ abstract public class CompareActivity extends Activity {
|
||||
Log.d(LOG_TAG, "failure to access hardware layer");
|
||||
return;
|
||||
}
|
||||
Method copyInto = hardwareLayer.getClass().getSuperclass()
|
||||
Method copyInto = hardwareLayer.getClass()
|
||||
.getDeclaredMethod("copyInto", Bitmap.class);
|
||||
if (!copyInto.isAccessible())
|
||||
copyInto.setAccessible(true);
|
||||
|
||||
@@ -35,23 +35,24 @@ public class ErrorCalculator {
|
||||
private static final boolean LOG_TIMING = false;
|
||||
private static final boolean LOG_CALC = false;
|
||||
|
||||
private final RenderScript mRS;
|
||||
private RenderScript mRS;
|
||||
private Allocation mIdealPixelsAllocation;
|
||||
private Allocation mGivenPixelsAllocation;
|
||||
private Allocation mOutputPixelsAllocation;
|
||||
|
||||
private final Allocation mInputRowsAllocation;
|
||||
private final Allocation mOutputRegionsAllocation;
|
||||
private Allocation mInputRowsAllocation;
|
||||
private Allocation mOutputRegionsAllocation;
|
||||
|
||||
private final ScriptC_errorCalculator mScript;
|
||||
private ScriptC_errorCalculator mScript;
|
||||
|
||||
private final int[] mOutputRowRegions;
|
||||
private int[] mOutputRowRegions;
|
||||
|
||||
public ErrorCalculator(Context c, Resources resources) {
|
||||
int width = resources.getDimensionPixelSize(R.dimen.layer_width);
|
||||
int height = resources.getDimensionPixelSize(R.dimen.layer_height);
|
||||
mOutputRowRegions = new int[height / REGION_SIZE];
|
||||
|
||||
/*
|
||||
mRS = RenderScript.create(c);
|
||||
int[] rowIndices = new int[height / REGION_SIZE];
|
||||
for (int i = 0; i < rowIndices.length; i++)
|
||||
@@ -67,12 +68,15 @@ public class ErrorCalculator {
|
||||
mInputRowsAllocation.copyFrom(rowIndices);
|
||||
mOutputRegionsAllocation = Allocation.createSized(mRS, Element.I32(mRS),
|
||||
mOutputRowRegions.length, Allocation.USAGE_SCRIPT);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
private static long startMillis, middleMillis;
|
||||
|
||||
public float calcErrorRS(Bitmap ideal, Bitmap given) {
|
||||
if (true)
|
||||
return calcError(ideal, given);
|
||||
if (LOG_TIMING) {
|
||||
startMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user