diff options
author | 2016-04-11 12:24:23 -0700 | |
---|---|---|
committer | 2016-04-11 12:32:41 -0700 | |
commit | d645640180c25c2711e99aa82ec629155f8e91ba (patch) | |
tree | d9b936f4d4bc5676dc0b7d6e0e2c8b87396609f7 | |
parent | a1544dd61457144969163d194c10d75bd7d251a9 (diff) |
Apply clip at reorder barriers to shadows
Fixes: 28004930
Change-Id: I208b78430c770a3135afd68c53cf8ff3fba50c52
-rw-r--r-- | libs/hwui/DisplayList.h | 3 | ||||
-rw-r--r-- | libs/hwui/FrameBuilder.cpp | 18 | ||||
-rw-r--r-- | libs/hwui/FrameBuilder.h | 5 | ||||
-rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/RecordingCanvas.h | 6 | ||||
-rw-r--r-- | libs/hwui/tests/unit/FrameBuilderTests.cpp | 29 | ||||
-rw-r--r-- | libs/hwui/tests/unit/RecordingCanvasTests.cpp | 30 |
7 files changed, 90 insertions, 12 deletions
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index e209e2a896fc..aba5d4bd218d 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -137,6 +137,9 @@ public: // whether children with non-zero Z in the chunk should be reordered bool reorderChildren; +#if HWUI_NEW_OPS + const ClipBase* reorderClip; +#endif }; DisplayList(); diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index f12e52325af1..6fc74a585659 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -269,7 +269,8 @@ static size_t findNonNegativeIndex(const V& zTranslatedNodes) { } template <typename V> -void FrameBuilder::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) { +void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode, + const V& zTranslatedNodes) { const int size = zTranslatedNodes.size(); if (size == 0 || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f) @@ -305,7 +306,7 @@ void FrameBuilder::defer3dChildren(ChildrenSelectMode mode, const V& zTranslated // attempt to render the shadow if the caster about to be drawn is its caster, // OR if its caster's Z value is similar to the previous potential caster if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) { - deferShadow(*casterNodeOp); + deferShadow(reorderClip, *casterNodeOp); lastCasterZ = casterZ; // must do this even if current caster not casting a shadow shadowIndex++; @@ -319,7 +320,7 @@ void FrameBuilder::defer3dChildren(ChildrenSelectMode mode, const V& zTranslated } } -void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) { +void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterNodeOp) { auto& node = *casterNodeOp.renderNode; auto& properties = node.properties(); @@ -365,6 +366,10 @@ void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) { casterPath = frameAllocatedPath; } + // apply reorder clip to shadow, so it respects clip at beginning of reorderable chunk + int restoreTo = mCanvasState.save(SaveFlags::MatrixClip); + mCanvasState.writableSnapshot()->applyClip(reorderClip, + *mCanvasState.currentSnapshot()->transform); if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) { Matrix4 shadowMatrixXY(casterNodeOp.localMatrix); Matrix4 shadowMatrixZ(casterNodeOp.localMatrix); @@ -386,6 +391,7 @@ void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) { currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow); } } + mCanvasState.restoreToCount(restoreTo); } void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) { @@ -438,11 +444,11 @@ void FrameBuilder::deferNodeOps(const RenderNode& renderNode) { // can't be null, since DL=null node rejection happens before deferNodePropsAndOps const DisplayList& displayList = *(renderNode.getDisplayList()); - for (const DisplayList::Chunk& chunk : displayList.getChunks()) { + for (auto& chunk : displayList.getChunks()) { FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; buildZSortedChildList(&zTranslatedNodes, displayList, chunk); - defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes); + defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Negative, zTranslatedNodes); for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { const RecordedOp* op = displayList.getOps()[opIndex]; receivers[op->opId](*this, *op); @@ -453,7 +459,7 @@ void FrameBuilder::deferNodeOps(const RenderNode& renderNode) { deferProjectedChildren(renderNode); } } - defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); + defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Positive, zTranslatedNodes); } } diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h index 039ab6bd88ab..a6fd7616ffcb 100644 --- a/libs/hwui/FrameBuilder.h +++ b/libs/hwui/FrameBuilder.h @@ -193,9 +193,10 @@ private: void deferNodePropsAndOps(RenderNode& node); template <typename V> - void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes); + void defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode, + const V& zTranslatedNodes); - void deferShadow(const RenderNodeOp& casterOp); + void deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterOp); void deferProjectedChildren(const RenderNode& renderNode); diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index b78497d6b6fc..ab733f138b25 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -57,6 +57,16 @@ DisplayList* RecordingCanvas::finishRecording() { return displayList; } +void RecordingCanvas::insertReorderBarrier(bool enableReorder) { + if (enableReorder) { + mDeferredBarrierType = DeferredBarrierType::OutOfOrder; + mDeferredBarrierClip = getRecordedClip(); + } else { + mDeferredBarrierType = DeferredBarrierType::InOrder; + mDeferredBarrierClip = nullptr; + } +} + SkCanvas* RecordingCanvas::asSkCanvas() { LOG_ALWAYS_FATAL_IF(!mDisplayList, "attempting to get an SkCanvas when we are not recording!"); @@ -610,6 +620,7 @@ size_t RecordingCanvas::addOp(RecordedOp* op) { newChunk.beginOpIndex = insertIndex; newChunk.endOpIndex = insertIndex + 1; newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder); + newChunk.reorderClip = mDeferredBarrierClip; int nextChildIndex = mDisplayList->children.size(); newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index acb88e2dc305..219296c97bb6 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -55,10 +55,7 @@ public: // ---------------------------------------------------------------------------- // MISC HWUI OPERATIONS - TODO: CATEGORIZE // ---------------------------------------------------------------------------- - virtual void insertReorderBarrier(bool enableReorder) override { - mDeferredBarrierType = enableReorder - ? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder; - } + virtual void insertReorderBarrier(bool enableReorder) override; virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; virtual void drawRenderNode(RenderNode* renderNode) override; @@ -312,6 +309,7 @@ private: std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy; ResourceCache& mResourceCache; DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None; + const ClipBase* mDeferredBarrierClip = nullptr; DisplayList* mDisplayList = nullptr; bool mHighContrastText = false; SkAutoTUnref<SkDrawFilter> mDrawFilter; diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp index 98774391fd30..209a10483a8e 100644 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp @@ -1722,6 +1722,35 @@ RENDERTHREAD_TEST(FrameBuilder, shadowLayering) { EXPECT_EQ(4, renderer.getIndex()); } +RENDERTHREAD_TEST(FrameBuilder, shadowClipping) { + class ShadowClippingTestRenderer : public TestRendererBase { + public: + void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { + EXPECT_EQ(0, mIndex++); + EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipState->rect) + << "Shadow must respect pre-barrier canvas clip value."; + } + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_EQ(1, mIndex++); + } + }; + auto parent = TestUtils::createNode(0, 0, 100, 100, + [](RenderProperties& props, RecordingCanvas& canvas) { + // Apply a clip before the reorder barrier/shadow casting child is drawn. + // This clip must be applied to the shadow cast by the child. + canvas.clipRect(25, 25, 75, 75, SkRegion::kIntersect_Op); + canvas.insertReorderBarrier(true); + canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get()); + }); + + FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, + TestUtils::createSyncedNodeList(parent), + (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance()); + ShadowClippingTestRenderer renderer; + frameBuilder.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(2, renderer.getIndex()); +} + static void testProperty(std::function<void(RenderProperties&)> propSetupCallback, std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) { class PropertyTestRenderer : public TestRendererBase { diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index c49ff71c0af0..18171de250d0 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -603,6 +603,36 @@ TEST(RecordingCanvas, insertReorderBarrier) { EXPECT_TRUE(chunks[1].reorderChildren); } +TEST(RecordingCanvas, insertReorderBarrier_clip) { + auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { + // first chunk: no recorded clip + canvas.insertReorderBarrier(true); + canvas.drawRect(0, 0, 400, 400, SkPaint()); + + // second chunk: no recorded clip, since inorder region + canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op); + canvas.insertReorderBarrier(false); + canvas.drawRect(0, 0, 400, 400, SkPaint()); + + // third chunk: recorded clip + canvas.insertReorderBarrier(true); + canvas.drawRect(0, 0, 400, 400, SkPaint()); + }); + + auto chunks = dl->getChunks(); + ASSERT_EQ(3u, chunks.size()); + + EXPECT_TRUE(chunks[0].reorderChildren); + EXPECT_EQ(nullptr, chunks[0].reorderClip); + + EXPECT_FALSE(chunks[1].reorderChildren); + EXPECT_EQ(nullptr, chunks[1].reorderClip); + + EXPECT_TRUE(chunks[2].reorderChildren); + ASSERT_NE(nullptr, chunks[2].reorderClip); + EXPECT_EQ(Rect(200, 200), chunks[2].reorderClip->rect); +} + TEST(RecordingCanvas, refPaint) { SkPaint paint; |