blob: 618df140deda65f590b1a592062a14c8f607b644 [file] [log] [blame]
Chris Craikb565df12015-10-05 13:00:52 -07001/*
Chris Craik5ea17242016-01-11 14:07:59 -08002 * Copyright (C) 2016 The Android Open Source Project
Chris Craikb565df12015-10-05 13:00:52 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <BakedOpState.h>
Chris Craikd2dfd8f2015-12-16 14:27:20 -080020#include <DeferredLayerUpdater.h>
Chris Craikf158b492016-01-12 14:45:08 -080021#include <FrameBuilder.h>
Chris Craik8ecf41c2015-11-16 10:27:59 -080022#include <LayerUpdateQueue.h>
Chris Craikb565df12015-10-05 13:00:52 -070023#include <RecordedOp.h>
24#include <RecordingCanvas.h>
Chris Craik8160f202015-12-02 14:50:25 -080025#include <tests/common/TestUtils.h>
Chris Craikb565df12015-10-05 13:00:52 -070026
27#include <unordered_map>
28
29namespace android {
30namespace uirenderer {
31
Chris Craik8ecf41c2015-11-16 10:27:59 -080032const LayerUpdateQueue sEmptyLayerUpdateQueue;
33const Vector3 sLightCenter = {100, 100, 100};
Chris Craik98787e62015-11-13 10:55:30 -080034
Chris Craik6fe991e52015-10-20 09:39:42 -070035/**
Chris Craik5854b342015-10-26 15:49:56 -070036 * Virtual class implemented by each test to redirect static operation / state transitions to
37 * virtual methods.
Chris Craik6fe991e52015-10-20 09:39:42 -070038 *
Chris Craik5854b342015-10-26 15:49:56 -070039 * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
40 * and allows Renderer vs Dispatching behavior to be merged.
Chris Craik6fe991e52015-10-20 09:39:42 -070041 *
42 * onXXXOp methods fail by default - tests should override ops they expect
Chris Craikd3daa312015-11-06 10:59:56 -080043 * startRepaintLayer fails by default - tests should override if expected
Chris Craik6fe991e52015-10-20 09:39:42 -070044 * startFrame/endFrame do nothing by default - tests should override to intercept
45 */
Chris Craik5854b342015-10-26 15:49:56 -070046class TestRendererBase {
Chris Craik6fe991e52015-10-20 09:39:42 -070047public:
Chris Craik5854b342015-10-26 15:49:56 -070048 virtual ~TestRendererBase() {}
Chris Craikd3daa312015-11-06 10:59:56 -080049 virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
Chris Craika6ac95e2015-11-02 18:06:59 -080050 ADD_FAILURE() << "Layer creation not expected in this test";
51 return nullptr;
52 }
Chris Craik98787e62015-11-13 10:55:30 -080053 virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
Chris Craika6ac95e2015-11-02 18:06:59 -080054 ADD_FAILURE() << "Layer repaint not expected in this test";
55 }
56 virtual void endLayer() {
57 ADD_FAILURE() << "Layer updates not expected in this test";
58 }
Chris Craik98787e62015-11-13 10:55:30 -080059 virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
Chris Craike4db79d2015-12-22 16:32:23 -080060 virtual void endFrame(const Rect& repaintRect) {}
Chris Craik6fe991e52015-10-20 09:39:42 -070061
Chris Craik15c3f192015-12-03 12:16:56 -080062 // define virtual defaults for single draw methods
63#define X(Type) \
Chris Craika6ac95e2015-11-02 18:06:59 -080064 virtual void on##Type(const Type&, const BakedOpState&) { \
65 ADD_FAILURE() << #Type " not expected in this test"; \
66 }
Chris Craik7cbf63d2016-01-06 13:46:52 -080067 MAP_RENDERABLE_OPS(X)
Chris Craik15c3f192015-12-03 12:16:56 -080068#undef X
69
70 // define virtual defaults for merged draw methods
71#define X(Type) \
72 virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
73 ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
74 }
Chris Craik7cbf63d2016-01-06 13:46:52 -080075 MAP_MERGEABLE_OPS(X)
Chris Craik15c3f192015-12-03 12:16:56 -080076#undef X
77
Chris Craik5854b342015-10-26 15:49:56 -070078 int getIndex() { return mIndex; }
Chris Craik6fe991e52015-10-20 09:39:42 -070079
Chris Craik5854b342015-10-26 15:49:56 -070080protected:
81 int mIndex = 0;
82};
83
84/**
85 * Dispatches all static methods to similar formed methods on renderer, which fail by default but
Chris Craik8ecf41c2015-11-16 10:27:59 -080086 * are overridden by subclasses per test.
Chris Craik5854b342015-10-26 15:49:56 -070087 */
88class TestDispatcher {
89public:
Chris Craik15c3f192015-12-03 12:16:56 -080090 // define single op methods, which redirect to TestRendererBase
91#define X(Type) \
Chris Craik5854b342015-10-26 15:49:56 -070092 static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
93 renderer.on##Type(op, state); \
Chris Craik6fe991e52015-10-20 09:39:42 -070094 }
Chris Craik7cbf63d2016-01-06 13:46:52 -080095 MAP_RENDERABLE_OPS(X);
Chris Craik15c3f192015-12-03 12:16:56 -080096#undef X
97
98 // define merged op methods, which redirect to TestRendererBase
99#define X(Type) \
100 static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
101 renderer.onMerged##Type##s(opList); \
102 }
Chris Craik7cbf63d2016-01-06 13:46:52 -0800103 MAP_MERGEABLE_OPS(X);
Chris Craik15c3f192015-12-03 12:16:56 -0800104#undef X
Chris Craik6fe991e52015-10-20 09:39:42 -0700105};
Chris Craikb565df12015-10-05 13:00:52 -0700106
Chris Craik5854b342015-10-26 15:49:56 -0700107class FailRenderer : public TestRendererBase {};
Chris Craik6fe991e52015-10-20 09:39:42 -0700108
Chris Craikf158b492016-01-12 14:45:08 -0800109TEST(FrameBuilder, simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800110 class SimpleTestRenderer : public TestRendererBase {
111 public:
Chris Craik98787e62015-11-13 10:55:30 -0800112 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800113 EXPECT_EQ(0, mIndex++);
114 EXPECT_EQ(100u, width);
115 EXPECT_EQ(200u, height);
116 }
117 void onRectOp(const RectOp& op, const BakedOpState& state) override {
118 EXPECT_EQ(1, mIndex++);
119 }
120 void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
121 EXPECT_EQ(2, mIndex++);
122 }
Chris Craike4db79d2015-12-22 16:32:23 -0800123 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800124 EXPECT_EQ(3, mIndex++);
125 }
126 };
127
Chris Craik8d1f2122015-11-24 16:40:09 -0800128 auto node = TestUtils::createNode(0, 0, 100, 200,
129 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700130 SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
Chris Craikb565df12015-10-05 13:00:52 -0700131 canvas.drawRect(0, 0, 100, 200, SkPaint());
132 canvas.drawBitmap(bitmap, 10, 10, nullptr);
133 });
Chris Craikf158b492016-01-12 14:45:08 -0800134 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800135 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700136 SimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800137 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700138 EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
Chris Craik6fe991e52015-10-20 09:39:42 -0700139}
140
Chris Craikf158b492016-01-12 14:45:08 -0800141TEST(FrameBuilder, simpleStroke) {
Chris Craik386aa032015-12-07 17:08:25 -0800142 class SimpleStrokeTestRenderer : public TestRendererBase {
143 public:
144 void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
145 EXPECT_EQ(0, mIndex++);
146 // even though initial bounds are empty...
147 EXPECT_TRUE(op.unmappedBounds.isEmpty())
148 << "initial bounds should be empty, since they're unstroked";
149 EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
150 << "final bounds should account for stroke";
151 }
152 };
153
154 auto node = TestUtils::createNode(0, 0, 100, 200,
155 [](RenderProperties& props, RecordingCanvas& canvas) {
156 SkPaint strokedPaint;
157 strokedPaint.setStrokeWidth(10);
158 canvas.drawPoint(50, 50, strokedPaint);
159 });
Chris Craikf158b492016-01-12 14:45:08 -0800160 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800161 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik386aa032015-12-07 17:08:25 -0800162 SimpleStrokeTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800163 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik386aa032015-12-07 17:08:25 -0800164 EXPECT_EQ(1, renderer.getIndex());
165}
166
Chris Craikf158b492016-01-12 14:45:08 -0800167TEST(FrameBuilder, simpleRejection) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800168 auto node = TestUtils::createNode(0, 0, 200, 200,
169 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500170 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700171 canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
172 canvas.drawRect(0, 0, 400, 400, SkPaint());
173 canvas.restore();
174 });
Chris Craikf158b492016-01-12 14:45:08 -0800175 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800176 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik6fe991e52015-10-20 09:39:42 -0700177
Chris Craik5854b342015-10-26 15:49:56 -0700178 FailRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800179 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb565df12015-10-05 13:00:52 -0700180}
181
Chris Craikf158b492016-01-12 14:45:08 -0800182TEST(FrameBuilder, simpleBatching) {
Chris Craika1717272015-11-19 13:02:43 -0800183 const int LOOPS = 5;
Chris Craikd3daa312015-11-06 10:59:56 -0800184 class SimpleBatchingTestRenderer : public TestRendererBase {
185 public:
186 void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
Chris Craika1717272015-11-19 13:02:43 -0800187 EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
Chris Craikd3daa312015-11-06 10:59:56 -0800188 }
189 void onRectOp(const RectOp& op, const BakedOpState& state) override {
Chris Craika1717272015-11-19 13:02:43 -0800190 EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
Chris Craikd3daa312015-11-06 10:59:56 -0800191 }
192 };
193
Chris Craik8d1f2122015-11-24 16:40:09 -0800194 auto node = TestUtils::createNode(0, 0, 200, 200,
195 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik15c3f192015-12-03 12:16:56 -0800196 SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
197 kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
Chris Craikb565df12015-10-05 13:00:52 -0700198
199 // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
200 // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
Florin Malitaeecff562015-12-21 10:43:01 -0500201 canvas.save(SaveFlags::MatrixClip);
Chris Craika1717272015-11-19 13:02:43 -0800202 for (int i = 0; i < LOOPS; i++) {
Chris Craikb565df12015-10-05 13:00:52 -0700203 canvas.translate(0, 10);
204 canvas.drawRect(0, 0, 10, 10, SkPaint());
205 canvas.drawBitmap(bitmap, 5, 0, nullptr);
206 }
207 canvas.restore();
208 });
209
Chris Craikf158b492016-01-12 14:45:08 -0800210 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800211 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700212 SimpleBatchingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800213 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craika1717272015-11-19 13:02:43 -0800214 EXPECT_EQ(2 * LOOPS, renderer.getIndex())
Chris Craik15c3f192015-12-03 12:16:56 -0800215 << "Expect number of ops = 2 * loop count";
Chris Craika1717272015-11-19 13:02:43 -0800216}
217
John Reck65182cc2016-01-26 10:50:10 -0800218// TODO: Disabled due to b/26793764
219TEST(FrameBuilder, DISABLED_clippedMerging) {
Chris Craik93e53e02015-12-17 18:42:44 -0800220 class ClippedMergingTestRenderer : public TestRendererBase {
221 public:
222 void onMergedBitmapOps(const MergedBakedOpList& opList) override {
223 EXPECT_EQ(0, mIndex);
224 mIndex += opList.count;
225 EXPECT_EQ(4u, opList.count);
226 EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
227 EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
228 opList.clipSideFlags);
229 }
230 };
231 auto node = TestUtils::createNode(0, 0, 100, 100,
232 [](RenderProperties& props, TestCanvas& canvas) {
233 SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
234
235 // left side clipped (to inset left half)
236 canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
237 canvas.drawBitmap(bitmap, 0, 40, nullptr);
238
239 // top side clipped (to inset top half)
240 canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
241 canvas.drawBitmap(bitmap, 40, 0, nullptr);
242
243 // right side clipped (to inset right half)
244 canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
245 canvas.drawBitmap(bitmap, 80, 40, nullptr);
246
247 // bottom not clipped, just abutting (inset bottom half)
248 canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
249 canvas.drawBitmap(bitmap, 40, 70, nullptr);
250 });
251
Chris Craikf158b492016-01-12 14:45:08 -0800252 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
John Reck7db5ffb2016-01-15 13:17:09 -0800253 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik93e53e02015-12-17 18:42:44 -0800254 ClippedMergingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800255 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik93e53e02015-12-17 18:42:44 -0800256 EXPECT_EQ(4, renderer.getIndex());
257}
258
Chris Craikf158b492016-01-12 14:45:08 -0800259TEST(FrameBuilder, textMerging) {
Chris Craikd7448e62015-12-15 10:34:36 -0800260 class TextMergingTestRenderer : public TestRendererBase {
261 public:
262 void onMergedTextOps(const MergedBakedOpList& opList) override {
263 EXPECT_EQ(0, mIndex);
264 mIndex += opList.count;
265 EXPECT_EQ(2u, opList.count);
266 EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
267 EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
268 EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
269 }
270 };
271 auto node = TestUtils::createNode(0, 0, 400, 400,
272 [](RenderProperties& props, TestCanvas& canvas) {
273 SkPaint paint;
274 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
275 paint.setAntiAlias(true);
276 paint.setTextSize(50);
277 TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
278 TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
279 });
Chris Craikf158b492016-01-12 14:45:08 -0800280 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
John Reck7db5ffb2016-01-15 13:17:09 -0800281 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikd7448e62015-12-15 10:34:36 -0800282 TextMergingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800283 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd7448e62015-12-15 10:34:36 -0800284 EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
285}
286
Chris Craikf158b492016-01-12 14:45:08 -0800287TEST(FrameBuilder, textStrikethrough) {
Chris Craika1717272015-11-19 13:02:43 -0800288 const int LOOPS = 5;
289 class TextStrikethroughTestRenderer : public TestRendererBase {
290 public:
291 void onRectOp(const RectOp& op, const BakedOpState& state) override {
292 EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
293 }
Chris Craik15c3f192015-12-03 12:16:56 -0800294 void onMergedTextOps(const MergedBakedOpList& opList) override {
295 EXPECT_EQ(0, mIndex);
296 mIndex += opList.count;
297 EXPECT_EQ(5u, opList.count);
Chris Craika1717272015-11-19 13:02:43 -0800298 }
299 };
Chris Craik8d1f2122015-11-24 16:40:09 -0800300 auto node = TestUtils::createNode(0, 0, 200, 2000,
301 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craika1717272015-11-19 13:02:43 -0800302 SkPaint textPaint;
303 textPaint.setAntiAlias(true);
304 textPaint.setTextSize(20);
305 textPaint.setStrikeThruText(true);
Chris Craik42a54072015-11-24 11:41:54 -0800306 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800307 for (int i = 0; i < LOOPS; i++) {
308 TestUtils::drawTextToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
309 }
310 });
Chris Craikf158b492016-01-12 14:45:08 -0800311 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
John Reck7db5ffb2016-01-15 13:17:09 -0800312 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craika1717272015-11-19 13:02:43 -0800313 TextStrikethroughTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800314 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craika1717272015-11-19 13:02:43 -0800315 EXPECT_EQ(2 * LOOPS, renderer.getIndex())
Chris Craikd7448e62015-12-15 10:34:36 -0800316 << "Expect number of ops = 2 * loop count";
Chris Craikb565df12015-10-05 13:00:52 -0700317}
318
Chris Craikf158b492016-01-12 14:45:08 -0800319RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800320 class TextureLayerTestRenderer : public TestRendererBase {
321 public:
322 void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
323 EXPECT_EQ(0, mIndex++);
Chris Craike4db79d2015-12-22 16:32:23 -0800324 EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800325 EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
326
327 Matrix4 expected;
328 expected.loadTranslate(5, 5, 0);
329 EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
330 }
331 };
332
333 auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
334 [](Matrix4* transform) {
335 transform->loadTranslate(5, 5, 0);
336 });
337
338 auto node = TestUtils::createNode(0, 0, 200, 200,
339 [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500340 canvas.save(SaveFlags::MatrixClip);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800341 canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
342 canvas.drawLayer(layerUpdater.get());
343 canvas.restore();
344 });
Chris Craikf158b492016-01-12 14:45:08 -0800345 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800346 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800347 TextureLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800348 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800349 EXPECT_EQ(1, renderer.getIndex());
350}
351
Chris Craikf158b492016-01-12 14:45:08 -0800352TEST(FrameBuilder, renderNode) {
Chris Craikd3daa312015-11-06 10:59:56 -0800353 class RenderNodeTestRenderer : public TestRendererBase {
354 public:
355 void onRectOp(const RectOp& op, const BakedOpState& state) override {
356 switch(mIndex++) {
357 case 0:
Chris Craik5430ab22015-12-10 16:28:16 -0800358 EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
Chris Craikd3daa312015-11-06 10:59:56 -0800359 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
360 break;
361 case 1:
362 EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
363 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
364 break;
365 default:
366 ADD_FAILURE();
367 }
368 }
369 };
370
Chris Craik8d1f2122015-11-24 16:40:09 -0800371 auto child = TestUtils::createNode(10, 10, 110, 110,
372 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikb565df12015-10-05 13:00:52 -0700373 SkPaint paint;
374 paint.setColor(SK_ColorWHITE);
375 canvas.drawRect(0, 0, 100, 100, paint);
376 });
377
Chris Craik8d1f2122015-11-24 16:40:09 -0800378 auto parent = TestUtils::createNode(0, 0, 200, 200,
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800379 [&child](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700380 SkPaint paint;
381 paint.setColor(SK_ColorDKGRAY);
382 canvas.drawRect(0, 0, 200, 200, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700383
Florin Malitaeecff562015-12-21 10:43:01 -0500384 canvas.save(SaveFlags::MatrixClip);
Chris Craikddf22152015-10-14 17:42:47 -0700385 canvas.translate(40, 40);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800386 canvas.drawRenderNode(child.get());
Chris Craikddf22152015-10-14 17:42:47 -0700387 canvas.restore();
Chris Craikb565df12015-10-05 13:00:52 -0700388 });
389
Chris Craikf158b492016-01-12 14:45:08 -0800390 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800391 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700392 RenderNodeTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800393 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb565df12015-10-05 13:00:52 -0700394}
395
Chris Craikf158b492016-01-12 14:45:08 -0800396TEST(FrameBuilder, clipped) {
Chris Craikd3daa312015-11-06 10:59:56 -0800397 class ClippedTestRenderer : public TestRendererBase {
398 public:
399 void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
400 EXPECT_EQ(0, mIndex++);
401 EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800402 EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800403 EXPECT_TRUE(state.computedState.transform.isIdentity());
404 }
405 };
406
Chris Craik8d1f2122015-11-24 16:40:09 -0800407 auto node = TestUtils::createNode(0, 0, 200, 200,
408 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700409 SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
410 canvas.drawBitmap(bitmap, 0, 0, nullptr);
411 });
Chris Craikddf22152015-10-14 17:42:47 -0700412
Chris Craikf158b492016-01-12 14:45:08 -0800413 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
Chris Craik0b7e8242015-10-28 16:50:44 -0700414 SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
John Reck7db5ffb2016-01-15 13:17:09 -0800415 200, 200, TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700416 ClippedTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800417 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikddf22152015-10-14 17:42:47 -0700418}
419
Chris Craikf158b492016-01-12 14:45:08 -0800420TEST(FrameBuilder, saveLayer_simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800421 class SaveLayerSimpleTestRenderer : public TestRendererBase {
422 public:
423 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
424 EXPECT_EQ(0, mIndex++);
425 EXPECT_EQ(180u, width);
426 EXPECT_EQ(180u, height);
427 return nullptr;
428 }
429 void endLayer() override {
430 EXPECT_EQ(2, mIndex++);
431 }
432 void onRectOp(const RectOp& op, const BakedOpState& state) override {
433 EXPECT_EQ(1, mIndex++);
434 EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
Chris Craik5430ab22015-12-10 16:28:16 -0800435 EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800436 EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800437
438 Matrix4 expectedTransform;
439 expectedTransform.loadTranslate(-10, -10, 0);
440 EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
441 }
442 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
443 EXPECT_EQ(3, mIndex++);
444 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800445 EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800446 EXPECT_TRUE(state.computedState.transform.isIdentity());
447 }
448 };
449
Chris Craik8d1f2122015-11-24 16:40:09 -0800450 auto node = TestUtils::createNode(0, 0, 200, 200,
451 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500452 canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700453 canvas.drawRect(10, 10, 190, 190, SkPaint());
454 canvas.restore();
455 });
Chris Craikf158b492016-01-12 14:45:08 -0800456 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800457 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700458 SaveLayerSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800459 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700460 EXPECT_EQ(4, renderer.getIndex());
Chris Craikb565df12015-10-05 13:00:52 -0700461}
Chris Craik6fe991e52015-10-20 09:39:42 -0700462
Chris Craikf158b492016-01-12 14:45:08 -0800463TEST(FrameBuilder, saveLayer_nested) {
Chris Craikd3daa312015-11-06 10:59:56 -0800464 /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
465 * - startTemporaryLayer2, rect2 endLayer2
466 * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
467 * - startFrame, layerOp1, endFrame
468 */
469 class SaveLayerNestedTestRenderer : public TestRendererBase {
470 public:
471 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
472 const int index = mIndex++;
473 if (index == 0) {
474 EXPECT_EQ(400u, width);
475 EXPECT_EQ(400u, height);
476 return (OffscreenBuffer*) 0x400;
477 } else if (index == 3) {
478 EXPECT_EQ(800u, width);
479 EXPECT_EQ(800u, height);
480 return (OffscreenBuffer*) 0x800;
481 } else { ADD_FAILURE(); }
482 return (OffscreenBuffer*) nullptr;
483 }
484 void endLayer() override {
485 int index = mIndex++;
486 EXPECT_TRUE(index == 2 || index == 6);
487 }
Chris Craik98787e62015-11-13 10:55:30 -0800488 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800489 EXPECT_EQ(7, mIndex++);
490 }
Chris Craike4db79d2015-12-22 16:32:23 -0800491 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800492 EXPECT_EQ(9, mIndex++);
493 }
494 void onRectOp(const RectOp& op, const BakedOpState& state) override {
495 const int index = mIndex++;
496 if (index == 1) {
Chris Craik5430ab22015-12-10 16:28:16 -0800497 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
Chris Craikd3daa312015-11-06 10:59:56 -0800498 } else if (index == 4) {
Chris Craik5430ab22015-12-10 16:28:16 -0800499 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
Chris Craikd3daa312015-11-06 10:59:56 -0800500 } else { ADD_FAILURE(); }
501 }
502 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
503 const int index = mIndex++;
504 if (index == 5) {
505 EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
Chris Craik5430ab22015-12-10 16:28:16 -0800506 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
Chris Craikd3daa312015-11-06 10:59:56 -0800507 } else if (index == 8) {
508 EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
Chris Craik5430ab22015-12-10 16:28:16 -0800509 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
Chris Craikd3daa312015-11-06 10:59:56 -0800510 } else { ADD_FAILURE(); }
511 }
512 };
513
Chris Craik8d1f2122015-11-24 16:40:09 -0800514 auto node = TestUtils::createNode(0, 0, 800, 800,
515 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500516 canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700517 {
518 canvas.drawRect(0, 0, 800, 800, SkPaint());
Florin Malitaeecff562015-12-21 10:43:01 -0500519 canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700520 {
521 canvas.drawRect(0, 0, 400, 400, SkPaint());
522 }
523 canvas.restore();
524 }
525 canvas.restore();
526 });
527
Chris Craikf158b492016-01-12 14:45:08 -0800528 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
John Reck7db5ffb2016-01-15 13:17:09 -0800529 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700530 SaveLayerNestedTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800531 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700532 EXPECT_EQ(10, renderer.getIndex());
Chris Craikb565df12015-10-05 13:00:52 -0700533}
Chris Craik6fe991e52015-10-20 09:39:42 -0700534
Chris Craikf158b492016-01-12 14:45:08 -0800535TEST(FrameBuilder, saveLayer_contentRejection) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800536 auto node = TestUtils::createNode(0, 0, 200, 200,
537 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500538 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700539 canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
Florin Malitaeecff562015-12-21 10:43:01 -0500540 canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700541
542 // draw within save layer may still be recorded, but shouldn't be drawn
543 canvas.drawRect(200, 200, 400, 400, SkPaint());
544
545 canvas.restore();
546 canvas.restore();
547 });
Chris Craikf158b492016-01-12 14:45:08 -0800548 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800549 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik6fe991e52015-10-20 09:39:42 -0700550
Chris Craik5854b342015-10-26 15:49:56 -0700551 FailRenderer renderer;
Chris Craik6fe991e52015-10-20 09:39:42 -0700552 // should see no ops, even within the layer, since the layer should be rejected
Chris Craikf158b492016-01-12 14:45:08 -0800553 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700554}
555
Chris Craikf158b492016-01-12 14:45:08 -0800556TEST(FrameBuilder, saveLayerUnclipped_simple) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800557 class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
558 public:
559 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
560 EXPECT_EQ(0, mIndex++);
561 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craik7435eb12016-01-07 17:41:40 -0800562 EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
Chris Craikb87eadd2016-01-06 09:16:05 -0800563 EXPECT_TRUE(state.computedState.transform.isIdentity());
564 }
565 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
566 EXPECT_EQ(1, mIndex++);
567 ASSERT_NE(nullptr, op.paint);
568 ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
569 }
570 void onRectOp(const RectOp& op, const BakedOpState& state) override {
571 EXPECT_EQ(2, mIndex++);
572 EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
573 EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
574 EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
575 EXPECT_TRUE(state.computedState.transform.isIdentity());
576 }
577 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
578 EXPECT_EQ(3, mIndex++);
579 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craik7435eb12016-01-07 17:41:40 -0800580 EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
Chris Craikb87eadd2016-01-06 09:16:05 -0800581 EXPECT_TRUE(state.computedState.transform.isIdentity());
582 }
583 };
584
585 auto node = TestUtils::createNode(0, 0, 200, 200,
586 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500587 canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
Chris Craikb87eadd2016-01-06 09:16:05 -0800588 canvas.drawRect(0, 0, 200, 200, SkPaint());
589 canvas.restore();
590 });
Chris Craikf158b492016-01-12 14:45:08 -0800591 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800592 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikb87eadd2016-01-06 09:16:05 -0800593 SaveLayerUnclippedSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800594 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800595 EXPECT_EQ(4, renderer.getIndex());
596}
597
Chris Craikf158b492016-01-12 14:45:08 -0800598TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800599 class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
600 public:
601 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
602 int index = mIndex++;
603 EXPECT_GT(4, index);
604 EXPECT_EQ(5, op.unmappedBounds.getWidth());
605 EXPECT_EQ(5, op.unmappedBounds.getHeight());
606 if (index == 0) {
607 EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
608 } else if (index == 1) {
609 EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
610 } else if (index == 2) {
611 EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
612 } else if (index == 3) {
613 EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
614 }
615 }
616 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
617 EXPECT_EQ(4, mIndex++);
618 ASSERT_EQ(op.vertexCount, 16u);
619 for (size_t i = 0; i < op.vertexCount; i++) {
620 auto v = op.vertices[i];
621 EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
622 EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
623 }
624 }
625 void onRectOp(const RectOp& op, const BakedOpState& state) override {
626 EXPECT_EQ(5, mIndex++);
627 }
628 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
629 EXPECT_LT(5, mIndex++);
630 }
631 };
632
633 auto node = TestUtils::createNode(0, 0, 200, 200,
634 [](RenderProperties& props, RecordingCanvas& canvas) {
635
Florin Malitaeecff562015-12-21 10:43:01 -0500636 int restoreTo = canvas.save(SaveFlags::MatrixClip);
Chris Craikb87eadd2016-01-06 09:16:05 -0800637 canvas.scale(2, 2);
Florin Malitaeecff562015-12-21 10:43:01 -0500638 canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
639 canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
640 canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
641 canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
Chris Craikb87eadd2016-01-06 09:16:05 -0800642 canvas.drawRect(0, 0, 100, 100, SkPaint());
643 canvas.restoreToCount(restoreTo);
644 });
Chris Craikf158b492016-01-12 14:45:08 -0800645 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800646 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikb87eadd2016-01-06 09:16:05 -0800647 SaveLayerUnclippedMergedClearsTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800648 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800649 EXPECT_EQ(10, renderer.getIndex())
650 << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
651}
652
653/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
654 * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
655 * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
656 */
Chris Craikf158b492016-01-12 14:45:08 -0800657TEST(FrameBuilder, saveLayerUnclipped_complex) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800658 class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
659 public:
660 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
661 EXPECT_EQ(0, mIndex++); // savelayer first
662 return (OffscreenBuffer*)0xabcd;
663 }
664 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
665 int index = mIndex++;
666 EXPECT_TRUE(index == 1 || index == 7);
667 }
668 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
669 int index = mIndex++;
670 EXPECT_TRUE(index == 2 || index == 8);
671 }
672 void onRectOp(const RectOp& op, const BakedOpState& state) override {
673 EXPECT_EQ(3, mIndex++);
674 Matrix4 expected;
675 expected.loadTranslate(-100, -100, 0);
676 EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
677 EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
678 }
679 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
680 int index = mIndex++;
681 EXPECT_TRUE(index == 4 || index == 10);
682 }
683 void endLayer() override {
684 EXPECT_EQ(5, mIndex++);
685 }
686 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
687 EXPECT_EQ(6, mIndex++);
688 }
689 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
690 EXPECT_EQ(9, mIndex++);
691 }
692 void endFrame(const Rect& repaintRect) override {
693 EXPECT_EQ(11, mIndex++);
694 }
695 };
696
697 auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
698 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500699 canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
700 canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
701 canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
Chris Craikb87eadd2016-01-06 09:16:05 -0800702 canvas.drawRect(200, 200, 300, 300, SkPaint());
703 canvas.restore();
704 canvas.restore();
705 canvas.restore();
706 });
Chris Craikf158b492016-01-12 14:45:08 -0800707 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
John Reck7db5ffb2016-01-15 13:17:09 -0800708 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikb87eadd2016-01-06 09:16:05 -0800709 SaveLayerUnclippedComplexTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800710 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800711 EXPECT_EQ(12, renderer.getIndex());
712}
713
Chris Craikf158b492016-01-12 14:45:08 -0800714RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800715 class HwLayerSimpleTestRenderer : public TestRendererBase {
716 public:
Chris Craik98787e62015-11-13 10:55:30 -0800717 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800718 EXPECT_EQ(0, mIndex++);
Chris Craik98787e62015-11-13 10:55:30 -0800719 EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
720 EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
721 EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
Chris Craikd3daa312015-11-06 10:59:56 -0800722 }
723 void onRectOp(const RectOp& op, const BakedOpState& state) override {
724 EXPECT_EQ(1, mIndex++);
725
726 EXPECT_TRUE(state.computedState.transform.isIdentity())
727 << "Transform should be reset within layer";
728
Chris Craike4db79d2015-12-22 16:32:23 -0800729 EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
Chris Craikd3daa312015-11-06 10:59:56 -0800730 << "Damage rect should be used to clip layer content";
731 }
732 void endLayer() override {
733 EXPECT_EQ(2, mIndex++);
734 }
Chris Craik98787e62015-11-13 10:55:30 -0800735 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800736 EXPECT_EQ(3, mIndex++);
737 }
738 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
739 EXPECT_EQ(4, mIndex++);
740 }
Chris Craike4db79d2015-12-22 16:32:23 -0800741 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800742 EXPECT_EQ(5, mIndex++);
743 }
744 };
745
Chris Craik8d1f2122015-11-24 16:40:09 -0800746 auto node = TestUtils::createNode(10, 10, 110, 110,
John Reck16c9d6a2015-11-17 15:51:08 -0800747 [](RenderProperties& props, RecordingCanvas& canvas) {
748 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700749 SkPaint paint;
750 paint.setColor(SK_ColorWHITE);
751 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -0800752 });
Chris Craik98787e62015-11-13 10:55:30 -0800753 OffscreenBuffer** layerHandle = node->getLayerHandle();
Chris Craik0b7e8242015-10-28 16:50:44 -0700754
Chris Craik98787e62015-11-13 10:55:30 -0800755 // create RenderNode's layer here in same way prepareTree would
756 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
757 *layerHandle = &layer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700758
John Reck7db5ffb2016-01-15 13:17:09 -0800759 auto syncedNodeList = TestUtils::createSyncedNodeList(node);
Chris Craik0b7e8242015-10-28 16:50:44 -0700760
761 // only enqueue partial damage
Chris Craik98787e62015-11-13 10:55:30 -0800762 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
Chris Craik0b7e8242015-10-28 16:50:44 -0700763 layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
764
Chris Craikf158b492016-01-12 14:45:08 -0800765 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik98787e62015-11-13 10:55:30 -0800766 syncedNodeList, sLightCenter);
Chris Craik0b7e8242015-10-28 16:50:44 -0700767 HwLayerSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800768 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700769 EXPECT_EQ(6, renderer.getIndex());
770
771 // clean up layer pointer, so we can safely destruct RenderNode
Chris Craik98787e62015-11-13 10:55:30 -0800772 *layerHandle = nullptr;
Chris Craik0b7e8242015-10-28 16:50:44 -0700773}
774
Chris Craikf158b492016-01-12 14:45:08 -0800775RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
Chris Craikd3daa312015-11-06 10:59:56 -0800776 /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
777 * - startRepaintLayer(child), rect(grey), endLayer
778 * - startTemporaryLayer, drawLayer(child), endLayer
779 * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
780 * - startFrame, drawLayer(parent), endLayerb
781 */
782 class HwLayerComplexTestRenderer : public TestRendererBase {
783 public:
784 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
785 EXPECT_EQ(3, mIndex++); // savelayer first
786 return (OffscreenBuffer*)0xabcd;
787 }
Chris Craik98787e62015-11-13 10:55:30 -0800788 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800789 int index = mIndex++;
790 if (index == 0) {
791 // starting inner layer
Chris Craik98787e62015-11-13 10:55:30 -0800792 EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
793 EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800794 } else if (index == 6) {
795 // starting outer layer
Chris Craik98787e62015-11-13 10:55:30 -0800796 EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
797 EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800798 } else { ADD_FAILURE(); }
799 }
800 void onRectOp(const RectOp& op, const BakedOpState& state) override {
801 int index = mIndex++;
802 if (index == 1) {
803 // inner layer's rect (white)
804 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
805 } else if (index == 7) {
806 // outer layer's rect (grey)
807 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
808 } else { ADD_FAILURE(); }
809 }
810 void endLayer() override {
811 int index = mIndex++;
812 EXPECT_TRUE(index == 2 || index == 5 || index == 9);
813 }
Chris Craik98787e62015-11-13 10:55:30 -0800814 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800815 EXPECT_EQ(10, mIndex++);
816 }
817 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
Chris Craik98787e62015-11-13 10:55:30 -0800818 OffscreenBuffer* layer = *op.layerHandle;
Chris Craikd3daa312015-11-06 10:59:56 -0800819 int index = mIndex++;
820 if (index == 4) {
Chris Craik98787e62015-11-13 10:55:30 -0800821 EXPECT_EQ(100u, layer->viewportWidth);
822 EXPECT_EQ(100u, layer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800823 } else if (index == 8) {
824 EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
825 } else if (index == 11) {
Chris Craik98787e62015-11-13 10:55:30 -0800826 EXPECT_EQ(200u, layer->viewportWidth);
827 EXPECT_EQ(200u, layer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800828 } else { ADD_FAILURE(); }
829 }
Chris Craike4db79d2015-12-22 16:32:23 -0800830 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800831 EXPECT_EQ(12, mIndex++);
832 }
833 };
834
John Reck16c9d6a2015-11-17 15:51:08 -0800835 auto child = TestUtils::createNode(50, 50, 150, 150,
836 [](RenderProperties& props, RecordingCanvas& canvas) {
837 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700838 SkPaint paint;
839 paint.setColor(SK_ColorWHITE);
840 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -0800841 });
Chris Craik98787e62015-11-13 10:55:30 -0800842 OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
843 *(child->getLayerHandle()) = &childLayer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700844
845 RenderNode* childPtr = child.get();
John Reck16c9d6a2015-11-17 15:51:08 -0800846 auto parent = TestUtils::createNode(0, 0, 200, 200,
847 [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
848 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700849 SkPaint paint;
850 paint.setColor(SK_ColorDKGRAY);
851 canvas.drawRect(0, 0, 200, 200, paint);
852
Florin Malitaeecff562015-12-21 10:43:01 -0500853 canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700854 canvas.drawRenderNode(childPtr);
855 canvas.restore();
John Reck16c9d6a2015-11-17 15:51:08 -0800856 });
Chris Craik98787e62015-11-13 10:55:30 -0800857 OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
858 *(parent->getLayerHandle()) = &parentLayer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700859
John Reck7db5ffb2016-01-15 13:17:09 -0800860 auto syncedList = TestUtils::createSyncedNodeList(parent);
Chris Craik0b7e8242015-10-28 16:50:44 -0700861
Chris Craik98787e62015-11-13 10:55:30 -0800862 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
Chris Craik0b7e8242015-10-28 16:50:44 -0700863 layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
864 layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
865
Chris Craikf158b492016-01-12 14:45:08 -0800866 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik98787e62015-11-13 10:55:30 -0800867 syncedList, sLightCenter);
Chris Craik0b7e8242015-10-28 16:50:44 -0700868 HwLayerComplexTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800869 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700870 EXPECT_EQ(13, renderer.getIndex());
871
872 // clean up layer pointers, so we can safely destruct RenderNodes
873 *(child->getLayerHandle()) = nullptr;
874 *(parent->getLayerHandle()) = nullptr;
875}
876
Chris Craik161f54b2015-11-05 11:08:52 -0800877static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
878 SkPaint paint;
879 paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
880 canvas->drawRect(0, 0, 100, 100, paint);
881}
882static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
John Reck16c9d6a2015-11-17 15:51:08 -0800883 auto node = TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -0800884 [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik161f54b2015-11-05 11:08:52 -0800885 drawOrderedRect(&canvas, expectedDrawOrder);
886 });
887 node->mutateStagingProperties().setTranslationZ(z);
888 node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
889 canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
890}
Chris Craikf158b492016-01-12 14:45:08 -0800891TEST(FrameBuilder, zReorder) {
Chris Craikd3daa312015-11-06 10:59:56 -0800892 class ZReorderTestRenderer : public TestRendererBase {
893 public:
894 void onRectOp(const RectOp& op, const BakedOpState& state) override {
895 int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
896 EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
897 }
898 };
899
John Reck16c9d6a2015-11-17 15:51:08 -0800900 auto parent = TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -0800901 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik161f54b2015-11-05 11:08:52 -0800902 drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
903 drawOrderedRect(&canvas, 1);
904 canvas.insertReorderBarrier(true);
905 drawOrderedNode(&canvas, 6, 2.0f);
906 drawOrderedRect(&canvas, 3);
907 drawOrderedNode(&canvas, 4, 0.0f);
908 drawOrderedRect(&canvas, 5);
909 drawOrderedNode(&canvas, 2, -2.0f);
910 drawOrderedNode(&canvas, 7, 2.0f);
911 canvas.insertReorderBarrier(false);
912 drawOrderedRect(&canvas, 8);
913 drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
914 });
Chris Craikf158b492016-01-12 14:45:08 -0800915 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
John Reck7db5ffb2016-01-15 13:17:09 -0800916 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik161f54b2015-11-05 11:08:52 -0800917 ZReorderTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800918 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik161f54b2015-11-05 11:08:52 -0800919 EXPECT_EQ(10, renderer.getIndex());
920};
921
Chris Craikf158b492016-01-12 14:45:08 -0800922TEST(FrameBuilder, projectionReorder) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800923 static const int scrollX = 5;
924 static const int scrollY = 10;
925 class ProjectionReorderTestRenderer : public TestRendererBase {
926 public:
927 void onRectOp(const RectOp& op, const BakedOpState& state) override {
928 const int index = mIndex++;
929
930 Matrix4 expectedMatrix;
931 switch (index) {
932 case 0:
933 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
934 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
935 expectedMatrix.loadIdentity();
936 break;
937 case 1:
938 EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
939 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
940 expectedMatrix.loadTranslate(50, 50, 0); // TODO: should scroll be respected here?
941 break;
942 case 2:
943 EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
944 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
945 expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
946 break;
947 default:
948 ADD_FAILURE();
949 }
950 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
951 }
952 };
953
954 /**
955 * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
956 * with a projecting child (P) of its own. P would normally draw between B and C's "background"
957 * draw, but because it is projected backwards, it's drawn in between B and C.
958 *
959 * The parent is scrolled by scrollX/scrollY, but this does not affect the background
960 * (which isn't affected by scroll).
961 */
962 auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
963 [](RenderProperties& properties, RecordingCanvas& canvas) {
964 properties.setProjectionReceiver(true);
965 // scroll doesn't apply to background, so undone via translationX/Y
966 // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
967 properties.setTranslationX(scrollX);
968 properties.setTranslationY(scrollY);
969
970 SkPaint paint;
971 paint.setColor(SK_ColorWHITE);
972 canvas.drawRect(0, 0, 100, 100, paint);
973 });
974 auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
975 [](RenderProperties& properties, RecordingCanvas& canvas) {
976 properties.setProjectBackwards(true);
977 properties.setClipToBounds(false);
978 SkPaint paint;
979 paint.setColor(SK_ColorDKGRAY);
980 canvas.drawRect(-10, -10, 60, 60, paint);
981 });
982 auto child = TestUtils::createNode(0, 50, 100, 100,
983 [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
984 SkPaint paint;
985 paint.setColor(SK_ColorBLUE);
986 canvas.drawRect(0, 0, 100, 50, paint);
987 canvas.drawRenderNode(projectingRipple.get());
988 });
989 auto parent = TestUtils::createNode(0, 0, 100, 100,
990 [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500991 canvas.save(SaveFlags::MatrixClip);
Chris Craik8d1f2122015-11-24 16:40:09 -0800992 canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
993 canvas.drawRenderNode(receiverBackground.get());
994 canvas.drawRenderNode(child.get());
995 canvas.restore();
996 });
997
Chris Craikf158b492016-01-12 14:45:08 -0800998 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
John Reck7db5ffb2016-01-15 13:17:09 -0800999 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik8d1f2122015-11-24 16:40:09 -08001000 ProjectionReorderTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001001 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik8d1f2122015-11-24 16:40:09 -08001002 EXPECT_EQ(3, renderer.getIndex());
1003}
1004
Chris Craik98787e62015-11-13 10:55:30 -08001005// creates a 100x100 shadow casting node with provided translationZ
1006static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
John Reck16c9d6a2015-11-17 15:51:08 -08001007 return TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -08001008 [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
John Reck16c9d6a2015-11-17 15:51:08 -08001009 properties.setTranslationZ(translationZ);
1010 properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
Chris Craik98787e62015-11-13 10:55:30 -08001011 SkPaint paint;
1012 paint.setColor(SK_ColorWHITE);
1013 canvas.drawRect(0, 0, 100, 100, paint);
Chris Craik98787e62015-11-13 10:55:30 -08001014 });
1015}
1016
Chris Craikf158b492016-01-12 14:45:08 -08001017TEST(FrameBuilder, shadow) {
Chris Craikd3daa312015-11-06 10:59:56 -08001018 class ShadowTestRenderer : public TestRendererBase {
1019 public:
1020 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1021 EXPECT_EQ(0, mIndex++);
Chris Craik98787e62015-11-13 10:55:30 -08001022 EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
1023 EXPECT_TRUE(op.casterPath->isRect(nullptr));
1024 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowMatrixXY);
1025
1026 Matrix4 expectedZ;
1027 expectedZ.loadTranslate(0, 0, 5);
1028 EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowMatrixZ);
Chris Craikd3daa312015-11-06 10:59:56 -08001029 }
1030 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1031 EXPECT_EQ(1, mIndex++);
1032 }
1033 };
Chris Craik161f54b2015-11-05 11:08:52 -08001034
Chris Craik8d1f2122015-11-24 16:40:09 -08001035 auto parent = TestUtils::createNode(0, 0, 200, 200,
1036 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikd3daa312015-11-06 10:59:56 -08001037 canvas.insertReorderBarrier(true);
Chris Craik98787e62015-11-13 10:55:30 -08001038 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
Chris Craikd3daa312015-11-06 10:59:56 -08001039 });
1040
Chris Craikf158b492016-01-12 14:45:08 -08001041 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001042 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craikd3daa312015-11-06 10:59:56 -08001043 ShadowTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001044 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd3daa312015-11-06 10:59:56 -08001045 EXPECT_EQ(2, renderer.getIndex());
1046}
Chris Craik76caecf2015-11-02 19:17:45 -08001047
Chris Craikf158b492016-01-12 14:45:08 -08001048TEST(FrameBuilder, shadowSaveLayer) {
Chris Craik98787e62015-11-13 10:55:30 -08001049 class ShadowSaveLayerTestRenderer : public TestRendererBase {
1050 public:
1051 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
1052 EXPECT_EQ(0, mIndex++);
1053 return nullptr;
1054 }
1055 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1056 EXPECT_EQ(1, mIndex++);
1057 EXPECT_FLOAT_EQ(50, op.lightCenter.x);
1058 EXPECT_FLOAT_EQ(40, op.lightCenter.y);
1059 }
1060 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1061 EXPECT_EQ(2, mIndex++);
1062 }
1063 void endLayer() override {
1064 EXPECT_EQ(3, mIndex++);
1065 }
1066 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1067 EXPECT_EQ(4, mIndex++);
1068 }
1069 };
1070
Chris Craik8d1f2122015-11-24 16:40:09 -08001071 auto parent = TestUtils::createNode(0, 0, 200, 200,
1072 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik98787e62015-11-13 10:55:30 -08001073 // save/restore outside of reorderBarrier, so they don't get moved out of place
1074 canvas.translate(20, 10);
Florin Malitaeecff562015-12-21 10:43:01 -05001075 int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
Chris Craik98787e62015-11-13 10:55:30 -08001076 canvas.insertReorderBarrier(true);
1077 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1078 canvas.insertReorderBarrier(false);
1079 canvas.restoreToCount(count);
1080 });
1081
Chris Craikf158b492016-01-12 14:45:08 -08001082 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001083 TestUtils::createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
Chris Craik98787e62015-11-13 10:55:30 -08001084 ShadowSaveLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001085 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001086 EXPECT_EQ(5, renderer.getIndex());
1087}
1088
Chris Craikf158b492016-01-12 14:45:08 -08001089RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
Chris Craik98787e62015-11-13 10:55:30 -08001090 class ShadowHwLayerTestRenderer : public TestRendererBase {
1091 public:
1092 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1093 EXPECT_EQ(0, mIndex++);
1094 }
1095 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1096 EXPECT_EQ(1, mIndex++);
1097 EXPECT_FLOAT_EQ(50, op.lightCenter.x);
1098 EXPECT_FLOAT_EQ(40, op.lightCenter.y);
1099 }
1100 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1101 EXPECT_EQ(2, mIndex++);
1102 }
1103 void endLayer() override {
1104 EXPECT_EQ(3, mIndex++);
1105 }
1106 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1107 EXPECT_EQ(4, mIndex++);
1108 }
1109 };
1110
Chris Craik8d1f2122015-11-24 16:40:09 -08001111 auto parent = TestUtils::createNode(50, 60, 150, 160,
John Reck16c9d6a2015-11-17 15:51:08 -08001112 [](RenderProperties& props, RecordingCanvas& canvas) {
1113 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik98787e62015-11-13 10:55:30 -08001114 canvas.insertReorderBarrier(true);
Florin Malitaeecff562015-12-21 10:43:01 -05001115 canvas.save(SaveFlags::MatrixClip);
Chris Craik98787e62015-11-13 10:55:30 -08001116 canvas.translate(20, 10);
1117 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1118 canvas.restore();
John Reck16c9d6a2015-11-17 15:51:08 -08001119 });
Chris Craik98787e62015-11-13 10:55:30 -08001120 OffscreenBuffer** layerHandle = parent->getLayerHandle();
1121
1122 // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1123 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
1124 Matrix4 windowTransform;
1125 windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
1126 layer.setWindowTransform(windowTransform);
1127 *layerHandle = &layer;
1128
John Reck7db5ffb2016-01-15 13:17:09 -08001129 auto syncedList = TestUtils::createSyncedNodeList(parent);
Chris Craik98787e62015-11-13 10:55:30 -08001130 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1131 layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
Chris Craikf158b492016-01-12 14:45:08 -08001132 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik98787e62015-11-13 10:55:30 -08001133 syncedList, (Vector3) { 100, 100, 100 });
Chris Craik98787e62015-11-13 10:55:30 -08001134 ShadowHwLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001135 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001136 EXPECT_EQ(5, renderer.getIndex());
1137
1138 // clean up layer pointer, so we can safely destruct RenderNode
1139 *layerHandle = nullptr;
1140}
1141
Chris Craikf158b492016-01-12 14:45:08 -08001142TEST(FrameBuilder, shadowLayering) {
Chris Craik98787e62015-11-13 10:55:30 -08001143 class ShadowLayeringTestRenderer : public TestRendererBase {
1144 public:
1145 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1146 int index = mIndex++;
1147 EXPECT_TRUE(index == 0 || index == 1);
1148 }
1149 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1150 int index = mIndex++;
1151 EXPECT_TRUE(index == 2 || index == 3);
1152 }
1153 };
Chris Craik8d1f2122015-11-24 16:40:09 -08001154 auto parent = TestUtils::createNode(0, 0, 200, 200,
1155 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik98787e62015-11-13 10:55:30 -08001156 canvas.insertReorderBarrier(true);
1157 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1158 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
1159 });
1160
Chris Craikf158b492016-01-12 14:45:08 -08001161 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001162 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik98787e62015-11-13 10:55:30 -08001163 ShadowLayeringTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001164 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001165 EXPECT_EQ(4, renderer.getIndex());
1166}
1167
John Reck16c9d6a2015-11-17 15:51:08 -08001168static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
Chris Craik76caecf2015-11-02 19:17:45 -08001169 std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
Chris Craikd3daa312015-11-06 10:59:56 -08001170 class PropertyTestRenderer : public TestRendererBase {
1171 public:
1172 PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1173 : mCallback(callback) {}
1174 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1175 EXPECT_EQ(mIndex++, 0);
1176 mCallback(op, state);
1177 }
1178 std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1179 };
1180
John Reck16c9d6a2015-11-17 15:51:08 -08001181 auto node = TestUtils::createNode(0, 0, 100, 100,
1182 [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
1183 propSetupCallback(props);
Chris Craik76caecf2015-11-02 19:17:45 -08001184 SkPaint paint;
1185 paint.setColor(SK_ColorWHITE);
1186 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -08001187 });
Chris Craik76caecf2015-11-02 19:17:45 -08001188
Chris Craikf158b492016-01-12 14:45:08 -08001189 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001190 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik76caecf2015-11-02 19:17:45 -08001191 PropertyTestRenderer renderer(opValidateCallback);
Chris Craikf158b492016-01-12 14:45:08 -08001192 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik76caecf2015-11-02 19:17:45 -08001193 EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
1194}
1195
Chris Craikf158b492016-01-12 14:45:08 -08001196TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
Chris Craik76caecf2015-11-02 19:17:45 -08001197 testProperty([](RenderProperties& properties) {
1198 properties.setAlpha(0.5f);
1199 properties.setHasOverlappingRendering(false);
Chris Craik76caecf2015-11-02 19:17:45 -08001200 }, [](const RectOp& op, const BakedOpState& state) {
1201 EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
1202 });
1203}
1204
Chris Craikf158b492016-01-12 14:45:08 -08001205TEST(FrameBuilder, renderPropClipping) {
Chris Craik76caecf2015-11-02 19:17:45 -08001206 testProperty([](RenderProperties& properties) {
1207 properties.setClipToBounds(true);
1208 properties.setClipBounds(Rect(10, 20, 300, 400));
Chris Craik76caecf2015-11-02 19:17:45 -08001209 }, [](const RectOp& op, const BakedOpState& state) {
1210 EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
1211 << "Clip rect should be intersection of node bounds and clip bounds";
1212 });
1213}
1214
Chris Craikf158b492016-01-12 14:45:08 -08001215TEST(FrameBuilder, renderPropRevealClip) {
Chris Craik76caecf2015-11-02 19:17:45 -08001216 testProperty([](RenderProperties& properties) {
1217 properties.mutableRevealClip().set(true, 50, 50, 25);
Chris Craik76caecf2015-11-02 19:17:45 -08001218 }, [](const RectOp& op, const BakedOpState& state) {
1219 ASSERT_NE(nullptr, state.roundRectClipState);
1220 EXPECT_TRUE(state.roundRectClipState->highPriority);
1221 EXPECT_EQ(25, state.roundRectClipState->radius);
1222 EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
1223 });
1224}
1225
Chris Craikf158b492016-01-12 14:45:08 -08001226TEST(FrameBuilder, renderPropOutlineClip) {
Chris Craik76caecf2015-11-02 19:17:45 -08001227 testProperty([](RenderProperties& properties) {
1228 properties.mutableOutline().setShouldClip(true);
1229 properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
Chris Craik76caecf2015-11-02 19:17:45 -08001230 }, [](const RectOp& op, const BakedOpState& state) {
1231 ASSERT_NE(nullptr, state.roundRectClipState);
1232 EXPECT_FALSE(state.roundRectClipState->highPriority);
1233 EXPECT_EQ(5, state.roundRectClipState->radius);
1234 EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
1235 });
1236}
1237
Chris Craikf158b492016-01-12 14:45:08 -08001238TEST(FrameBuilder, renderPropTransform) {
Chris Craik76caecf2015-11-02 19:17:45 -08001239 testProperty([](RenderProperties& properties) {
1240 properties.setLeftTopRightBottom(10, 10, 110, 110);
1241
1242 SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
1243 properties.setStaticMatrix(&staticMatrix);
1244
1245 // ignored, since static overrides animation
1246 SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
1247 properties.setAnimationMatrix(&animationMatrix);
1248
1249 properties.setTranslationX(10);
1250 properties.setTranslationY(20);
1251 properties.setScaleX(0.5f);
1252 properties.setScaleY(0.7f);
Chris Craik76caecf2015-11-02 19:17:45 -08001253 }, [](const RectOp& op, const BakedOpState& state) {
1254 Matrix4 matrix;
1255 matrix.loadTranslate(10, 10, 0); // left, top
1256 matrix.scale(1.2f, 1.2f, 1); // static matrix
1257 // ignore animation matrix, since static overrides it
1258
1259 // translation xy
1260 matrix.translate(10, 20);
1261
1262 // scale xy (from default pivot - center)
1263 matrix.translate(50, 50);
1264 matrix.scale(0.5f, 0.7f, 1);
1265 matrix.translate(-50, -50);
1266 EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
1267 << "Op draw matrix must match expected combination of transformation properties";
1268 });
1269}
Chris Craik161f54b2015-11-05 11:08:52 -08001270
Chris Craik8ecf41c2015-11-16 10:27:59 -08001271struct SaveLayerAlphaData {
1272 uint32_t layerWidth = 0;
1273 uint32_t layerHeight = 0;
1274 Rect rectClippedBounds;
1275 Matrix4 rectMatrix;
1276};
1277/**
1278 * Constructs a view to hit the temporary layer alpha property implementation:
1279 * a) 0 < alpha < 1
1280 * b) too big for layer (larger than maxTextureSize)
1281 * c) overlapping rendering content
1282 * returning observed data about layer size and content clip/transform.
1283 *
1284 * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
1285 * (for efficiency, and to fit in layer size constraints) based on parent clip.
1286 */
1287void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
John Reck16c9d6a2015-11-17 15:51:08 -08001288 std::function<void(RenderProperties&)> propSetupCallback) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001289 class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
1290 public:
1291 SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
1292 : mOutData(outData) {}
1293
1294 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
1295 EXPECT_EQ(0, mIndex++);
1296 mOutData->layerWidth = width;
1297 mOutData->layerHeight = height;
1298 return nullptr;
1299 }
1300 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1301 EXPECT_EQ(1, mIndex++);
1302
1303 mOutData->rectClippedBounds = state.computedState.clippedBounds;
1304 mOutData->rectMatrix = state.computedState.transform;
1305 }
1306 void endLayer() override {
1307 EXPECT_EQ(2, mIndex++);
1308 }
1309 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1310 EXPECT_EQ(3, mIndex++);
1311 }
1312 private:
1313 SaveLayerAlphaData* mOutData;
1314 };
1315
1316 ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
1317 << "Node must be bigger than max texture size to exercise saveLayer codepath";
John Reck16c9d6a2015-11-17 15:51:08 -08001318 auto node = TestUtils::createNode(0, 0, 10000, 10000,
1319 [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
1320 properties.setHasOverlappingRendering(true);
1321 properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
1322 // apply other properties
1323 propSetupCallback(properties);
1324
Chris Craik8ecf41c2015-11-16 10:27:59 -08001325 SkPaint paint;
1326 paint.setColor(SK_ColorWHITE);
1327 canvas.drawRect(0, 0, 10000, 10000, paint);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001328 });
John Reck7db5ffb2016-01-15 13:17:09 -08001329 auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
Chris Craik8ecf41c2015-11-16 10:27:59 -08001330
Chris Craikf158b492016-01-12 14:45:08 -08001331 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001332 SaveLayerAlphaClipTestRenderer renderer(outObservedData);
Chris Craikf158b492016-01-12 14:45:08 -08001333 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001334
1335 // assert, since output won't be valid if we haven't seen a save layer triggered
1336 ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
1337}
1338
Chris Craikf158b492016-01-12 14:45:08 -08001339TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001340 SaveLayerAlphaData observedData;
1341 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1342 properties.setTranslationX(10); // offset rendering content
1343 properties.setTranslationY(-2000); // offset rendering content
Chris Craik8ecf41c2015-11-16 10:27:59 -08001344 });
1345 EXPECT_EQ(190u, observedData.layerWidth);
1346 EXPECT_EQ(200u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001347 EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
Chris Craik8ecf41c2015-11-16 10:27:59 -08001348 << "expect content to be clipped to screen area";
1349 Matrix4 expected;
1350 expected.loadTranslate(0, -2000, 0);
1351 EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
1352 << "expect content to be translated as part of being clipped";
1353}
1354
Chris Craikf158b492016-01-12 14:45:08 -08001355TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001356 SaveLayerAlphaData observedData;
1357 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1358 // Translate and rotate the view so that the only visible part is the top left corner of
Chris Craik8d1f2122015-11-24 16:40:09 -08001359 // the view. It will form an isosceles right triangle with a long side length of 200 at the
Chris Craik8ecf41c2015-11-16 10:27:59 -08001360 // bottom of the viewport.
1361 properties.setTranslationX(100);
1362 properties.setTranslationY(100);
1363 properties.setPivotX(0);
1364 properties.setPivotY(0);
1365 properties.setRotation(45);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001366 });
1367 // ceil(sqrt(2) / 2 * 200) = 142
1368 EXPECT_EQ(142u, observedData.layerWidth);
1369 EXPECT_EQ(142u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001370 EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001371 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
1372}
1373
Chris Craikf158b492016-01-12 14:45:08 -08001374TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001375 SaveLayerAlphaData observedData;
1376 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1377 properties.setPivotX(0);
1378 properties.setPivotY(0);
1379 properties.setScaleX(2);
1380 properties.setScaleY(0.5f);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001381 });
1382 EXPECT_EQ(100u, observedData.layerWidth);
1383 EXPECT_EQ(400u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001384 EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001385 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
1386}
1387
Chris Craik6fe991e52015-10-20 09:39:42 -07001388} // namespace uirenderer
1389} // namespace android