Draw textShadow always first.
Interleaving text and shadow rendering resulted in issuing draw commands from FontRenderer::renderDropShadow.
bug: 28528923
Change-Id: Ife2677f58180aaf10ec74d7c6efe5c44fe248daa
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 0f670a8..e98c24e 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -194,8 +194,12 @@
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;
@@ -258,15 +262,9 @@
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;
@@ -321,6 +319,12 @@
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++) {
@@ -328,7 +332,7 @@
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);
}
}
@@ -739,7 +743,8 @@
}
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) {
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index de57cd1e..5613f9f 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -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>
@@ -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 {
@@ -45,7 +49,7 @@
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) {
@@ -67,7 +71,7 @@
[](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";
@@ -154,4 +158,40 @@
LinesOp linesOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4);
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