Loading libs/hwui/OpReorderer.cpp +6 −12 Original line number Diff line number Diff line Loading @@ -91,8 +91,7 @@ public: MergingOpBatch(batchid_t batchId, BakedOpState* op) : BatchBase(batchId, op, true) , mClipSideFlags(op->computedState.clipSideFlags) , mClipRect(op->computedState.clipRect) { , mClipSideFlags(op->computedState.clipSideFlags) { } /* Loading Loading @@ -194,22 +193,17 @@ public: mBounds.unionWith(op->computedState.clippedBounds); mOps.push_back(op); const int newClipSideFlags = op->computedState.clipSideFlags; mClipSideFlags |= newClipSideFlags; const Rect& opClip = op->computedState.clipRect; if (newClipSideFlags & OpClipSideFlags::Left) mClipRect.left = opClip.left; if (newClipSideFlags & OpClipSideFlags::Top) mClipRect.top = opClip.top; if (newClipSideFlags & OpClipSideFlags::Right) mClipRect.right = opClip.right; if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom; // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat // check, and doesn't extend past a side of the clip that's in use by the merged batch. // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect. mClipSideFlags |= op->computedState.clipSideFlags; } int getClipSideFlags() const { return mClipSideFlags; } const Rect& getClipRect() const { return mClipRect; } const Rect& getClipRect() const { return mBounds; } private: int mClipSideFlags; Rect mClipRect; }; OpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height, Loading libs/hwui/tests/unit/OpReordererTests.cpp +40 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,46 @@ TEST(OpReorderer, simpleBatching) { << "Expect number of ops = 2 * loop count"; } TEST(OpReorderer, clippedMerging) { class ClippedMergingTestRenderer : public TestRendererBase { public: void onMergedBitmapOps(const MergedBakedOpList& opList) override { EXPECT_EQ(0, mIndex); mIndex += opList.count; EXPECT_EQ(4u, opList.count); EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip); EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right, opList.clipSideFlags); } }; auto node = TestUtils::createNode(0, 0, 100, 100, [](RenderProperties& props, TestCanvas& canvas) { SkBitmap bitmap = TestUtils::createSkBitmap(20, 20); // left side clipped (to inset left half) canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 0, 40, nullptr); // top side clipped (to inset top half) canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 40, 0, nullptr); // right side clipped (to inset right half) canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 80, 40, nullptr); // bottom not clipped, just abutting (inset bottom half) canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 40, 70, nullptr); }); OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, createSyncedNodeList(node), sLightCenter); ClippedMergingTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); } TEST(OpReorderer, textMerging) { class TextMergingTestRenderer : public TestRendererBase { public: Loading Loading
libs/hwui/OpReorderer.cpp +6 −12 Original line number Diff line number Diff line Loading @@ -91,8 +91,7 @@ public: MergingOpBatch(batchid_t batchId, BakedOpState* op) : BatchBase(batchId, op, true) , mClipSideFlags(op->computedState.clipSideFlags) , mClipRect(op->computedState.clipRect) { , mClipSideFlags(op->computedState.clipSideFlags) { } /* Loading Loading @@ -194,22 +193,17 @@ public: mBounds.unionWith(op->computedState.clippedBounds); mOps.push_back(op); const int newClipSideFlags = op->computedState.clipSideFlags; mClipSideFlags |= newClipSideFlags; const Rect& opClip = op->computedState.clipRect; if (newClipSideFlags & OpClipSideFlags::Left) mClipRect.left = opClip.left; if (newClipSideFlags & OpClipSideFlags::Top) mClipRect.top = opClip.top; if (newClipSideFlags & OpClipSideFlags::Right) mClipRect.right = opClip.right; if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom; // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat // check, and doesn't extend past a side of the clip that's in use by the merged batch. // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect. mClipSideFlags |= op->computedState.clipSideFlags; } int getClipSideFlags() const { return mClipSideFlags; } const Rect& getClipRect() const { return mClipRect; } const Rect& getClipRect() const { return mBounds; } private: int mClipSideFlags; Rect mClipRect; }; OpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height, Loading
libs/hwui/tests/unit/OpReordererTests.cpp +40 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,46 @@ TEST(OpReorderer, simpleBatching) { << "Expect number of ops = 2 * loop count"; } TEST(OpReorderer, clippedMerging) { class ClippedMergingTestRenderer : public TestRendererBase { public: void onMergedBitmapOps(const MergedBakedOpList& opList) override { EXPECT_EQ(0, mIndex); mIndex += opList.count; EXPECT_EQ(4u, opList.count); EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip); EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right, opList.clipSideFlags); } }; auto node = TestUtils::createNode(0, 0, 100, 100, [](RenderProperties& props, TestCanvas& canvas) { SkBitmap bitmap = TestUtils::createSkBitmap(20, 20); // left side clipped (to inset left half) canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 0, 40, nullptr); // top side clipped (to inset top half) canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 40, 0, nullptr); // right side clipped (to inset right half) canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 80, 40, nullptr); // bottom not clipped, just abutting (inset bottom half) canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op); canvas.drawBitmap(bitmap, 40, 70, nullptr); }); OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, createSyncedNodeList(node), sLightCenter); ClippedMergingTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); } TEST(OpReorderer, textMerging) { class TextMergingTestRenderer : public TestRendererBase { public: Loading