Enable changing properties of layer paint
Previously, to draw a layered view with a changed Paint object for the
drawLayer operation, you'd have to invalidate the parent view, to get the
native DisplayList to pick up the new Paint properties. This change adds
API and functionality so that the developer can call setLayerPaint(), which
does the proper invalidation (lightweight, doesn't cause redrawing the view).
Issue #6923810 Make it easy to efficiently animate a layer's Paint
Change-Id: I7fea79788d50f6d9c86dd5e5b2a4490cb95142bb
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 @@
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 2de70d462..3e3121e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -1004,29 +1004,39 @@
}
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 @@
* 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 @@
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 @@
texture.height = height;
}
+ ANDROID_API void setPaint(SkPaint* paint);
+
inline void setBlend(bool blend) {
texture.blend = blend;
}
@@ -191,9 +191,7 @@
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 @@
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 @@
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 @@
*/
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 @@
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.
*/