summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/Android.common.mk6
-rw-r--r--libs/hwui/CanvasState.h5
-rw-r--r--libs/hwui/DeferredDisplayList.cpp4
-rw-r--r--libs/hwui/DisplayListCanvas.cpp29
-rw-r--r--libs/hwui/DisplayListCanvas.h2
-rw-r--r--libs/hwui/DisplayListOp.h17
-rw-r--r--libs/hwui/FrameInfoVisualizer.cpp1
-rw-r--r--libs/hwui/GlopBuilder.cpp31
-rw-r--r--libs/hwui/OpenGLRenderer.cpp36
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h16
-rw-r--r--libs/hwui/RenderNode.cpp73
-rw-r--r--libs/hwui/RenderNode.h4
-rw-r--r--libs/hwui/RenderProperties.cpp19
-rw-r--r--libs/hwui/RenderProperties.h42
-rw-r--r--libs/hwui/TextureCache.cpp10
-rw-r--r--libs/hwui/TextureCache.h5
16 files changed, 207 insertions, 93 deletions
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index a5bfde7..9590595 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -118,5 +118,9 @@ endif
# Defaults for ATRACE_TAG and LOG_TAG for libhwui
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
+LOCAL_CFLAGS += -Wall -Wno-unused-parameter -Wunreachable-code
-LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter -Wunreachable-code
+# b/21698669
+ifneq ($(USE_CLANG_PLATFORM_BUILD),true)
+ LOCAL_CFLAGS += -Werror
+endif
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index 9354e94..b35db28 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -155,8 +155,9 @@ public:
inline bool currentlyIgnored() const { return currentSnapshot()->isIgnored(); }
int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
- int getWidth() { return mWidth; }
- int getHeight() { return mHeight; }
+ int getWidth() const { return mWidth; }
+ int getHeight() const { return mHeight; }
+ bool clipIsSimple() const { return currentSnapshot()->clipIsSimple(); }
inline const Snapshot* currentSnapshot() const {
return mSnapshot != nullptr ? mSnapshot.get() : mFirstSnapshot.get();
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index b077a85..f05857c 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -494,7 +494,9 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
// complex clip has a complex set of expectations on the renderer state - for now, avoid taking
// the merge path in those cases
deferInfo.mergeable &= !recordingComplexClip();
- deferInfo.opaqueOverBounds &= !recordingComplexClip() && mSaveStack.isEmpty();
+ deferInfo.opaqueOverBounds &= !recordingComplexClip()
+ && mSaveStack.isEmpty()
+ && !state->mRoundRectClipState;
if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() &&
state->mClipSideFlags != kClipSide_ConservativeFull &&
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index cbb6fd5..843c412 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -203,10 +203,10 @@ bool DisplayListCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) {
LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
-
- // dirty is an out parameter and should not be recorded,
- // it matters only when replaying the display list
- DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, *mState.currentTransform());
+ DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(
+ renderNode,
+ *mState.currentTransform(),
+ mState.clipIsSimple());
addRenderNodeOp(op);
}
@@ -352,6 +352,7 @@ void DisplayListCanvas::drawRoundRect(
mDisplayListData->ref(rx);
mDisplayListData->ref(ry);
mDisplayListData->ref(paint);
+ refBitmapsInShader(paint->value.getShader());
addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value,
&right->value, &bottom->value, &rx->value, &ry->value, &paint->value));
}
@@ -366,6 +367,7 @@ void DisplayListCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPri
mDisplayListData->ref(y);
mDisplayListData->ref(radius);
mDisplayListData->ref(paint);
+ refBitmapsInShader(paint->value.getShader());
addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
&radius->value, &paint->value));
}
@@ -565,5 +567,24 @@ size_t DisplayListCanvas::addRenderNodeOp(DrawRenderNodeOp* op) {
return opIndex;
}
+void DisplayListCanvas::refBitmapsInShader(const SkShader* shader) {
+ if (!shader) return;
+
+ // If this paint has an SkShader that has an SkBitmap add
+ // it to the bitmap pile
+ SkBitmap bitmap;
+ SkShader::TileMode xy[2];
+ if (shader->asABitmap(&bitmap, nullptr, xy) == SkShader::kDefault_BitmapType) {
+ refBitmap(bitmap);
+ return;
+ }
+ SkShader::ComposeRec rec;
+ if (shader->asACompose(&rec)) {
+ refBitmapsInShader(rec.fShaderA);
+ refBitmapsInShader(rec.fShaderB);
+ return;
+ }
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index d997ef4..edfda62 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -263,6 +263,7 @@ private:
size_t addDrawOp(DrawOp* op);
size_t addRenderNodeOp(DrawRenderNodeOp* op);
+ void refBitmapsInShader(const SkShader* shader);
template<class T>
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
@@ -311,6 +312,7 @@ private:
// replaceValueFor() performs an add if the entry doesn't exist
mPaintMap.replaceValueFor(key, cachedPaint);
+ refBitmapsInShader(cachedPaint->getShader());
}
return cachedPaint;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index e9d6ebc..fb2852a 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1398,9 +1398,10 @@ class DrawRenderNodeOp : public DrawBoundedOp {
friend class RenderNode; // grant RenderNode access to info of child
friend class DisplayListData; // grant DisplayListData access to info of child
public:
- DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent)
+ DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple)
: DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
, mRenderNode(renderNode)
+ , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple())
, mTransformFromParent(transformFromParent)
, mSkipInOrderDraw(false) {}
@@ -1436,6 +1437,20 @@ public:
private:
RenderNode* mRenderNode;
+ /**
+ * This RenderNode was drawn into a DisplayList with the canvas in a state that will likely
+ * require rendering with stencil clipping. Either:
+ *
+ * 1) A path clip or rotated rect clip was in effect on the canvas at record time
+ * 2) The RenderNode was recorded with a non-simple canvas transform (e.g. rotation)
+ *
+ * Note: even if this is false, non-rect clipping may still be applied applied either due to
+ * property-driven rotation (either in this RenderNode, or any ancestor), or record time
+ * clipping in an ancestor. These are handled in RenderNode::prepareTreeImpl since they are
+ * dynamic (relative to a static DisplayList of a parent), and don't affect this flag.
+ */
+ bool mRecordedWithPotentialStencilClip;
+
///////////////////////////
// Properties below are used by RenderNode::computeOrderingImpl() and issueOperations()
///////////////////////////
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index 5b81ac9..7f9d9b9 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -28,7 +28,6 @@
#define PROFILE_DRAW_DP_PER_MS 7
// Must be NUM_ELEMENTS in size
-static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d;
static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
static const SkColor BAR_FAST_ALPHA = 0x8F000000;
static const SkColor BAR_JANKY_ALPHA = 0xDF000000;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index b7cdaa2..288fed3 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -29,8 +29,9 @@
#include <GLES2/gl2.h>
#include <SkPaint.h>
-namespace android {
-namespace uirenderer {
+#define DEBUG_GLOP_BUILDER 0
+
+#if DEBUG_GLOP_BUILDER
#define TRIGGER_STAGE(stageFlag) \
LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
@@ -40,6 +41,16 @@ namespace uirenderer {
LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
"not prepared for current stage")
+#else
+
+#define TRIGGER_STAGE(stageFlag) ((void)0)
+#define REQUIRE_STAGES(requiredFlags) ((void)0)
+
+#endif
+
+namespace android {
+namespace uirenderer {
+
static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
quadVertex[0] = {0, 0, uvs.left, uvs.top};
quadVertex[1] = {1, 0, uvs.right, uvs.top};
@@ -301,7 +312,7 @@ void GlopBuilder::setFill(int color, float alphaScale,
GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
const int textureFillFlags, const SkPaint* paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter)
? GL_LINEAR : PaintUtils::getFilter(paint);
@@ -345,7 +356,7 @@ GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
@@ -359,7 +370,7 @@ GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
//specify invalid filter/clamp, since these are always static for PathTextures
mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
@@ -376,7 +387,7 @@ GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
//specify invalid filter/clamp, since these are always static for ShadowTextures
mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
@@ -399,7 +410,7 @@ GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int
GlopBuilder& GlopBuilder::setFillBlack() {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
@@ -409,7 +420,7 @@ GlopBuilder& GlopBuilder::setFillBlack() {
GlopBuilder& GlopBuilder::setFillClear() {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, Blend::ModeOrderSwap::NoSwap,
@@ -420,7 +431,7 @@ GlopBuilder& GlopBuilder::setFillClear() {
GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { &texture,
GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
@@ -434,7 +445,7 @@ GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* co
GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { &(layer.getTexture()),
layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5769376..433e178 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -847,11 +847,11 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
&& layer->getHeight() == (uint32_t) rect.getHeight();
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
.setFillTextureLayer(*layer, getLayerAlpha(layer))
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -859,12 +859,12 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
void OpenGLRenderer::composeLayerRectSwapped(Layer* layer, const Rect& rect) {
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(nullptr, layer->texCoords)
.setFillLayer(layer->getTexture(), layer->getColorFilter(),
getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::Swap)
.setTransform(*currentSnapshot(), TransformFlags::MeshIgnoresCanvasTransform)
.setModelViewMapUnitToRect(rect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -880,11 +880,11 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect) {
&& layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(nullptr, layer->texCoords)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1021,11 +1021,11 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
Rect modelRect = Rect(rect.getWidth(), rect.getHeight());
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRectSnap(rect.left, rect.top, modelRect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
@@ -1140,11 +1140,11 @@ void OpenGLRenderer::clearLayerRegions() {
const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(nullptr) // clear ignores clip state
.setMeshIndexedQuads(&mesh[0], quadCount)
.setFillClear()
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop, false);
@@ -1330,11 +1330,11 @@ void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
Glop glop;
Vertex* vertices = &rectangleVertices[0];
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshIndexedQuads(vertices, rectangleVertices.size() / 4)
.setFillBlack()
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, scissorBox)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1534,11 +1534,11 @@ void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entr
const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedMesh(vertices, bitmapCount * 6)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1557,11 +1557,11 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUnitQuad(texture->uvMapper)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1647,11 +1647,11 @@ void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int m
const int textureFillFlags = TextureFillFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshColoredTexturedMesh(mesh.get(), elementCount)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1676,11 +1676,11 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, cons
&& MathUtils::areEqual(src.getHeight(), dst.getHeight());
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(texture->uvMapper, uv)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, dst)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1702,11 +1702,11 @@ void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
}
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshPatchQuads(*mesh)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1732,11 +1732,11 @@ void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entr
}
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedIndexedQuads(vertices, elementCount)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1753,11 +1753,11 @@ void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
const int transformFlags = TransformFlags::OffsetByFudgeFactor;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshVertexBuffer(vertexBuffer, shadowInterp)
.setFillPaint(*paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2039,11 +2039,11 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
.setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2364,11 +2364,11 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
} else if (layer->mesh) {
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
#if DEBUG_LAYERS_AS_REGIONS
@@ -2422,11 +2422,11 @@ void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
.setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2560,11 +2560,11 @@ void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint
? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshIndexedQuads(&mesh[0], count / 4)
.setFillPaint(*paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2575,11 +2575,11 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshUnitQuad()
.setFillPaint(*paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewMapUnitToRect(Rect(left, top, right, bottom))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 29fbf0c..5850dc6 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -524,22 +524,6 @@ protected:
inline float getLayerAlpha(const Layer* layer) const;
/**
- * Safely retrieves the ColorFilter from the given Paint. If the paint is
- * null then null is returned.
- */
- static inline SkColorFilter* getColorFilter(const SkPaint* paint) {
- return paint ? paint->getColorFilter() : nullptr;
- }
-
- /**
- * Safely retrieves the Shader from the given Paint. If the paint is
- * null then null is returned.
- */
- static inline const SkShader* getShader(const SkPaint* paint) {
- return paint ? paint->getShader() : nullptr;
- }
-
- /**
* Set to true to suppress error checks at the end of a frame.
*/
virtual bool suppressErrorChecks() const {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 7d3b41e..b4cbc36 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -83,11 +83,12 @@ void RenderNode::setStagingDisplayList(DisplayListData* data) {
* display list. This function should remain in sync with the replay() function.
*/
void RenderNode::output(uint32_t level) {
- ALOGD("%*sStart display list (%p, %s%s%s%s%s)", (level - 1) * 2, "", this,
+ ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this,
getName(),
(MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""),
(properties().hasShadow() ? ", casting shadow" : ""),
(isRenderable() ? "" : ", empty"),
+ (properties().getProjectBackwards() ? ", projected" : ""),
(mLayer != nullptr ? ", on HW Layer" : ""));
ALOGD("%*s%s %d", level * 2, "", "Save",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -119,7 +120,10 @@ void RenderNode::prepareTree(TreeInfo& info) {
ATRACE_CALL();
LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
- prepareTreeImpl(info);
+ // Functors don't correctly handle stencil usage of overdraw debugging - shove 'em in a layer.
+ bool functorsNeedLayer = Properties::debugOverdraw;
+
+ prepareTreeImpl(info, functorsNeedLayer);
}
void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
@@ -218,7 +222,15 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
}
}
-void RenderNode::prepareTreeImpl(TreeInfo& info) {
+/**
+ * Traverse down the the draw tree to prepare for a frame.
+ *
+ * MODE_FULL = UI Thread-driven (thus properties must be synced), otherwise RT driven
+ *
+ * While traversing down the tree, functorsNeedLayer flag is set to true if anything that uses the
+ * stencil buffer may be needed. Views that use a functor to draw will be forced onto a layer.
+ */
+void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
@@ -228,11 +240,17 @@ void RenderNode::prepareTreeImpl(TreeInfo& info) {
if (CC_LIKELY(info.runAnimations)) {
animatorDirtyMask = mAnimatorManager.animate(info);
}
+
+ bool willHaveFunctor = info.mode == TreeInfo::MODE_FULL && mStagingDisplayListData
+ ? !mStagingDisplayListData->functors.isEmpty() : !mDisplayListData->functors.isEmpty();
+ bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
+ willHaveFunctor, functorsNeedLayer);
+
prepareLayer(info, animatorDirtyMask);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingDisplayListChanges(info);
}
- prepareSubTree(info, mDisplayListData);
+ prepareSubTree(info, childFunctorsNeedLayer, mDisplayListData);
pushLayerUpdate(info);
info.damageAccumulator->popTransform();
@@ -312,7 +330,7 @@ void RenderNode::deleteDisplayListData() {
mDisplayListData = nullptr;
}
-void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
+void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayListData* subtree) {
if (subtree) {
TextureCache& cache = Caches::getInstance().textureCache;
info.out.hasFunctors |= subtree->functors.size();
@@ -323,7 +341,10 @@ void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
DrawRenderNodeOp* op = subtree->children()[i];
RenderNode* childNode = op->mRenderNode;
info.damageAccumulator->pushTransform(&op->mTransformFromParent);
- childNode->prepareTreeImpl(info);
+ bool childFunctorsNeedLayer = functorsNeedLayer
+ // Recorded with non-rect clip, or canvas-rotated by parent
+ || op->mRecordedWithPotentialStencilClip;
+ childNode->prepareTreeImpl(info, childFunctorsNeedLayer);
info.damageAccumulator->popTransform();
}
}
@@ -391,11 +412,27 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
if (isLayer) {
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
- LOG_ALWAYS_FATAL_IF(!isLayer && properties().getHasOverlappingRendering());
- renderer.scaleAlpha(properties().getAlpha());
+ if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) {
+ // simply scale rendering content's alpha
+ renderer.scaleAlpha(properties().getAlpha());
+ } else {
+ // savelayer needed to create an offscreen buffer
+ Rect layerBounds(0, 0, getWidth(), getHeight());
+ if (clipFlags) {
+ properties().getClippingRectForFlags(clipFlags, &layerBounds);
+ clipFlags = 0; // all clipping done by savelayer
+ }
+ SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
+ layerBounds.left, layerBounds.top,
+ layerBounds.right, layerBounds.bottom,
+ (int) (properties().getAlpha() * 255),
+ SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
+ handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ }
if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) {
- // pretend to cause savelayer to warn about performance problem affecting old versions
+ // pretend alpha always causes savelayer to warn about
+ // performance problem affecting old versions
ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(),
static_cast<int>(getWidth()),
static_cast<int>(getHeight()));
@@ -520,10 +557,10 @@ void RenderNode::computeOrderingImpl(
Vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
const mat4* projectionTransform = nullptr;
if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
- // if receiving projections, collect projecting descendent
+ // if receiving projections, collect projecting descendant
- // Note that if a direct descendent is projecting backwards, we pass it's
- // grandparent projection collection, since it shouldn't project onto it's
+ // Note that if a direct descendant is projecting backwards, we pass its
+ // grandparent projection collection, since it shouldn't project onto its
// parent, where it will already be drawing.
projectionOutline = properties().getOutline().getPath();
projectionChildren = &mProjectedNodes;
@@ -802,7 +839,8 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
template <class T>
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
if (mDisplayListData->isEmpty()) {
- DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
+ DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", handler.level() * 2, "",
+ this, getName());
return;
}
@@ -814,7 +852,8 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
if (useViewProperties) {
const Outline& outline = properties().getOutline();
if (properties().getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty())) {
- DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", level * 2, "", this, getName());
+ DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", handler.level() * 2, "",
+ this, getName());
return;
}
}
@@ -833,7 +872,7 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
PROPERTY_SAVECOUNT, properties().getClipToBounds());
- DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
+ DISPLAY_LIST_LOGD("%*sSave %d %d", (handler.level() + 1) * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
if (useViewProperties) {
@@ -880,11 +919,11 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
}
}
- DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
+ DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (handler.level() + 1) * 2, "", restoreTo);
handler(new (alloc) RestoreToCountOp(restoreTo),
PROPERTY_SAVECOUNT, properties().getClipToBounds());
- DISPLAY_LIST_LOGD("%*sDone (%p, %s)", level * 2, "", this, getName());
+ DISPLAY_LIST_LOGD("%*sDone (%p, %s)", handler.level() * 2, "", this, getName());
handler.endMark();
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index d0d81d9..025a4a4 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -235,10 +235,10 @@ private:
const char* mText;
};
- void prepareTreeImpl(TreeInfo& info);
+ void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
void pushStagingDisplayListChanges(TreeInfo& info);
- void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
+ void prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayListData* subtree);
void applyLayerPropertiesToLayer(TreeInfo& info);
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info);
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 07b8ce6..4f6ef4e 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -152,7 +152,24 @@ void RenderProperties::debugOutputProperties(const int level) const {
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
- ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
+ if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
+ // simply scale rendering content's alpha
+ ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
+ } else {
+ // savelayeralpha to create an offscreen buffer to apply alpha
+ Rect layerBounds(0, 0, getWidth(), getHeight());
+ if (clipFlags) {
+ getClippingRectForFlags(clipFlags, &layerBounds);
+ clipFlags = 0; // all clipping done by savelayer
+ }
+ ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
+ (int)layerBounds.left, (int)layerBounds.top,
+ (int)layerBounds.right, (int)layerBounds.bottom,
+ (int)(mPrimitiveFields.mAlpha * 255),
+ SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
+ }
+
+
}
if (clipFlags) {
Rect clipRect;
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 98029a8..81cf2df 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -28,6 +28,7 @@
#include <SkRegion.h>
#include <SkXfermode.h>
+#include "Caches.h"
#include "Rect.h"
#include "RevealClip.h"
#include "Outline.h"
@@ -157,6 +158,32 @@ public:
}
}
+ /**
+ * Set internal layer state based on whether this layer
+ *
+ * Additionally, returns true if child RenderNodes with functors will need to use a layer
+ * to support clipping.
+ */
+ bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) {
+ // parent may have already dictated that a descendant layer is needed
+ bool functorsNeedLayer = ancestorDictatesFunctorsNeedLayer
+
+ // Round rect clipping forces layer for functors
+ || CC_UNLIKELY(getOutline().willClip())
+ || CC_UNLIKELY(getRevealClip().willClip())
+
+ // Complex matrices forces layer, due to stencil clipping
+ || CC_UNLIKELY(getTransformMatrix() && !getTransformMatrix()->isScaleTranslate())
+ || CC_UNLIKELY(getAnimationMatrix() && !getAnimationMatrix()->isScaleTranslate())
+ || CC_UNLIKELY(getStaticMatrix() && !getStaticMatrix()->isScaleTranslate());
+
+ mComputedFields.mNeedLayerForFunctors = (willHaveFunctor && functorsNeedLayer);
+
+ // If on a layer, will have consumed the need for isolating functors from stencil.
+ // Thus, it's safe to reset the flag until some descendent sets it.
+ return CC_LIKELY(effectiveLayerType() == LayerType::None) && functorsNeedLayer;
+ }
+
RenderProperties& operator=(const RenderProperties& other);
bool setClipToBounds(bool clipToBounds) {
@@ -577,14 +604,18 @@ public:
}
bool promotedToLayer() const {
+ const int maxTextureSize = Caches::getInstance().maxTextureSize;
return mLayerProperties.mType == LayerType::None
- && !MathUtils::isZero(mPrimitiveFields.mAlpha)
- && mPrimitiveFields.mAlpha < 1
- && mPrimitiveFields.mHasOverlappingRendering;
+ && mPrimitiveFields.mWidth <= maxTextureSize
+ && mPrimitiveFields.mHeight <= maxTextureSize
+ && (mComputedFields.mNeedLayerForFunctors
+ || (!MathUtils::isZero(mPrimitiveFields.mAlpha)
+ && mPrimitiveFields.mAlpha < 1
+ && mPrimitiveFields.mHasOverlappingRendering));
}
LayerType effectiveLayerType() const {
- return promotedToLayer() ? LayerType::RenderLayer : mLayerProperties.mType;
+ return CC_UNLIKELY(promotedToLayer()) ? LayerType::RenderLayer : mLayerProperties.mType;
}
private:
@@ -632,6 +663,9 @@ private:
SkMatrix* mTransformMatrix;
Sk3DView mTransformCamera;
+
+ // Force layer on for functors to enable render features they don't yet support (clipping)
+ bool mNeedLayerForFunctors = false;
} mComputedFields;
};
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index e59688c..5147e98 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -215,16 +215,6 @@ Texture* TextureCache::get(const SkBitmap* bitmap) {
return texture;
}
-Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
- Texture* texture = new Texture(Caches::getInstance());
- texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
- texture->cleanup = true;
-
- generateTexture(bitmap, texture, false);
-
- return texture;
-}
-
void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
Mutex::Autolock _l(mLock);
mGarbage.push(pixelRefStableID);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index a2c6380..e7fc990 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -80,11 +80,6 @@ public:
* cannot be found in the cache, a new texture is generated.
*/
Texture* get(const SkBitmap* bitmap);
- /**
- * Returns the texture associated with the specified bitmap. The generated
- * texture is not kept in the cache. The caller must destroy the texture.
- */
- Texture* getTransient(const SkBitmap* bitmap);
/**
* Removes the texture associated with the specified pixelRef. This is meant