Merge "Apply clip at reorder barriers to shadows" into nyc-dev
This commit is contained in:
@@ -137,6 +137,9 @@ public:
|
|||||||
|
|
||||||
// whether children with non-zero Z in the chunk should be reordered
|
// whether children with non-zero Z in the chunk should be reordered
|
||||||
bool reorderChildren;
|
bool reorderChildren;
|
||||||
|
#if HWUI_NEW_OPS
|
||||||
|
const ClipBase* reorderClip;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
DisplayList();
|
DisplayList();
|
||||||
|
|||||||
@@ -269,7 +269,8 @@ static size_t findNonNegativeIndex(const V& zTranslatedNodes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
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();
|
const int size = zTranslatedNodes.size();
|
||||||
if (size == 0
|
if (size == 0
|
||||||
|| (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
|
|| (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,
|
// 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
|
// OR if its caster's Z value is similar to the previous potential caster
|
||||||
if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) {
|
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
|
lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
|
||||||
shadowIndex++;
|
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& node = *casterNodeOp.renderNode;
|
||||||
auto& properties = node.properties();
|
auto& properties = node.properties();
|
||||||
|
|
||||||
@@ -365,6 +366,10 @@ void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
|
|||||||
casterPath = frameAllocatedPath;
|
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())) {
|
if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
|
||||||
Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
|
Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
|
||||||
Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
|
Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
|
||||||
@@ -386,6 +391,7 @@ void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
|
|||||||
currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
|
currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mCanvasState.restoreToCount(restoreTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
|
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
|
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
|
||||||
const DisplayList& displayList = *(renderNode.getDisplayList());
|
const DisplayList& displayList = *(renderNode.getDisplayList());
|
||||||
for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
|
for (auto& chunk : displayList.getChunks()) {
|
||||||
FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes;
|
FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes;
|
||||||
buildZSortedChildList(&zTranslatedNodes, displayList, chunk);
|
buildZSortedChildList(&zTranslatedNodes, displayList, chunk);
|
||||||
|
|
||||||
defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes);
|
defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Negative, zTranslatedNodes);
|
||||||
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
|
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
|
||||||
const RecordedOp* op = displayList.getOps()[opIndex];
|
const RecordedOp* op = displayList.getOps()[opIndex];
|
||||||
receivers[op->opId](*this, *op);
|
receivers[op->opId](*this, *op);
|
||||||
@@ -453,7 +459,7 @@ void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
|
|||||||
deferProjectedChildren(renderNode);
|
deferProjectedChildren(renderNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes);
|
defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Positive, zTranslatedNodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,9 +193,10 @@ private:
|
|||||||
void deferNodePropsAndOps(RenderNode& node);
|
void deferNodePropsAndOps(RenderNode& node);
|
||||||
|
|
||||||
template <typename V>
|
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);
|
void deferProjectedChildren(const RenderNode& renderNode);
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,16 @@ DisplayList* RecordingCanvas::finishRecording() {
|
|||||||
return displayList;
|
return displayList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecordingCanvas::insertReorderBarrier(bool enableReorder) {
|
||||||
|
if (enableReorder) {
|
||||||
|
mDeferredBarrierType = DeferredBarrierType::OutOfOrder;
|
||||||
|
mDeferredBarrierClip = getRecordedClip();
|
||||||
|
} else {
|
||||||
|
mDeferredBarrierType = DeferredBarrierType::InOrder;
|
||||||
|
mDeferredBarrierClip = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SkCanvas* RecordingCanvas::asSkCanvas() {
|
SkCanvas* RecordingCanvas::asSkCanvas() {
|
||||||
LOG_ALWAYS_FATAL_IF(!mDisplayList,
|
LOG_ALWAYS_FATAL_IF(!mDisplayList,
|
||||||
"attempting to get an SkCanvas when we are not recording!");
|
"attempting to get an SkCanvas when we are not recording!");
|
||||||
@@ -610,6 +620,7 @@ size_t RecordingCanvas::addOp(RecordedOp* op) {
|
|||||||
newChunk.beginOpIndex = insertIndex;
|
newChunk.beginOpIndex = insertIndex;
|
||||||
newChunk.endOpIndex = insertIndex + 1;
|
newChunk.endOpIndex = insertIndex + 1;
|
||||||
newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder);
|
newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder);
|
||||||
|
newChunk.reorderClip = mDeferredBarrierClip;
|
||||||
|
|
||||||
int nextChildIndex = mDisplayList->children.size();
|
int nextChildIndex = mDisplayList->children.size();
|
||||||
newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
|
newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
|
||||||
|
|||||||
@@ -55,10 +55,7 @@ public:
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// MISC HWUI OPERATIONS - TODO: CATEGORIZE
|
// MISC HWUI OPERATIONS - TODO: CATEGORIZE
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
virtual void insertReorderBarrier(bool enableReorder) override {
|
virtual void insertReorderBarrier(bool enableReorder) override;
|
||||||
mDeferredBarrierType = enableReorder
|
|
||||||
? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
|
virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
|
||||||
virtual void drawRenderNode(RenderNode* renderNode) override;
|
virtual void drawRenderNode(RenderNode* renderNode) override;
|
||||||
@@ -312,6 +309,7 @@ private:
|
|||||||
std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy;
|
std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy;
|
||||||
ResourceCache& mResourceCache;
|
ResourceCache& mResourceCache;
|
||||||
DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None;
|
DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None;
|
||||||
|
const ClipBase* mDeferredBarrierClip = nullptr;
|
||||||
DisplayList* mDisplayList = nullptr;
|
DisplayList* mDisplayList = nullptr;
|
||||||
bool mHighContrastText = false;
|
bool mHighContrastText = false;
|
||||||
SkAutoTUnref<SkDrawFilter> mDrawFilter;
|
SkAutoTUnref<SkDrawFilter> mDrawFilter;
|
||||||
|
|||||||
@@ -1722,6 +1722,35 @@ RENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
|
|||||||
EXPECT_EQ(4, renderer.getIndex());
|
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,
|
static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
|
||||||
std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
|
std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
|
||||||
class PropertyTestRenderer : public TestRendererBase {
|
class PropertyTestRenderer : public TestRendererBase {
|
||||||
|
|||||||
@@ -603,6 +603,36 @@ TEST(RecordingCanvas, insertReorderBarrier) {
|
|||||||
EXPECT_TRUE(chunks[1].reorderChildren);
|
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) {
|
TEST(RecordingCanvas, refPaint) {
|
||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user