diff options
Diffstat (limited to 'libs/hwui')
| -rw-r--r-- | libs/hwui/Android.common.mk | 6 | ||||
| -rw-r--r-- | libs/hwui/CanvasState.h | 5 | ||||
| -rw-r--r-- | libs/hwui/DeferredDisplayList.cpp | 4 | ||||
| -rw-r--r-- | libs/hwui/DisplayListCanvas.cpp | 29 | ||||
| -rw-r--r-- | libs/hwui/DisplayListCanvas.h | 2 | ||||
| -rw-r--r-- | libs/hwui/DisplayListOp.h | 17 | ||||
| -rw-r--r-- | libs/hwui/FrameInfoVisualizer.cpp | 1 | ||||
| -rw-r--r-- | libs/hwui/GlopBuilder.cpp | 31 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 36 | ||||
| -rwxr-xr-x | libs/hwui/OpenGLRenderer.h | 16 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.cpp | 73 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.h | 4 | ||||
| -rw-r--r-- | libs/hwui/RenderProperties.cpp | 19 | ||||
| -rw-r--r-- | libs/hwui/RenderProperties.h | 42 | ||||
| -rw-r--r-- | libs/hwui/TextureCache.cpp | 10 | ||||
| -rw-r--r-- | libs/hwui/TextureCache.h | 5 |
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 |
