diff --git a/api/current.txt b/api/current.txt index 4b3918e6adba1..5aa840d320587 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21010,6 +21010,21 @@ package android.view { method public void setZOrderOnTop(boolean); } + public class TextureView extends android.view.View { + ctor public TextureView(android.content.Context); + ctor public TextureView(android.content.Context, android.util.AttributeSet); + ctor public TextureView(android.content.Context, android.util.AttributeSet, int); + method public final void draw(android.graphics.Canvas); + method public android.graphics.SurfaceTexture getSurfaceTexture(); + method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener(); + method protected final void onDraw(android.graphics.Canvas); + method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener); + } + + public static abstract interface TextureView.SurfaceTextureListener { + method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture); + } + public class TouchDelegate { ctor public TouchDelegate(android.graphics.Rect, android.view.View); method public boolean onTouchEvent(android.view.MotionEvent); diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index b8c5c2acadc85..cdf8954f5b2f5 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -160,8 +160,11 @@ class GLES20Canvas extends HardwareCanvas { // Hardware layers /////////////////////////////////////////////////////////////////////////// + static native int nCreateTextureLayer(int[] layerInfo); static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo); static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo); + static native void nUpdateTextureLayer(int layerId, int width, int height, + float[] textureTransform); static native void nDestroyLayer(int layerId); static native void nDestroyLayerDeferred(int layerId); @@ -272,7 +275,7 @@ class GLES20Canvas extends HardwareCanvas { } private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint); - + void interrupt() { nInterrupt(mRenderer); } diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java index 6000a4a53bff8..bc191a6fae9b3 100644 --- a/core/java/android/view/GLES20Layer.java +++ b/core/java/android/view/GLES20Layer.java @@ -14,39 +14,21 @@ * limitations under the License. */ -package android.view; -import android.graphics.Canvas; +package android.view; /** * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. */ -class GLES20Layer extends HardwareLayer { - private int mLayer; +abstract class GLES20Layer extends HardwareLayer { + int mLayer; + Finalizer mFinalizer; - private int mLayerWidth; - private int mLayerHeight; + GLES20Layer() { + } - private final GLES20Canvas mCanvas; - - @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) - private final Finalizer mFinalizer; - - GLES20Layer(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; - } + GLES20Layer(int width, int height, boolean opaque) { + super(width, height, opaque); } /** @@ -58,55 +40,14 @@ class GLES20Layer extends HardwareLayer { return mLayer; } - @Override - boolean isValid() { - return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0; - } - - @Override - void resize(int width, int height) { - if (!isValid() || width <= 0 || height <= 0) return; - - mWidth = width; - mHeight = height; - - if (width != mLayerWidth || height != mLayerHeight) { - int[] layerInfo = new int[2]; - - GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo); - - mLayerWidth = layerInfo[0]; - mLayerHeight = layerInfo[1]; - } - } - - @Override - HardwareCanvas getCanvas() { - return mCanvas; - } - - @Override - void end(Canvas currentCanvas) { - if (currentCanvas instanceof GLES20Canvas) { - ((GLES20Canvas) currentCanvas).resume(); - } - } - - @Override - HardwareCanvas start(Canvas currentCanvas) { - if (currentCanvas instanceof GLES20Canvas) { - ((GLES20Canvas) currentCanvas).interrupt(); - } - return getCanvas(); - } - + @Override void destroy() { - mFinalizer.destroy(); + if (mFinalizer != null) mFinalizer.destroy(); mLayer = 0; } - private static class Finalizer { + static class Finalizer { private int mLayerId; public Finalizer(int layerId) { diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java new file mode 100644 index 0000000000000..7adac1ce3e3fe --- /dev/null +++ b/core/java/android/view/GLES20RenderLayer.java @@ -0,0 +1,91 @@ +/* + * 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; + +/** + * 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 + void resize(int width, int height) { + if (!isValid() || width <= 0 || height <= 0) return; + + mWidth = width; + mHeight = height; + + if (width != mLayerWidth || height != mLayerHeight) { + int[] layerInfo = new int[2]; + + GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo); + + mLayerWidth = layerInfo[0]; + mLayerHeight = layerInfo[1]; + } + } + + @Override + HardwareCanvas getCanvas() { + return mCanvas; + } + + @Override + void end(Canvas currentCanvas) { + if (currentCanvas instanceof GLES20Canvas) { + ((GLES20Canvas) currentCanvas).resume(); + } + } + + @Override + HardwareCanvas start(Canvas currentCanvas) { + if (currentCanvas instanceof GLES20Canvas) { + ((GLES20Canvas) currentCanvas).interrupt(); + } + return getCanvas(); + } +} diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java new file mode 100644 index 0000000000000..21fbdfcf6af35 --- /dev/null +++ b/core/java/android/view/GLES20TextureLayer.java @@ -0,0 +1,76 @@ +/* + * 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.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() { + int[] layerInfo = new int[2]; + mLayer = GLES20Canvas.nCreateTextureLayer(layerInfo); + + if (mLayer != 0) { + mTexture = layerInfo[0]; + mFinalizer = new Finalizer(mLayer); + } else { + mFinalizer = null; + } + } + + @Override + boolean isValid() { + return mLayer != 0 && mTexture != 0; + } + + @Override + void resize(int width, int height) { + } + + @Override + HardwareCanvas getCanvas() { + return null; + } + + @Override + HardwareCanvas start(Canvas currentCanvas) { + return null; + } + + @Override + void end(Canvas currentCanvas) { + } + + SurfaceTexture getSurfaceTexture() { + if (mSurface == null) { + mSurface = new SurfaceTexture(mTexture); + } + return mSurface; + } + + void update(int width, int height, float[] textureTransform) { + GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, textureTransform); + } +} diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index d01b8ce37854e..86dec3f16effa 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -26,11 +26,23 @@ import android.graphics.Canvas; * drawn several times. */ abstract class HardwareLayer { + /** + * Indicates an unknown dimension (width or height.) + */ + static final int DIMENSION_UNDEFINED = -1; + int mWidth; int mHeight; final boolean mOpaque; + /** + * Creates a new hardware layer with undefined dimensions. + */ + HardwareLayer() { + this(DIMENSION_UNDEFINED, DIMENSION_UNDEFINED, false); + } + /** * Creates a new hardware layer at least as large as the supplied * dimensions. diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 66f37f29b0bd3..5b2983d548a11 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -20,6 +20,7 @@ package android.view; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.SurfaceTexture; import android.os.*; import android.util.EventLog; import android.util.Log; @@ -165,6 +166,14 @@ public abstract class HardwareRenderer { */ abstract DisplayList createDisplayList(View v); + /** + * 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. + * + * @return A hardware layer + */ + abstract HardwareLayer createHardwareLayer(); + /** * Creates a new hardware layer. * @@ -175,6 +184,29 @@ public abstract class HardwareRenderer { * @return A hardware layer */ abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque); + + /** + * Creates a new {@link SurfaceTexture} that can be used to render into the + * specified hardware layer. + * + * + * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture} + * + * @return A {@link SurfaceTexture} + */ + abstract SurfaceTexture createSuraceTexture(HardwareLayer layer); + + /** + * Updates the specified layer. + * + * @param layer The hardware layer to update + * @param width The layer's width + * @param height The layer's height + * @param textureTransform A 4x4 column-first transform matrix to apply to + * texture coordinates + */ + abstract void updateTextureLayer(HardwareLayer layer, int width, int height, + float[] textureTransform); /** * Initializes the hardware renderer for the specified surface and setup the @@ -856,10 +888,26 @@ public abstract class HardwareRenderer { DisplayList createDisplayList(View v) { return new GLES20DisplayList(v); } - + + @Override + HardwareLayer createHardwareLayer() { + return new GLES20TextureLayer(); + } + @Override HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) { - return new GLES20Layer(width, height, isOpaque); + return new GLES20RenderLayer(width, height, isOpaque); + } + + @Override + SurfaceTexture createSuraceTexture(HardwareLayer layer) { + return ((GLES20TextureLayer) layer).getSurfaceTexture(); + } + + @Override + void updateTextureLayer(HardwareLayer layer, int width, int height, + float[] textureTransform) { + ((GLES20TextureLayer) layer).update(width, height, textureTransform); } static HardwareRenderer create(boolean translucent) { diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java new file mode 100644 index 0000000000000..5ece15cca7a81 --- /dev/null +++ b/core/java/android/view/TextureView.java @@ -0,0 +1,299 @@ +/* + * 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.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.SurfaceTexture; +import android.util.AttributeSet; +import android.util.Log; + +/** + *
A TextureView can be used to display a content stream. Such a content + * stream can for instance be a video or an OpenGL scene. The content stream + * can come from the application's process as well as a remote process.
+ * + *TextureView can only be used in a hardware accelerated window. When + * rendered in software, TextureView will draw nothing.
+ * + *Unlike {@link SurfaceView}, TextureView does not create a separate
+ * window but behaves as a regular View. This key difference allows a
+ * TextureView to be moved, transformed, animated, etc. For instance, you
+ * can make a TextureView semi-translucent by calling
+ * myView.setAlpha(0.5f).
Using a TextureView is simple: all you need to do is get its + * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to + * render content. The following example demonstrates how to render the + * camera preview into a TextureView:
+ * + *
+ * public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
+ * private Camera mCamera;
+ * private TextureView mTextureView;
+ *
+ * @Override
+ * protected void onCreate(Bundle savedInstanceState) {
+ * super.onCreate(savedInstanceState);
+ *
+ * mTextureView = new TextureView(this);
+ * mTextureView.setSurfaceTextureListener(this);
+ *
+ * setContentView(mTextureView);
+ * }
+ *
+ * @Override
+ * protected void onDestroy() {
+ * super.onDestroy();
+ *
+ * mCamera.stopPreview();
+ * mCamera.release();
+ * }
+ *
+ * @Override
+ * public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ * mCamera = Camera.open();
+ *
+ * try {
+ * mCamera.setPreviewTexture(surface);
+ * mCamera.startPreview();
+ * } catch (IOException ioe) {
+ * // Something bad happened
+ * }
+ * }
+ * }
+ *
+ *
+ * A TextureView's SurfaceTexture can be obtained either by invoking + * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}. + * It is important to know that a SurfaceTexture is available only after the + * TextureView is attached to a window (and {@link #onAttachedToWindow()} has + * been invoked.) It is therefore highly recommended you use a listener to + * be notified when the SurfaceTexture becomes available.
+ * + * @see SurfaceView + * @see SurfaceTexture + */ +public class TextureView extends View { + private HardwareLayer mLayer; + private SurfaceTexture mSurface; + private SurfaceTextureListener mListener; + + private final float[] mTextureTransform = new float[16]; + + private final Runnable mUpdateLayerAction = new Runnable() { + @Override + public void run() { + updateLayer(); + } + }; + + /** + * Creates a new TextureView. + * + * @param context The context to associate this view with. + */ + public TextureView(Context context) { + super(context); + init(); + } + + /** + * Creates a new TextureView. + * + * @param context The context to associate this view with. + * @param attrs The attributes of the XML tag that is inflating the view. + */ + @SuppressWarnings({"UnusedDeclaration"}) + public TextureView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + /** + * Creates a new TextureView. + * + * @param context The context to associate this view with. + * @param attrs The attributes of the XML tag that is inflating the view. + * @param defStyle The default style to apply to this view. If 0, no style + * will be applied (beyond what is included in the theme). This may + * either be an attribute resource, whose value will be retrieved + * from the current theme, or an explicit style resource. + */ + @SuppressWarnings({"UnusedDeclaration"}) + public TextureView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + mLayerPaint = new Paint(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (!isHardwareAccelerated()) { + Log.w("TextureView", "A TextureView or a subclass can only be " + + "used with hardware acceleration enabled."); + } + } + + /** + * The layer type of a TextureView is ignored since a TextureView is always + * considered to act as a hardware layer. The optional paint supplied to this + * method will however be taken into account when rendering the content of + * this TextureView. + * + * @param layerType The ype of layer to use with this view, must be one of + * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or + * {@link #LAYER_TYPE_HARDWARE} + * @param paint The paint used to compose the layer. This argument is optional + * and can be null. It is ignored when the layer type is + * {@link #LAYER_TYPE_NONE} + */ + @Override + public void setLayerType(int layerType, Paint paint) { + if (paint != mLayerPaint) { + mLayerPaint = paint; + invalidate(); + } + } + + /** + * Always returns {@link #LAYER_TYPE_HARDWARE}. + */ + @Override + public int getLayerType() { + return LAYER_TYPE_HARDWARE; + } + + /** + * Calling this method has no effect. + */ + @Override + public void buildLayer() { + } + + /** + * Subclasses of TextureView cannot do their own rendering + * with the {@link Canvas} object. + * + * @param canvas The Canvas to which the View is rendered. + */ + @Override + public final void draw(Canvas canvas) { + super.draw(canvas); + } + + /** + * Subclasses of TextureView cannot do their own rendering + * with the {@link Canvas} object. + * + * @param canvas The Canvas to which the View is rendered. + */ + @Override + protected final void onDraw(Canvas canvas) { + } + + @Override + HardwareLayer getHardwareLayer() { + if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { + return null; + } + + if (mLayer == null) { + mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(); + mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer); + + mSurface.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { + @Override + public void onFrameAvailable(SurfaceTexture surfaceTexture) { + // Per SurfaceTexture's documentation, the callback may be invoked + // from an arbitrary thread + post(mUpdateLayerAction); + } + }); + + if (mListener != null) { + mListener.onSurfaceTextureAvailable(mSurface); + } + } + + return mLayer; + } + + private void updateLayer() { + if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { + return; + } + + mSurface.updateTexImage(); + mSurface.getTransformMatrix(mTextureTransform); + + mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), + mTextureTransform); + + invalidate(); + } + + /** + * Returns the {@link SurfaceTexture} used by this view. This method + * may return null if the view is not attached to a window. + */ + public SurfaceTexture getSurfaceTexture() { + return mSurface; + } + + /** + * Returns the {@link SurfaceTextureListener} currently associated with this + * texture view. + * + * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener) + * @see SurfaceTextureListener + */ + public SurfaceTextureListener getSurfaceTextureListener() { + return mListener; + } + + /** + * Sets the {@link SurfaceTextureListener} used to listen to surface + * texture events. + * + * @see #getSurfaceTextureListener() + * @see SurfaceTextureListener + */ + public void setSurfaceTextureListener(SurfaceTextureListener listener) { + mListener = listener; + } + + /** + * This listener can be used to be notified when the surface texture + * associated with this texture view is available. + */ + public static interface SurfaceTextureListener { + /** + * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use. + * + * @param surface The surface returned by + * {@link android.view.TextureView#getSurfaceTexture()} + */ + public void onSurfaceTextureAvailable(SurfaceTexture surface); + } +} diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 314c2ee3b1767..af7639a541d83 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -539,6 +539,19 @@ static OpenGLRenderer* android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env return NULL; } +static Layer* android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject clazz, + jintArray layerInfo) { + Layer* layer = LayerRenderer::createTextureLayer(); + + if (layer) { + jint* storage = env->GetIntArrayElements(layerInfo, NULL); + storage[0] = layer->texture; + env->ReleaseIntArrayElements(layerInfo, storage, 0); + } + + return layer; +} + static Layer* android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz, jint width, jint height, jboolean isOpaque, jintArray layerInfo) { Layer* layer = LayerRenderer::createLayer(width, height, isOpaque); @@ -563,6 +576,13 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz, env->ReleaseIntArrayElements(layerInfo, storage, 0); } +static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz, + Layer* layer, jint width, jint height, jfloatArray texTransform) { + jfloat* transform = env->GetFloatArrayElements(texTransform, NULL); + LayerRenderer::updateTextureLayer(layer, width, height, transform); + env->ReleaseFloatArrayElements(texTransform, transform, 0); +} + static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, Layer* layer) { LayerRenderer::destroyLayer(layer); } @@ -696,6 +716,8 @@ static JNINativeMethod gMethods[] = { { "nCreateLayerRenderer", "(I)I", (void*) android_view_GLES20Canvas_createLayerRenderer }, { "nCreateLayer", "(IIZ[I)I", (void*) android_view_GLES20Canvas_createLayer }, { "nResizeLayer", "(III[I)V" , (void*) android_view_GLES20Canvas_resizeLayer }, + { "nCreateTextureLayer", "([I)I", (void*) android_view_GLES20Canvas_createTextureLayer }, + { "nUpdateTextureLayer", "(III[F)V" , (void*) android_view_GLES20Canvas_updateTextureLayer }, { "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer }, { "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred }, { "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer }, diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 6c4a2a9a972dd..16566b80164d5 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -45,6 +45,8 @@ struct Layer { mesh = NULL; meshIndices = NULL; meshElementCount = 0; + isCacheable = true; + isTextureLayer = false; } ~Layer() { @@ -137,6 +139,22 @@ struct Layer { TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; + + /** + * If set to true (by default), the layer can be reused. + */ + bool isCacheable; + + /** + * When set to true, this layer must be treated as a texture + * layer. + */ + bool isTextureLayer; + + /** + * Optional texture coordinates transform. + */ + mat4 texTransform; }; // struct Layer }; // namespace uirenderer diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index a9710ad6adbfc..b2d795f3516ba 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -154,6 +154,8 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh } bool LayerCache::put(Layer* layer) { + if (!layer->isCacheable) return false; + const uint32_t size = layer->width * layer->height * 4; // Don't even try to cache a layer that's bigger than the cache if (size < mMaxSize) { diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index ca1e7ae0027bc..e167336c8657f 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -20,6 +20,7 @@ #include "LayerCache.h" #include "LayerRenderer.h" +#include "Matrix.h" #include "Properties.h" #include "Rect.h" @@ -165,6 +166,40 @@ void LayerRenderer::generateMesh() { // Layers management /////////////////////////////////////////////////////////////////////////////// +Layer* LayerRenderer::createTextureLayer() { + LAYER_RENDERER_LOGD("Creating new texture layer"); + + Layer* layer = new Layer(0, 0); + layer->isCacheable = false; + layer->isTextureLayer = true; + layer->blend = true; + layer->empty = true; + layer->fbo = 0; + layer->colorFilter = NULL; + layer->fbo = 0; + layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); + layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f); + layer->alpha = 255; + layer->mode = SkXfermode::kSrcOver_Mode; + layer->colorFilter = NULL; + layer->region.clear(); + + glActiveTexture(GL_TEXTURE0); + + glGenTextures(1, &layer->texture); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, layer->texture); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + return layer; +} + Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height); @@ -244,6 +279,18 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { return true; } +void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, + float* transform) { + if (layer) { + layer->width = width; + layer->height = height; + layer->layer.set(0.0f, 0.0f, width, height); + layer->region.set(width, height); + layer->regionRect.set(0.0f, 0.0f, width, height); + layer->texTransform.load(transform); + } +} + void LayerRenderer::destroyLayer(Layer* layer) { if (layer) { LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo); diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index d2f565e4f3074..b3cd5db4fbe2c 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -53,8 +53,11 @@ public: Region* getRegion(); GLint getTargetFbo(); + static Layer* createTextureLayer(); static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false); static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); + static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, + float* transform); static void destroyLayer(Layer* layer); static void destroyLayerDeferred(Layer* layer); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index ea42838972732..34d8fd31e206d 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -633,15 +633,43 @@ void OpenGLRenderer::composeLayer(sp