Optimization of alpha with DisplayList properties
Some views (such as ImageView and TextView) handle non-opaque alpha
values directly. This was originally an optimization, but we can handle it faster
in many cases without this optimization when DisplayList properties are enabled.
Basically, if a view has non-overlapping rendering, we set the alpha value directly
on the renderer (the equivalent of setting it on the Paint object) and draw each
primitive with that alpha value. Doing it this way avoids re-creating DisplayLists
while getting the same speedup that onSetAlpha() used to get pre-DisplayList properties.
Change-Id: I0f7827f075d3b35093a882d4adbb300a1063c288
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f37bfd2..9f2bacd 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -112,6 +112,7 @@
mClipChildren = true;
mAlpha = 1;
mMultipliedAlpha = 255;
+ mHasOverlappingRendering = true;
mTranslationX = 0;
mTranslationY = 0;
mRotation = 0;
@@ -772,18 +773,23 @@
}
}
if (mAlpha < 1 && !mCaching) {
- // TODO: should be able to store the size of a DL at record time and not
- // have to pass it into this call. In fact, this information might be in the
- // location/size info that we store with the new native transform data.
- int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
- if (mClipChildren) {
- flags |= SkCanvas::kClipToLayer_SaveFlag;
+ if (!mHasOverlappingRendering) {
+ DISPLAY_LIST_LOGD("%s%s %.2f", indent, "SetAlpha", mAlpha);
+ renderer.setAlpha(mAlpha);
+ } else {
+ // TODO: should be able to store the size of a DL at record time and not
+ // have to pass it into this call. In fact, this information might be in the
+ // location/size info that we store with the new native transform data.
+ int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+ if (mClipChildren) {
+ flags |= SkCanvas::kClipToLayer_SaveFlag;
+ }
+ DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+ (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
+ mMultipliedAlpha, flags);
+ renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
+ mMultipliedAlpha, flags);
}
- DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
- (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
- mMultipliedAlpha, flags);
- renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
- mMultipliedAlpha, flags);
}
if (mClipChildren) {
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 38b0a6d..fe0c94d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -181,6 +181,10 @@
}
}
+ void setHasOverlappingRendering(bool hasOverlappingRendering) {
+ mHasOverlappingRendering = hasOverlappingRendering;
+ }
+
void setTranslationX(float translationX) {
if (translationX != mTranslationX) {
mTranslationX = translationX;
@@ -496,6 +500,7 @@
bool mClipChildren;
float mAlpha;
int mMultipliedAlpha;
+ bool mHasOverlappingRendering;
float mTranslationX, mTranslationY;
float mRotation, mRotationX, mRotationY;
float mScaleX, mScaleY;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 115787c..ec9b56b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1101,6 +1101,7 @@
void OpenGLRenderer::setupDrawColor(int color, int alpha) {
mColorA = alpha / 255.0f;
+ mColorA *= mSnapshot->alpha;
// Second divide of a by 255 is an optimization, allowing us to simply multiply
// the rgb values by a instead of also dividing by 255
const float a = mColorA / 255.0f;
@@ -2800,6 +2801,7 @@
*mode = SkXfermode::kSrcOver_Mode;
*alpha = 255;
}
+ *alpha *= mSnapshot->alpha;
}
SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b651904..ab137cc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -85,6 +85,10 @@
virtual int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags);
+ virtual void setAlpha(float alpha) {
+ mSnapshot->alpha = alpha;
+ }
+
virtual void translate(float dx, float dy);
virtual void rotate(float degrees);
virtual void scale(float sx, float sy);
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index de2c674..5d5961a 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -26,7 +26,7 @@
///////////////////////////////////////////////////////////////////////////////
Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
- invisible(false), empty(false) {
+ invisible(false), empty(false), alpha(1.0f) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
@@ -41,7 +41,7 @@
Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
flags(0), previous(s), layer(NULL), fbo(s->fbo),
invisible(s->invisible), empty(false),
- viewport(s->viewport), height(s->height) {
+ viewport(s->viewport), height(s->height), alpha(s->alpha) {
clipRegion = NULL;
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index b2bc879..30b03fc 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -208,6 +208,17 @@
*/
Region* region;
+ /**
+ * Current alpha value. This value is 1 by default, but may be set by a DisplayList which
+ * has translucent rendering in a non-overlapping View. This value will be used by
+ * the renderer to set the alpha in the current color being used for ensuing drawing
+ * operations. The value is inherited by child snapshots because the same value should
+ * be applied to descendents of the current DisplayList (for example, a TextView contains
+ * the base alpha value which should be applied to the child DisplayLists used for drawing
+ * the actual text).
+ */
+ float alpha;
+
private:
void ensureClipRegion();
void copyClipRectFromRegion();