diff options
-rw-r--r-- | api/current.txt | 1 | ||||
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 11 | ||||
-rw-r--r-- | core/java/android/view/GLES20Layer.java | 10 | ||||
-rw-r--r-- | core/java/android/view/HardwareLayer.java | 9 | ||||
-rw-r--r-- | core/java/android/view/TextureView.java | 1 | ||||
-rw-r--r-- | core/java/android/view/View.java | 49 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 51 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 12 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 12 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 52 |
13 files changed, 189 insertions, 52 deletions
diff --git a/api/current.txt b/api/current.txt index 7ad9cad..161909c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25027,6 +25027,7 @@ package android.view { method public void setId(int); method public void setImportantForAccessibility(int); method public void setKeepScreenOn(boolean); + method public void setLayerPaint(android.graphics.Paint); method public void setLayerType(int, android.graphics.Paint); method public void setLayoutDirection(int); method public void setLayoutParams(android.view.ViewGroup.LayoutParams); diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index f4ab133..869cd00 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -152,6 +152,8 @@ class GLES20Canvas extends HardwareCanvas { 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 nSetOpaqueLayer(int layerId, boolean isOpaque); + static native void nSetLayerPaint(int layerId, int nativePaint); + static native void nSetLayerColorFilter(int layerId, int nativeColorFilter); static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque, SurfaceTexture surface); static native void nSetTextureLayerTransform(int layerId, int matrix); @@ -394,13 +396,8 @@ class GLES20Canvas extends HardwareCanvas { void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) { final GLES20Layer glLayer = (GLES20Layer) layer; - int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE; - try { - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint); - } finally { - if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); - } + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint); } private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint); diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java index a0ae379..a462ed6 100644 --- a/core/java/android/view/GLES20Layer.java +++ b/core/java/android/view/GLES20Layer.java @@ -18,6 +18,7 @@ package android.view; import android.graphics.Bitmap; +import android.graphics.Paint; /** * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. @@ -43,6 +44,15 @@ abstract class GLES20Layer extends HardwareLayer { } @Override + void setLayerPaint(Paint paint) { + if (paint != null) { + GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint); + GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ? + paint.getColorFilter().nativeColorFilter : 0); + } + } + + @Override boolean copyInto(Bitmap bitmap) { return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap); } diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index 06c6e7c..6e763b2 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -19,6 +19,7 @@ package android.view; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.Rect; /** @@ -62,6 +63,14 @@ abstract class HardwareLayer { } /** + * Update the paint used when drawing this layer. + * + * @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 diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index fe14c88..7e335f0 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -367,6 +367,7 @@ public class TextureView extends View { if (mListener != null && !mUpdateSurface) { mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight()); } + mLayer.setLayerPaint(mLayerPaint); } if (mUpdateSurface) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d268fd2..236adab 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -11932,13 +11932,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by * this view's alpha value. Calling {@link #setAlpha(float)} is therefore * equivalent to setting a hardware layer on this view and providing a paint with - * the desired alpha value.<p> + * the desired alpha value.</p> * * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled}, * {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware} * for more information on when and how to use layers.</p> * - * @param layerType The ype of layer to use with this view, must be one of + * @param layerType The type 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 @@ -11990,6 +11990,50 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Updates the {@link Paint} object used with the current layer (used only if the current + * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint + * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time + * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to + * ensure that the view gets redrawn immediately. + * + * <p>A layer is associated with an optional {@link android.graphics.Paint} + * instance that controls how the layer is composed on screen. The following + * properties of the paint are taken into account when composing the layer:</p> + * <ul> + * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> + * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> + * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> + * </ul> + * + * <p>If this view has an alpha value set to < 1.0 by calling + * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by + * this view's alpha value. Calling {@link #setAlpha(float)} is therefore + * equivalent to setting a hardware layer on this view and providing a paint with + * the desired alpha value.</p> + * + * @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} + * + * @see #setLayerType(int, android.graphics.Paint) + */ + public void setLayerPaint(Paint paint) { + int layerType = getLayerType(); + if (layerType != LAYER_TYPE_NONE) { + mLayerPaint = paint == null ? new Paint() : paint; + if (layerType == LAYER_TYPE_HARDWARE) { + HardwareLayer layer = getHardwareLayer(); + if (layer != null) { + layer.setLayerPaint(paint); + } + invalidateViewProperty(false, false); + } else { + invalidate(); + } + } + } + + /** * Indicates whether this view has a static layer. A view with layer type * {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are * dynamic. @@ -12101,6 +12145,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!mHardwareLayer.isValid()) { return null; } + mHardwareLayer.setLayerPaint(mLayerPaint); mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect); mLocalDirtyRect.setEmpty(); diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 3538fef..7dbf9ec 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -776,6 +776,20 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz, env->ReleaseIntArrayElements(layerInfo, storage, 0); } +static void android_view_GLES20Canvas_setLayerPaint(JNIEnv* env, jobject clazz, + Layer* layer, SkPaint* paint) { + if (layer) { + layer->setPaint(paint); + } +} + +static void android_view_GLES20Canvas_setLayerColorFilter(JNIEnv* env, jobject clazz, + Layer* layer, SkiaColorFilter* colorFilter) { + if (layer) { + layer->setColorFilter(colorFilter); + } +} + static void android_view_GLES20Canvas_setOpaqueLayer(JNIEnv* env, jobject clazz, Layer* layer, jboolean isOpaque) { if (layer) { @@ -979,6 +993,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 }, + { "nSetLayerPaint", "(II)V", (void*) android_view_GLES20Canvas_setLayerPaint }, + { "nSetLayerColorFilter", "(II)V", (void*) android_view_GLES20Canvas_setLayerColorFilter }, { "nSetOpaqueLayer", "(IZ)V", (void*) android_view_GLES20Canvas_setOpaqueLayer }, { "nCreateTextureLayer", "(Z[I)I", (void*) android_view_GLES20Canvas_createTextureLayer }, { "nUpdateTextureLayer", "(IIIZLandroid/graphics/SurfaceTexture;)V", diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index c0f79df..e032ae4 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -16,6 +16,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) Dither.cpp \ FboCache.cpp \ GradientCache.cpp \ + Layer.cpp \ LayerCache.cpp \ LayerRenderer.cpp \ Matrix.cpp \ diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 2de70d4..3e3121e 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -1004,29 +1004,39 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag } break; case DrawLayer: { + int oldAlpha = -1; Layer* layer = (Layer*) getInt(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); - if (mCaching) { - paint->setAlpha(mMultipliedAlpha); + if (mCaching && mMultipliedAlpha < 255) { + oldAlpha = layer->getAlpha(); + layer->setAlpha(mMultipliedAlpha); } DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], layer, x, y, paint); drawGlStatus |= renderer.drawLayer(layer, x, y, paint); + if (oldAlpha >= 0) { + layer->setAlpha(oldAlpha); + } } break; case DrawBitmap: { + int oldAlpha = -1; SkBitmap* bitmap = getBitmap(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); - if (mCaching) { + if (mCaching && mMultipliedAlpha < 255) { + oldAlpha = paint->getAlpha(); paint->setAlpha(mMultipliedAlpha); } DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], bitmap, x, y, paint); drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint); + if (oldAlpha >= 0) { + paint->setAlpha(oldAlpha); + } } break; case DrawBitmapMatrix: { diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp new file mode 100644 index 0000000..31e169b --- /dev/null +++ b/libs/hwui/Layer.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 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 <utils/Log.h> + +#include "Layer.h" +#include "OpenGLRenderer.h" +#include "Caches.h" + +namespace android { +namespace uirenderer { + +Layer::~Layer() { + if (mesh) delete mesh; + if (meshIndices) delete meshIndices; + if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter); +} + +void Layer::setPaint(SkPaint* paint) { + OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode); +} + +void Layer::setColorFilter(SkiaColorFilter* filter) { + if (colorFilter) { + Caches::getInstance().resourceCache.decrementRefcount(colorFilter); + } + colorFilter = filter; + if (colorFilter) { + Caches::getInstance().resourceCache.incrementRefcount(colorFilter); + } +} + + + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index f243177..76da671 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -45,6 +45,7 @@ class DisplayList; * A layer has dimensions and is backed by an OpenGL texture or FBO. */ struct Layer { + Layer(const uint32_t layerWidth, const uint32_t layerHeight) { mesh = NULL; meshIndices = NULL; @@ -60,10 +61,7 @@ struct Layer { displayList = NULL; } - ~Layer() { - if (mesh) delete mesh; - if (meshIndices) delete meshIndices; - } + ~Layer(); /** * Sets this layer's region to a rectangle. Computes the appropriate @@ -106,6 +104,8 @@ struct Layer { texture.height = height; } + ANDROID_API void setPaint(SkPaint* paint); + inline void setBlend(bool blend) { texture.blend = blend; } @@ -191,9 +191,7 @@ struct Layer { return colorFilter; } - inline void setColorFilter(SkiaColorFilter* filter) { - colorFilter = filter; - } + ANDROID_API void setColorFilter(SkiaColorFilter* filter); inline void bindTexture() { glBindTexture(renderTarget, texture.id); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index b66c898..05c7809 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2593,17 +2593,13 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain mCaches.activeTexture(0); - int alpha; - SkXfermode::Mode mode; - getAlphaAndMode(paint, &alpha, &mode); - - layer->setAlpha(alpha, mode); - if (CC_LIKELY(!layer->region.isEmpty())) { if (layer->region.isRect()) { composeLayerRect(layer, layer->regionRect); } else if (layer->mesh) { - const float a = alpha / 255.0f; + const float a = layer->getAlpha() / 255.0f; + SkiaColorFilter *oldFilter = mColorFilter; + mColorFilter = layer->getColorFilter(); setupDraw(); setupDrawWithTexture(); @@ -2633,6 +2629,8 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain finishDrawTexture(); + mColorFilter = oldFilter; + #if DEBUG_LAYERS_AS_REGIONS drawRegionRects(layer->region); #endif diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index f2b5f0a..7f9405f 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -227,6 +227,32 @@ public: */ void endMark() const; + /** + * Gets the alpha and xfermode out of a paint object. If the paint is null + * alpha will be 255 and the xfermode will be SRC_OVER. This method does + * not multiply the paint's alpha by the current snapshot's alpha. + * + * @param paint The paint to extract values from + * @param alpha Where to store the resulting alpha + * @param mode Where to store the resulting xfermode + */ + static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { + if (paint) { + *mode = getXfermode(paint->getXfermode()); + + // Skia draws using the color's alpha channel if < 255 + // Otherwise, it uses the paint's alpha + int color = paint->getColor(); + *alpha = (color >> 24) & 0xFF; + if (*alpha == 255) { + *alpha = paint->getAlpha(); + } + } else { + *mode = SkXfermode::kSrcOver_Mode; + *alpha = 255; + } + } + protected: /** * Compose the layer defined in the current snapshot with the layer @@ -291,32 +317,6 @@ protected: inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode); /** - * Gets the alpha and xfermode out of a paint object. If the paint is null - * alpha will be 255 and the xfermode will be SRC_OVER. This method does - * not multiply the paint's alpha by the current snapshot's alpha. - * - * @param paint The paint to extract values from - * @param alpha Where to store the resulting alpha - * @param mode Where to store the resulting xfermode - */ - static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { - if (paint) { - *mode = getXfermode(paint->getXfermode()); - - // Skia draws using the color's alpha channel if < 255 - // Otherwise, it uses the paint's alpha - int color = paint->getColor(); - *alpha = (color >> 24) & 0xFF; - if (*alpha == 255) { - *alpha = paint->getAlpha(); - } - } else { - *mode = SkXfermode::kSrcOver_Mode; - *alpha = 255; - } - } - - /** * Safely retrieves the mode from the specified xfermode. If the specified * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode. */ |