From a204848b1dc63877a12e2d24108e9d8e1e691e28 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 25 Mar 2016 14:17:49 -0700 Subject: [PATCH] Create first class unbounded ColorOp bug:27810783 Previous drawColor->drawPaint conversion failed to preserve unbounded nature of drawColor from old pipeline. Change-Id: Ifd7a7b9d645f0887e252e48ca95d3195ee31615f --- libs/hwui/BakedOpDispatcher.cpp | 16 ++++++++++++++++ libs/hwui/FrameBuilder.cpp | 6 ++++++ libs/hwui/RecordedOp.h | 11 +++++++++++ libs/hwui/RecordingCanvas.cpp | 8 ++++---- libs/hwui/tests/unit/FrameBuilderTests.cpp | 26 +++++++++++++++++++++++++- libs/hwui/tests/unit/RecordingCanvasTests.cpp | 4 ++-- 6 files changed, 64 insertions(+), 7 deletions(-) diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 06b712e5f13b..ea4f4eb98f36 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -506,6 +506,22 @@ void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRe renderer.renderGlop(state, glop); } +void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) { + SkPaint paint; + paint.setColor(op.color); + paint.setXfermodeMode(op.mode); + + Glop glop; + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) + .setRoundRectClipState(state.roundRectClipState) + .setMeshUnitQuad() + .setFillPaint(paint, state.alpha) + .setTransform(Matrix4::identity(), TransformFlags::None) + .setModelViewMapUnitToRect(state.computedState.clipState->rect) + .build(); + renderer.renderGlop(state, glop); +} + void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) { renderer.renderFunctor(op, state); } diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index fae8e489f337..0ebb8866bdb3 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -572,6 +572,12 @@ void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) { deferOvalOp(*resolvedOp); } +void FrameBuilder::deferColorOp(const ColorOp& op) { + BakedOpState* bakedState = tryBakeUnboundedOpState(op); + if (!bakedState) return; // quick rejected + currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); +} + void FrameBuilder::deferFunctorOp(const FunctorOp& op) { BakedOpState* bakedState = tryBakeUnboundedOpState(op); if (!bakedState) return; // quick rejected diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index 96a57b6a8efe..64c604a5ee44 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -90,6 +90,7 @@ class Tree; UNMERGEABLE_OP_FN(ArcOp) \ UNMERGEABLE_OP_FN(BitmapMeshOp) \ UNMERGEABLE_OP_FN(BitmapRectOp) \ + UNMERGEABLE_OP_FN(ColorOp) \ UNMERGEABLE_OP_FN(FunctorOp) \ UNMERGEABLE_OP_FN(LinesOp) \ UNMERGEABLE_OP_FN(OvalOp) \ @@ -256,6 +257,16 @@ struct CirclePropsOp : RecordedOp { const float* radius; }; +struct ColorOp : RecordedOp { + // Note: unbounded op that will fillclip, so no bounds/matrix needed + ColorOp(const ClipBase* localClip, int color, SkXfermode::Mode mode) + : RecordedOp(RecordedOpId::ColorOp, Rect(), Matrix4::identity(), localClip, nullptr) + , color(color) + , mode(mode) {} + const int color; + const SkXfermode::Mode mode; +}; + struct FunctorOp : RecordedOp { // Note: undefined record-time bounds, since this op fills the clip // TODO: explicitly define bounds diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 4eeadb7ad30f..f43dadeca034 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -234,10 +234,10 @@ bool RecordingCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { // android/graphics/Canvas draw operations // ---------------------------------------------------------------------------- void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) { - SkPaint paint; - paint.setColor(color); - paint.setXfermodeMode(mode); - drawPaint(paint); + addOp(alloc().create_trivial( + getRecordedClip(), + color, + mode)); } void RecordingCanvas::drawPaint(const SkPaint& paint) { diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp index 99400c6d48df..a8c032156459 100644 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp @@ -429,7 +429,31 @@ RENDERTHREAD_TEST(FrameBuilder, functor_reject) { EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected"; } -RENDERTHREAD_TEST(FrameBuilder, renderNode) { +RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) { + class ColorTestRenderer : public TestRendererBase { + public: + void onColorOp(const ColorOp& op, const BakedOpState& state) override { + EXPECT_EQ(0, mIndex++); + EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds) + << "Color op should be expanded to bounds of surrounding"; + } + }; + + auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10, + [](RenderProperties& props, RecordingCanvas& canvas) { + props.setClipToBounds(false); + canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode); + }); + + FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + TestUtils::createSyncedNodeList(unclippedColorView), + sLightGeometry, Caches::getInstance()); + ColorTestRenderer renderer; + frameBuilder.replayBakedOps(renderer); + EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected"; +} + +TEST(FrameBuilder, renderNode) { class RenderNodeTestRenderer : public TestRendererBase { public: void onRectOp(const RectOp& op, const BakedOpState& state) override { diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index 42dabd3e0745..1c240db15e9c 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -226,9 +226,9 @@ TEST(RecordingCanvas, drawColor) { ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; auto op = *(dl->getOps()[0]); - EXPECT_EQ(RecordedOpId::RectOp, op.opId); + EXPECT_EQ(RecordedOpId::ColorOp, op.opId); EXPECT_EQ(nullptr, op.localClip); - EXPECT_TRUE(op.unmappedBounds.contains(Rect(200, 200))) << "Expect recording/clip bounds"; + EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds"; } TEST(RecordingCanvas, backgroundAndImage) { -- 2.11.0