Loading libs/hwui/BakedOpDispatcher.cpp +15 −10 Original line number Diff line number Diff line Loading @@ -194,8 +194,12 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer, renderer.renderGlop(nullptr, clip, glop); } static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer, static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& textOpState) { if (CC_LIKELY(!PaintUtils::hasTextShadow(op.paint))) return; FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); fontRenderer.setFont(op.paint, SkMatrix::I()); renderer.caches().textureState().activateTexture(0); PaintUtils::TextShadow textShadow; Loading Loading @@ -258,15 +262,9 @@ enum class TextRenderType { Flush }; static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, const ClipBase* renderClip, TextRenderType renderType) { FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) { fontRenderer.setFont(op.paint, SkMatrix::I()); renderTextShadow(renderer, fontRenderer, op, state); } float x = op.x; float y = op.y; const Matrix4& transform = state.computedState.transform; Loading Loading @@ -321,6 +319,12 @@ static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const Bake void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, const MergedBakedOpList& opList) { for (size_t i = 0; i < opList.count; i++) { const BakedOpState& state = *(opList.states[i]); const TextOp& op = *(static_cast<const TextOp*>(state.op)); renderTextShadow(renderer, op, state); } ClipRect renderTargetClip(opList.clip); const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr; for (size_t i = 0; i < opList.count; i++) { Loading @@ -328,7 +332,7 @@ void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, const TextOp& op = *(static_cast<const TextOp*>(state.op)); TextRenderType renderType = (i + 1 == opList.count) ? TextRenderType::Flush : TextRenderType::Defer; renderTextOp(renderer, op, state, clip, renderType); renderText(renderer, op, state, clip, renderType); } } Loading Loading @@ -740,7 +744,8 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR } void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) { renderTextOp(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush); renderTextShadow(renderer, op, state); renderText(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush); } void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) { Loading libs/hwui/tests/unit/BakedOpDispatcherTests.cpp +42 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ #include <RecordedOp.h> #include <BakedOpDispatcher.h> #include <BakedOpRenderer.h> #include <FrameBuilder.h> #include <SkBlurDrawLooper.h> #include <hwui/Paint.h> #include <tests/common/TestUtils.h> #include <SkDashPathEffect.h> Loading @@ -26,6 +29,7 @@ using namespace android::uirenderer; static BakedOpRenderer::LightInfo sLightInfo; const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50}; static Rect sBaseClip(100, 100); class ValidatingBakedOpRenderer : public BakedOpRenderer { Loading @@ -45,7 +49,7 @@ private: std::function<void(const Glop& glop)> mValidator; }; typedef void (*BakedOpReceiver)(BakedOpRenderer&, const BakedOpState&); typedef void (*TestBakedOpReceiver)(BakedOpRenderer&, const BakedOpState&); static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op, std::function<void(const Glop& glop)> glopVerifier) { Loading @@ -67,7 +71,7 @@ static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, R [](BakedOpRenderer& renderer, const BakedOpState& state) { \ BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \ }, static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); static TestBakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); #undef X unmergedReceivers[op->opId](renderer, *state); ASSERT_EQ(1, glopCount) << "Exactly one Glop expected"; Loading Loading @@ -155,3 +159,39 @@ RENDERTHREAD_TEST(BakedOpDispatcher, offsetFlags) { EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &linesOp)) << "Expect an offset for non-AA lines."; } RENDERTHREAD_TEST(BakedOpDispatcher, renderTextWithShadow) { auto node = TestUtils::createNode(0, 0, 100, 100, [](RenderProperties& props, TestCanvas& canvas) { android::Paint shadowPaint; shadowPaint.setColor(SK_ColorRED); SkScalar sigma = Blur::convertRadiusToSigma(5); shadowPaint.setLooper(SkBlurDrawLooper::Create(SK_ColorWHITE, sigma, 3, 3))->unref(); TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25); TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50); }); int glopCount = 0; auto glopReceiver = [&glopCount] (const Glop& glop) { if (glopCount < 2) { // two white shadows EXPECT_EQ(FloatColor({1, 1, 1, 1}), glop.fill.color); } else { // two text draws merged into one, drawn after both shadows EXPECT_EQ(FloatColor({1, 0, 0, 1}), glop.fill.color); } glopCount++; }; ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver); FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, Caches::getInstance()); frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); ASSERT_EQ(3, glopCount) << "Exactly three glops expected"; } No newline at end of file Loading
libs/hwui/BakedOpDispatcher.cpp +15 −10 Original line number Diff line number Diff line Loading @@ -194,8 +194,12 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer, renderer.renderGlop(nullptr, clip, glop); } static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer, static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& textOpState) { if (CC_LIKELY(!PaintUtils::hasTextShadow(op.paint))) return; FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); fontRenderer.setFont(op.paint, SkMatrix::I()); renderer.caches().textureState().activateTexture(0); PaintUtils::TextShadow textShadow; Loading Loading @@ -258,15 +262,9 @@ enum class TextRenderType { Flush }; static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, const ClipBase* renderClip, TextRenderType renderType) { FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) { fontRenderer.setFont(op.paint, SkMatrix::I()); renderTextShadow(renderer, fontRenderer, op, state); } float x = op.x; float y = op.y; const Matrix4& transform = state.computedState.transform; Loading Loading @@ -321,6 +319,12 @@ static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const Bake void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, const MergedBakedOpList& opList) { for (size_t i = 0; i < opList.count; i++) { const BakedOpState& state = *(opList.states[i]); const TextOp& op = *(static_cast<const TextOp*>(state.op)); renderTextShadow(renderer, op, state); } ClipRect renderTargetClip(opList.clip); const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr; for (size_t i = 0; i < opList.count; i++) { Loading @@ -328,7 +332,7 @@ void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, const TextOp& op = *(static_cast<const TextOp*>(state.op)); TextRenderType renderType = (i + 1 == opList.count) ? TextRenderType::Flush : TextRenderType::Defer; renderTextOp(renderer, op, state, clip, renderType); renderText(renderer, op, state, clip, renderType); } } Loading Loading @@ -740,7 +744,8 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR } void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) { renderTextOp(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush); renderTextShadow(renderer, op, state); renderText(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush); } void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) { Loading
libs/hwui/tests/unit/BakedOpDispatcherTests.cpp +42 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ #include <RecordedOp.h> #include <BakedOpDispatcher.h> #include <BakedOpRenderer.h> #include <FrameBuilder.h> #include <SkBlurDrawLooper.h> #include <hwui/Paint.h> #include <tests/common/TestUtils.h> #include <SkDashPathEffect.h> Loading @@ -26,6 +29,7 @@ using namespace android::uirenderer; static BakedOpRenderer::LightInfo sLightInfo; const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50}; static Rect sBaseClip(100, 100); class ValidatingBakedOpRenderer : public BakedOpRenderer { Loading @@ -45,7 +49,7 @@ private: std::function<void(const Glop& glop)> mValidator; }; typedef void (*BakedOpReceiver)(BakedOpRenderer&, const BakedOpState&); typedef void (*TestBakedOpReceiver)(BakedOpRenderer&, const BakedOpState&); static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op, std::function<void(const Glop& glop)> glopVerifier) { Loading @@ -67,7 +71,7 @@ static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, R [](BakedOpRenderer& renderer, const BakedOpState& state) { \ BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \ }, static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); static TestBakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); #undef X unmergedReceivers[op->opId](renderer, *state); ASSERT_EQ(1, glopCount) << "Exactly one Glop expected"; Loading Loading @@ -155,3 +159,39 @@ RENDERTHREAD_TEST(BakedOpDispatcher, offsetFlags) { EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &linesOp)) << "Expect an offset for non-AA lines."; } RENDERTHREAD_TEST(BakedOpDispatcher, renderTextWithShadow) { auto node = TestUtils::createNode(0, 0, 100, 100, [](RenderProperties& props, TestCanvas& canvas) { android::Paint shadowPaint; shadowPaint.setColor(SK_ColorRED); SkScalar sigma = Blur::convertRadiusToSigma(5); shadowPaint.setLooper(SkBlurDrawLooper::Create(SK_ColorWHITE, sigma, 3, 3))->unref(); TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25); TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50); }); int glopCount = 0; auto glopReceiver = [&glopCount] (const Glop& glop) { if (glopCount < 2) { // two white shadows EXPECT_EQ(FloatColor({1, 1, 1, 1}), glop.fill.color); } else { // two text draws merged into one, drawn after both shadows EXPECT_EQ(FloatColor({1, 0, 0, 1}), glop.fill.color); } glopCount++; }; ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver); FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, Caches::getInstance()); frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); ASSERT_EQ(3, glopCount) << "Exactly three glops expected"; } No newline at end of file