Loading libs/hwui/BakedOpState.cpp +9 −7 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ static int computeClipSideFlags(const Rect& clip, const Rect& bounds) { } ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) { const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) { // resolvedMatrix = parentMatrix * localMatrix transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix); Loading @@ -40,6 +40,8 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s if (CC_UNLIKELY(expandForStroke)) { // account for non-hairline stroke clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f); } else if (CC_UNLIKELY(expandForPathTexture)) { clippedBounds.outset(1); } transform.mapRect(clippedBounds); if (CC_UNLIKELY(expandForStroke Loading Loading @@ -111,7 +113,7 @@ BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp) { if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; BakedOpState* bakedState = allocator.create_trivial<BakedOpState>( allocator, snapshot, recordedOp, false); allocator, snapshot, recordedOp, false, false); if (bakedState->computedState.clippedBounds.isEmpty()) { // bounds are empty, so op is rejected allocator.rewindIfLastAlloc(bakedState); Loading @@ -127,14 +129,14 @@ BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator, } BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) { Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior, bool expandForPathTexture) { if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined) ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style) : true; bool expandForStroke = (strokeBehavior == StrokeBehavior::Forced || (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)); BakedOpState* bakedState = allocator.create_trivial<BakedOpState>( allocator, snapshot, recordedOp, expandForStroke); allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture); if (bakedState->computedState.clippedBounds.isEmpty()) { // bounds are empty, so op is rejected // NOTE: this won't succeed if a clip was allocated Loading libs/hwui/BakedOpState.h +5 −4 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ struct MergedBakedOpList { class ResolvedRenderState { public: ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke); const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture); // Constructor for unbounded ops *with* transform/clip ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, Loading Loading @@ -117,7 +117,8 @@ public: }; static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior); Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior, bool expandForPathTexture); static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr); Loading @@ -140,8 +141,8 @@ private: friend class LinearAllocator; BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) : computedState(allocator, snapshot, recordedOp, expandForStroke) const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) : computedState(allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture) , alpha(snapshot.alpha) , roundRectClipState(snapshot.roundRectClipState) , op(&recordedOp) {} Loading libs/hwui/FrameBuilder.cpp +8 −4 Original line number Diff line number Diff line Loading @@ -562,10 +562,11 @@ void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) { * for paint's style on the bounds being computed. */ BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior) { BakedOpState::StrokeBehavior strokeBehavior, bool expandForPathTexture) { // Note: here we account for stroke when baking the op BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior); mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior, expandForPathTexture); if (!bakedState) return nullptr; // quick rejected if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) { Loading @@ -590,7 +591,10 @@ static batchid_t tessBatchId(const RecordedOp& op) { } void FrameBuilder::deferArcOp(const ArcOp& op) { deferStrokeableOp(op, tessBatchId(op)); // Pass true below since arcs have a tendency to draw outside their expected bounds within // their path textures. Passing true makes it more likely that we'll scissor, instead of // corrupting the frame by drawing outside of clip bounds. deferStrokeableOp(op, tessBatchId(op), BakedOpState::StrokeBehavior::StyleDefined, true); } static bool hasMergeableClip(const BakedOpState& state) { Loading Loading @@ -748,7 +752,7 @@ static batchid_t textBatchId(const SkPaint& paint) { void FrameBuilder::deferTextOp(const TextOp& op) { BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( mAllocator, *mCanvasState.writableSnapshot(), op, BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior::StyleDefined, false); if (!bakedState) return; // quick rejected batchid_t batchId = textBatchId(*(op.paint)); Loading libs/hwui/FrameBuilder.h +2 −1 Original line number Diff line number Diff line Loading @@ -211,7 +211,8 @@ private: } BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined, bool expandForPathTexture = false); /** * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type. Loading libs/hwui/tests/unit/BakedOpStateTests.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ TEST(ResolvedRenderState, construct) { { // recorded with transform, no parent transform auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20); EXPECT_EQ(Rect(100, 200), state.clipRect()); EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped Loading @@ -44,7 +44,7 @@ TEST(ResolvedRenderState, construct) { { // recorded with transform and parent transform auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); Matrix4 expectedTranslate; expectedTranslate.loadTranslate(20, 40, 0); Loading @@ -70,14 +70,14 @@ TEST(ResolvedRenderState, computeLocalSpaceClip) { { // recorded with transform, no parent transform auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip()) << "Local clip rect should be 100x200, offset by -10,-20"; } { // recorded with transform + parent transform auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip()) << "Local clip rect should be 90x190, offset by -10,-20"; } Loading Loading @@ -170,7 +170,7 @@ TEST(ResolvedRenderState, construct_expandForStroke) { snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1); auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true, false); testCase.validator(state); } } Loading Loading @@ -234,7 +234,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) { RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint); auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior::StyleDefined, false); EXPECT_EQ(nullptr, bakedState); EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op Loading @@ -248,7 +248,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) { RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint); auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200)); auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior::StyleDefined, false); ASSERT_NE(nullptr, bakedState); EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds); Loading @@ -263,7 +263,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) { RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint); auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200)); auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::Forced); BakedOpState::StrokeBehavior::Forced, false); ASSERT_NE(nullptr, bakedState); EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds); Loading Loading
libs/hwui/BakedOpState.cpp +9 −7 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ static int computeClipSideFlags(const Rect& clip, const Rect& bounds) { } ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) { const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) { // resolvedMatrix = parentMatrix * localMatrix transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix); Loading @@ -40,6 +40,8 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s if (CC_UNLIKELY(expandForStroke)) { // account for non-hairline stroke clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f); } else if (CC_UNLIKELY(expandForPathTexture)) { clippedBounds.outset(1); } transform.mapRect(clippedBounds); if (CC_UNLIKELY(expandForStroke Loading Loading @@ -111,7 +113,7 @@ BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp) { if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; BakedOpState* bakedState = allocator.create_trivial<BakedOpState>( allocator, snapshot, recordedOp, false); allocator, snapshot, recordedOp, false, false); if (bakedState->computedState.clippedBounds.isEmpty()) { // bounds are empty, so op is rejected allocator.rewindIfLastAlloc(bakedState); Loading @@ -127,14 +129,14 @@ BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator, } BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) { Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior, bool expandForPathTexture) { if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined) ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style) : true; bool expandForStroke = (strokeBehavior == StrokeBehavior::Forced || (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)); BakedOpState* bakedState = allocator.create_trivial<BakedOpState>( allocator, snapshot, recordedOp, expandForStroke); allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture); if (bakedState->computedState.clippedBounds.isEmpty()) { // bounds are empty, so op is rejected // NOTE: this won't succeed if a clip was allocated Loading
libs/hwui/BakedOpState.h +5 −4 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ struct MergedBakedOpList { class ResolvedRenderState { public: ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke); const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture); // Constructor for unbounded ops *with* transform/clip ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, Loading Loading @@ -117,7 +117,8 @@ public: }; static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior); Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior, bool expandForPathTexture); static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr); Loading @@ -140,8 +141,8 @@ private: friend class LinearAllocator; BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) : computedState(allocator, snapshot, recordedOp, expandForStroke) const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) : computedState(allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture) , alpha(snapshot.alpha) , roundRectClipState(snapshot.roundRectClipState) , op(&recordedOp) {} Loading
libs/hwui/FrameBuilder.cpp +8 −4 Original line number Diff line number Diff line Loading @@ -562,10 +562,11 @@ void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) { * for paint's style on the bounds being computed. */ BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior) { BakedOpState::StrokeBehavior strokeBehavior, bool expandForPathTexture) { // Note: here we account for stroke when baking the op BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior); mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior, expandForPathTexture); if (!bakedState) return nullptr; // quick rejected if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) { Loading @@ -590,7 +591,10 @@ static batchid_t tessBatchId(const RecordedOp& op) { } void FrameBuilder::deferArcOp(const ArcOp& op) { deferStrokeableOp(op, tessBatchId(op)); // Pass true below since arcs have a tendency to draw outside their expected bounds within // their path textures. Passing true makes it more likely that we'll scissor, instead of // corrupting the frame by drawing outside of clip bounds. deferStrokeableOp(op, tessBatchId(op), BakedOpState::StrokeBehavior::StyleDefined, true); } static bool hasMergeableClip(const BakedOpState& state) { Loading Loading @@ -748,7 +752,7 @@ static batchid_t textBatchId(const SkPaint& paint) { void FrameBuilder::deferTextOp(const TextOp& op) { BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( mAllocator, *mCanvasState.writableSnapshot(), op, BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior::StyleDefined, false); if (!bakedState) return; // quick rejected batchid_t batchId = textBatchId(*(op.paint)); Loading
libs/hwui/FrameBuilder.h +2 −1 Original line number Diff line number Diff line Loading @@ -211,7 +211,8 @@ private: } BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined, bool expandForPathTexture = false); /** * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type. Loading
libs/hwui/tests/unit/BakedOpStateTests.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ TEST(ResolvedRenderState, construct) { { // recorded with transform, no parent transform auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20); EXPECT_EQ(Rect(100, 200), state.clipRect()); EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped Loading @@ -44,7 +44,7 @@ TEST(ResolvedRenderState, construct) { { // recorded with transform and parent transform auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); Matrix4 expectedTranslate; expectedTranslate.loadTranslate(20, 40, 0); Loading @@ -70,14 +70,14 @@ TEST(ResolvedRenderState, computeLocalSpaceClip) { { // recorded with transform, no parent transform auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip()) << "Local clip rect should be 100x200, offset by -10,-20"; } { // recorded with transform + parent transform auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip()) << "Local clip rect should be 90x190, offset by -10,-20"; } Loading Loading @@ -170,7 +170,7 @@ TEST(ResolvedRenderState, construct_expandForStroke) { snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1); auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200)); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true); ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true, false); testCase.validator(state); } } Loading Loading @@ -234,7 +234,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) { RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint); auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior::StyleDefined, false); EXPECT_EQ(nullptr, bakedState); EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op Loading @@ -248,7 +248,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) { RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint); auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200)); auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined); BakedOpState::StrokeBehavior::StyleDefined, false); ASSERT_NE(nullptr, bakedState); EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds); Loading @@ -263,7 +263,7 @@ TEST(BakedOpState, tryStrokeableOpConstruct) { RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint); auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200)); auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::Forced); BakedOpState::StrokeBehavior::Forced, false); ASSERT_NE(nullptr, bakedState); EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds); Loading