blob: b51bd2ff99cf18052285a6b32ad35309445aa6df [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) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700170 canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
171 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.
201 canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
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
Chris Craikf158b492016-01-12 14:45:08 -0800218TEST(FrameBuilder, clippedMerging) {
Chris Craik93e53e02015-12-17 18:42:44 -0800219 class ClippedMergingTestRenderer : public TestRendererBase {
220 public:
221 void onMergedBitmapOps(const MergedBakedOpList& opList) override {
222 EXPECT_EQ(0, mIndex);
223 mIndex += opList.count;
224 EXPECT_EQ(4u, opList.count);
225 EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
226 EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
227 opList.clipSideFlags);
228 }
229 };
230 auto node = TestUtils::createNode(0, 0, 100, 100,
231 [](RenderProperties& props, TestCanvas& canvas) {
232 SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
233
234 // left side clipped (to inset left half)
235 canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
236 canvas.drawBitmap(bitmap, 0, 40, nullptr);
237
238 // top side clipped (to inset top half)
239 canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
240 canvas.drawBitmap(bitmap, 40, 0, nullptr);
241
242 // right side clipped (to inset right half)
243 canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
244 canvas.drawBitmap(bitmap, 80, 40, nullptr);
245
246 // bottom not clipped, just abutting (inset bottom half)
247 canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
248 canvas.drawBitmap(bitmap, 40, 70, nullptr);
249 });
250
Chris Craikf158b492016-01-12 14:45:08 -0800251 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
John Reck7db5ffb2016-01-15 13:17:09 -0800252 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik93e53e02015-12-17 18:42:44 -0800253 ClippedMergingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800254 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik93e53e02015-12-17 18:42:44 -0800255 EXPECT_EQ(4, renderer.getIndex());
256}
257
Chris Craikf158b492016-01-12 14:45:08 -0800258TEST(FrameBuilder, textMerging) {
Chris Craikd7448e62015-12-15 10:34:36 -0800259 class TextMergingTestRenderer : public TestRendererBase {
260 public:
261 void onMergedTextOps(const MergedBakedOpList& opList) override {
262 EXPECT_EQ(0, mIndex);
263 mIndex += opList.count;
264 EXPECT_EQ(2u, opList.count);
265 EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
266 EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
267 EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
268 }
269 };
270 auto node = TestUtils::createNode(0, 0, 400, 400,
271 [](RenderProperties& props, TestCanvas& canvas) {
272 SkPaint paint;
273 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
274 paint.setAntiAlias(true);
275 paint.setTextSize(50);
276 TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
277 TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
278 });
Chris Craikf158b492016-01-12 14:45:08 -0800279 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
John Reck7db5ffb2016-01-15 13:17:09 -0800280 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikd7448e62015-12-15 10:34:36 -0800281 TextMergingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800282 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd7448e62015-12-15 10:34:36 -0800283 EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
284}
285
Chris Craikf158b492016-01-12 14:45:08 -0800286TEST(FrameBuilder, textStrikethrough) {
Chris Craika1717272015-11-19 13:02:43 -0800287 const int LOOPS = 5;
288 class TextStrikethroughTestRenderer : public TestRendererBase {
289 public:
290 void onRectOp(const RectOp& op, const BakedOpState& state) override {
291 EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
292 }
Chris Craik15c3f192015-12-03 12:16:56 -0800293 void onMergedTextOps(const MergedBakedOpList& opList) override {
294 EXPECT_EQ(0, mIndex);
295 mIndex += opList.count;
296 EXPECT_EQ(5u, opList.count);
Chris Craika1717272015-11-19 13:02:43 -0800297 }
298 };
Chris Craik8d1f2122015-11-24 16:40:09 -0800299 auto node = TestUtils::createNode(0, 0, 200, 2000,
300 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craika1717272015-11-19 13:02:43 -0800301 SkPaint textPaint;
302 textPaint.setAntiAlias(true);
303 textPaint.setTextSize(20);
304 textPaint.setStrikeThruText(true);
Chris Craik42a54072015-11-24 11:41:54 -0800305 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800306 for (int i = 0; i < LOOPS; i++) {
307 TestUtils::drawTextToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
308 }
309 });
Chris Craikf158b492016-01-12 14:45:08 -0800310 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
John Reck7db5ffb2016-01-15 13:17:09 -0800311 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craika1717272015-11-19 13:02:43 -0800312 TextStrikethroughTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800313 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craika1717272015-11-19 13:02:43 -0800314 EXPECT_EQ(2 * LOOPS, renderer.getIndex())
Chris Craikd7448e62015-12-15 10:34:36 -0800315 << "Expect number of ops = 2 * loop count";
Chris Craikb565df12015-10-05 13:00:52 -0700316}
317
Chris Craikf158b492016-01-12 14:45:08 -0800318RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800319 class TextureLayerTestRenderer : public TestRendererBase {
320 public:
321 void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
322 EXPECT_EQ(0, mIndex++);
Chris Craike4db79d2015-12-22 16:32:23 -0800323 EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800324 EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
325
326 Matrix4 expected;
327 expected.loadTranslate(5, 5, 0);
328 EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
329 }
330 };
331
332 auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
333 [](Matrix4* transform) {
334 transform->loadTranslate(5, 5, 0);
335 });
336
337 auto node = TestUtils::createNode(0, 0, 200, 200,
338 [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
339 canvas.save(SkCanvas::kMatrixClip_SaveFlag);
340 canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
341 canvas.drawLayer(layerUpdater.get());
342 canvas.restore();
343 });
Chris Craikf158b492016-01-12 14:45:08 -0800344 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800345 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800346 TextureLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800347 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800348 EXPECT_EQ(1, renderer.getIndex());
349}
350
Chris Craikf158b492016-01-12 14:45:08 -0800351TEST(FrameBuilder, renderNode) {
Chris Craikd3daa312015-11-06 10:59:56 -0800352 class RenderNodeTestRenderer : public TestRendererBase {
353 public:
354 void onRectOp(const RectOp& op, const BakedOpState& state) override {
355 switch(mIndex++) {
356 case 0:
Chris Craik5430ab22015-12-10 16:28:16 -0800357 EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
Chris Craikd3daa312015-11-06 10:59:56 -0800358 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
359 break;
360 case 1:
361 EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
362 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
363 break;
364 default:
365 ADD_FAILURE();
366 }
367 }
368 };
369
Chris Craik8d1f2122015-11-24 16:40:09 -0800370 auto child = TestUtils::createNode(10, 10, 110, 110,
371 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikb565df12015-10-05 13:00:52 -0700372 SkPaint paint;
373 paint.setColor(SK_ColorWHITE);
374 canvas.drawRect(0, 0, 100, 100, paint);
375 });
376
Chris Craik8d1f2122015-11-24 16:40:09 -0800377 auto parent = TestUtils::createNode(0, 0, 200, 200,
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800378 [&child](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700379 SkPaint paint;
380 paint.setColor(SK_ColorDKGRAY);
381 canvas.drawRect(0, 0, 200, 200, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700382
Chris Craikddf22152015-10-14 17:42:47 -0700383 canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
384 canvas.translate(40, 40);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800385 canvas.drawRenderNode(child.get());
Chris Craikddf22152015-10-14 17:42:47 -0700386 canvas.restore();
Chris Craikb565df12015-10-05 13:00:52 -0700387 });
388
Chris Craikf158b492016-01-12 14:45:08 -0800389 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800390 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700391 RenderNodeTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800392 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb565df12015-10-05 13:00:52 -0700393}
394
Chris Craikf158b492016-01-12 14:45:08 -0800395TEST(FrameBuilder, clipped) {
Chris Craikd3daa312015-11-06 10:59:56 -0800396 class ClippedTestRenderer : public TestRendererBase {
397 public:
398 void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
399 EXPECT_EQ(0, mIndex++);
400 EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800401 EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800402 EXPECT_TRUE(state.computedState.transform.isIdentity());
403 }
404 };
405
Chris Craik8d1f2122015-11-24 16:40:09 -0800406 auto node = TestUtils::createNode(0, 0, 200, 200,
407 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700408 SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
409 canvas.drawBitmap(bitmap, 0, 0, nullptr);
410 });
Chris Craikddf22152015-10-14 17:42:47 -0700411
Chris Craikf158b492016-01-12 14:45:08 -0800412 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
Chris Craik0b7e8242015-10-28 16:50:44 -0700413 SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
John Reck7db5ffb2016-01-15 13:17:09 -0800414 200, 200, TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700415 ClippedTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800416 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikddf22152015-10-14 17:42:47 -0700417}
418
Chris Craikf158b492016-01-12 14:45:08 -0800419TEST(FrameBuilder, saveLayer_simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800420 class SaveLayerSimpleTestRenderer : public TestRendererBase {
421 public:
422 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
423 EXPECT_EQ(0, mIndex++);
424 EXPECT_EQ(180u, width);
425 EXPECT_EQ(180u, height);
426 return nullptr;
427 }
428 void endLayer() override {
429 EXPECT_EQ(2, mIndex++);
430 }
431 void onRectOp(const RectOp& op, const BakedOpState& state) override {
432 EXPECT_EQ(1, mIndex++);
433 EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
Chris Craik5430ab22015-12-10 16:28:16 -0800434 EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800435 EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800436
437 Matrix4 expectedTransform;
438 expectedTransform.loadTranslate(-10, -10, 0);
439 EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
440 }
441 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
442 EXPECT_EQ(3, mIndex++);
443 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800444 EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800445 EXPECT_TRUE(state.computedState.transform.isIdentity());
446 }
447 };
448
Chris Craik8d1f2122015-11-24 16:40:09 -0800449 auto node = TestUtils::createNode(0, 0, 200, 200,
450 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700451 canvas.saveLayerAlpha(10, 10, 190, 190, 128, SkCanvas::kClipToLayer_SaveFlag);
452 canvas.drawRect(10, 10, 190, 190, SkPaint());
453 canvas.restore();
454 });
Chris Craikf158b492016-01-12 14:45:08 -0800455 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800456 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700457 SaveLayerSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800458 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700459 EXPECT_EQ(4, renderer.getIndex());
Chris Craikb565df12015-10-05 13:00:52 -0700460}
Chris Craik6fe991e52015-10-20 09:39:42 -0700461
Chris Craikf158b492016-01-12 14:45:08 -0800462TEST(FrameBuilder, saveLayer_nested) {
Chris Craikd3daa312015-11-06 10:59:56 -0800463 /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
464 * - startTemporaryLayer2, rect2 endLayer2
465 * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
466 * - startFrame, layerOp1, endFrame
467 */
468 class SaveLayerNestedTestRenderer : public TestRendererBase {
469 public:
470 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
471 const int index = mIndex++;
472 if (index == 0) {
473 EXPECT_EQ(400u, width);
474 EXPECT_EQ(400u, height);
475 return (OffscreenBuffer*) 0x400;
476 } else if (index == 3) {
477 EXPECT_EQ(800u, width);
478 EXPECT_EQ(800u, height);
479 return (OffscreenBuffer*) 0x800;
480 } else { ADD_FAILURE(); }
481 return (OffscreenBuffer*) nullptr;
482 }
483 void endLayer() override {
484 int index = mIndex++;
485 EXPECT_TRUE(index == 2 || index == 6);
486 }
Chris Craik98787e62015-11-13 10:55:30 -0800487 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800488 EXPECT_EQ(7, mIndex++);
489 }
Chris Craike4db79d2015-12-22 16:32:23 -0800490 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800491 EXPECT_EQ(9, mIndex++);
492 }
493 void onRectOp(const RectOp& op, const BakedOpState& state) override {
494 const int index = mIndex++;
495 if (index == 1) {
Chris Craik5430ab22015-12-10 16:28:16 -0800496 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
Chris Craikd3daa312015-11-06 10:59:56 -0800497 } else if (index == 4) {
Chris Craik5430ab22015-12-10 16:28:16 -0800498 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
Chris Craikd3daa312015-11-06 10:59:56 -0800499 } else { ADD_FAILURE(); }
500 }
501 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
502 const int index = mIndex++;
503 if (index == 5) {
504 EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
Chris Craik5430ab22015-12-10 16:28:16 -0800505 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
Chris Craikd3daa312015-11-06 10:59:56 -0800506 } else if (index == 8) {
507 EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
Chris Craik5430ab22015-12-10 16:28:16 -0800508 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
Chris Craikd3daa312015-11-06 10:59:56 -0800509 } else { ADD_FAILURE(); }
510 }
511 };
512
Chris Craik8d1f2122015-11-24 16:40:09 -0800513 auto node = TestUtils::createNode(0, 0, 800, 800,
514 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700515 canvas.saveLayerAlpha(0, 0, 800, 800, 128, SkCanvas::kClipToLayer_SaveFlag);
516 {
517 canvas.drawRect(0, 0, 800, 800, SkPaint());
518 canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
519 {
520 canvas.drawRect(0, 0, 400, 400, SkPaint());
521 }
522 canvas.restore();
523 }
524 canvas.restore();
525 });
526
Chris Craikf158b492016-01-12 14:45:08 -0800527 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
John Reck7db5ffb2016-01-15 13:17:09 -0800528 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik5854b342015-10-26 15:49:56 -0700529 SaveLayerNestedTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800530 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700531 EXPECT_EQ(10, renderer.getIndex());
Chris Craikb565df12015-10-05 13:00:52 -0700532}
Chris Craik6fe991e52015-10-20 09:39:42 -0700533
Chris Craikf158b492016-01-12 14:45:08 -0800534TEST(FrameBuilder, saveLayer_contentRejection) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800535 auto node = TestUtils::createNode(0, 0, 200, 200,
536 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700537 canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
538 canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
539 canvas.saveLayerAlpha(200, 200, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
540
541 // draw within save layer may still be recorded, but shouldn't be drawn
542 canvas.drawRect(200, 200, 400, 400, SkPaint());
543
544 canvas.restore();
545 canvas.restore();
546 });
Chris Craikf158b492016-01-12 14:45:08 -0800547 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800548 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik6fe991e52015-10-20 09:39:42 -0700549
Chris Craik5854b342015-10-26 15:49:56 -0700550 FailRenderer renderer;
Chris Craik6fe991e52015-10-20 09:39:42 -0700551 // should see no ops, even within the layer, since the layer should be rejected
Chris Craikf158b492016-01-12 14:45:08 -0800552 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700553}
554
Chris Craikf158b492016-01-12 14:45:08 -0800555TEST(FrameBuilder, saveLayerUnclipped_simple) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800556 class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
557 public:
558 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
559 EXPECT_EQ(0, mIndex++);
560 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craik7435eb12016-01-07 17:41:40 -0800561 EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
Chris Craikb87eadd2016-01-06 09:16:05 -0800562 EXPECT_TRUE(state.computedState.transform.isIdentity());
563 }
564 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
565 EXPECT_EQ(1, mIndex++);
566 ASSERT_NE(nullptr, op.paint);
567 ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
568 }
569 void onRectOp(const RectOp& op, const BakedOpState& state) override {
570 EXPECT_EQ(2, mIndex++);
571 EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
572 EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
573 EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
574 EXPECT_TRUE(state.computedState.transform.isIdentity());
575 }
576 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
577 EXPECT_EQ(3, mIndex++);
578 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craik7435eb12016-01-07 17:41:40 -0800579 EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
Chris Craikb87eadd2016-01-06 09:16:05 -0800580 EXPECT_TRUE(state.computedState.transform.isIdentity());
581 }
582 };
583
584 auto node = TestUtils::createNode(0, 0, 200, 200,
585 [](RenderProperties& props, RecordingCanvas& canvas) {
John Reck7db5ffb2016-01-15 13:17:09 -0800586 canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SkCanvas::SaveFlags)(0));
Chris Craikb87eadd2016-01-06 09:16:05 -0800587 canvas.drawRect(0, 0, 200, 200, SkPaint());
588 canvas.restore();
589 });
Chris Craikf158b492016-01-12 14:45:08 -0800590 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800591 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikb87eadd2016-01-06 09:16:05 -0800592 SaveLayerUnclippedSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800593 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800594 EXPECT_EQ(4, renderer.getIndex());
595}
596
Chris Craikf158b492016-01-12 14:45:08 -0800597TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800598 class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
599 public:
600 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
601 int index = mIndex++;
602 EXPECT_GT(4, index);
603 EXPECT_EQ(5, op.unmappedBounds.getWidth());
604 EXPECT_EQ(5, op.unmappedBounds.getHeight());
605 if (index == 0) {
606 EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
607 } else if (index == 1) {
608 EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
609 } else if (index == 2) {
610 EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
611 } else if (index == 3) {
612 EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
613 }
614 }
615 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
616 EXPECT_EQ(4, mIndex++);
617 ASSERT_EQ(op.vertexCount, 16u);
618 for (size_t i = 0; i < op.vertexCount; i++) {
619 auto v = op.vertices[i];
620 EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
621 EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
622 }
623 }
624 void onRectOp(const RectOp& op, const BakedOpState& state) override {
625 EXPECT_EQ(5, mIndex++);
626 }
627 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
628 EXPECT_LT(5, mIndex++);
629 }
630 };
631
632 auto node = TestUtils::createNode(0, 0, 200, 200,
633 [](RenderProperties& props, RecordingCanvas& canvas) {
634
635 int restoreTo = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
636 canvas.scale(2, 2);
637 canvas.saveLayerAlpha(0, 0, 5, 5, 128, SkCanvas::kMatrixClip_SaveFlag);
638 canvas.saveLayerAlpha(95, 0, 100, 5, 128, SkCanvas::kMatrixClip_SaveFlag);
639 canvas.saveLayerAlpha(0, 95, 5, 100, 128, SkCanvas::kMatrixClip_SaveFlag);
640 canvas.saveLayerAlpha(95, 95, 100, 100, 128, SkCanvas::kMatrixClip_SaveFlag);
641 canvas.drawRect(0, 0, 100, 100, SkPaint());
642 canvas.restoreToCount(restoreTo);
643 });
Chris Craikf158b492016-01-12 14:45:08 -0800644 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -0800645 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikb87eadd2016-01-06 09:16:05 -0800646 SaveLayerUnclippedMergedClearsTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800647 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800648 EXPECT_EQ(10, renderer.getIndex())
649 << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
650}
651
652/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
653 * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
654 * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
655 */
Chris Craikf158b492016-01-12 14:45:08 -0800656TEST(FrameBuilder, saveLayerUnclipped_complex) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800657 class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
658 public:
659 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
660 EXPECT_EQ(0, mIndex++); // savelayer first
661 return (OffscreenBuffer*)0xabcd;
662 }
663 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
664 int index = mIndex++;
665 EXPECT_TRUE(index == 1 || index == 7);
666 }
667 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
668 int index = mIndex++;
669 EXPECT_TRUE(index == 2 || index == 8);
670 }
671 void onRectOp(const RectOp& op, const BakedOpState& state) override {
672 EXPECT_EQ(3, mIndex++);
673 Matrix4 expected;
674 expected.loadTranslate(-100, -100, 0);
675 EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
676 EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
677 }
678 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
679 int index = mIndex++;
680 EXPECT_TRUE(index == 4 || index == 10);
681 }
682 void endLayer() override {
683 EXPECT_EQ(5, mIndex++);
684 }
685 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
686 EXPECT_EQ(6, mIndex++);
687 }
688 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
689 EXPECT_EQ(9, mIndex++);
690 }
691 void endFrame(const Rect& repaintRect) override {
692 EXPECT_EQ(11, mIndex++);
693 }
694 };
695
696 auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
697 [](RenderProperties& props, RecordingCanvas& canvas) {
698 canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SkCanvas::SaveFlags)0); // unclipped
699 canvas.saveLayerAlpha(100, 100, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag); // clipped
700 canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SkCanvas::SaveFlags)0); // unclipped
701 canvas.drawRect(200, 200, 300, 300, SkPaint());
702 canvas.restore();
703 canvas.restore();
704 canvas.restore();
705 });
Chris Craikf158b492016-01-12 14:45:08 -0800706 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
John Reck7db5ffb2016-01-15 13:17:09 -0800707 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craikb87eadd2016-01-06 09:16:05 -0800708 SaveLayerUnclippedComplexTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800709 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800710 EXPECT_EQ(12, renderer.getIndex());
711}
712
Chris Craikf158b492016-01-12 14:45:08 -0800713RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800714 class HwLayerSimpleTestRenderer : public TestRendererBase {
715 public:
Chris Craik98787e62015-11-13 10:55:30 -0800716 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800717 EXPECT_EQ(0, mIndex++);
Chris Craik98787e62015-11-13 10:55:30 -0800718 EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
719 EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
720 EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
Chris Craikd3daa312015-11-06 10:59:56 -0800721 }
722 void onRectOp(const RectOp& op, const BakedOpState& state) override {
723 EXPECT_EQ(1, mIndex++);
724
725 EXPECT_TRUE(state.computedState.transform.isIdentity())
726 << "Transform should be reset within layer";
727
Chris Craike4db79d2015-12-22 16:32:23 -0800728 EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
Chris Craikd3daa312015-11-06 10:59:56 -0800729 << "Damage rect should be used to clip layer content";
730 }
731 void endLayer() override {
732 EXPECT_EQ(2, mIndex++);
733 }
Chris Craik98787e62015-11-13 10:55:30 -0800734 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800735 EXPECT_EQ(3, mIndex++);
736 }
737 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
738 EXPECT_EQ(4, mIndex++);
739 }
Chris Craike4db79d2015-12-22 16:32:23 -0800740 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800741 EXPECT_EQ(5, mIndex++);
742 }
743 };
744
Chris Craik8d1f2122015-11-24 16:40:09 -0800745 auto node = TestUtils::createNode(10, 10, 110, 110,
John Reck16c9d6a2015-11-17 15:51:08 -0800746 [](RenderProperties& props, RecordingCanvas& canvas) {
747 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700748 SkPaint paint;
749 paint.setColor(SK_ColorWHITE);
750 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -0800751 });
Chris Craik98787e62015-11-13 10:55:30 -0800752 OffscreenBuffer** layerHandle = node->getLayerHandle();
Chris Craik0b7e8242015-10-28 16:50:44 -0700753
Chris Craik98787e62015-11-13 10:55:30 -0800754 // create RenderNode's layer here in same way prepareTree would
755 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
756 *layerHandle = &layer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700757
John Reck7db5ffb2016-01-15 13:17:09 -0800758 auto syncedNodeList = TestUtils::createSyncedNodeList(node);
Chris Craik0b7e8242015-10-28 16:50:44 -0700759
760 // only enqueue partial damage
Chris Craik98787e62015-11-13 10:55:30 -0800761 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
Chris Craik0b7e8242015-10-28 16:50:44 -0700762 layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
763
Chris Craikf158b492016-01-12 14:45:08 -0800764 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik98787e62015-11-13 10:55:30 -0800765 syncedNodeList, sLightCenter);
Chris Craik0b7e8242015-10-28 16:50:44 -0700766 HwLayerSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800767 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700768 EXPECT_EQ(6, renderer.getIndex());
769
770 // clean up layer pointer, so we can safely destruct RenderNode
Chris Craik98787e62015-11-13 10:55:30 -0800771 *layerHandle = nullptr;
Chris Craik0b7e8242015-10-28 16:50:44 -0700772}
773
Chris Craikf158b492016-01-12 14:45:08 -0800774RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
Chris Craikd3daa312015-11-06 10:59:56 -0800775 /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
776 * - startRepaintLayer(child), rect(grey), endLayer
777 * - startTemporaryLayer, drawLayer(child), endLayer
778 * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
779 * - startFrame, drawLayer(parent), endLayerb
780 */
781 class HwLayerComplexTestRenderer : public TestRendererBase {
782 public:
783 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
784 EXPECT_EQ(3, mIndex++); // savelayer first
785 return (OffscreenBuffer*)0xabcd;
786 }
Chris Craik98787e62015-11-13 10:55:30 -0800787 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800788 int index = mIndex++;
789 if (index == 0) {
790 // starting inner layer
Chris Craik98787e62015-11-13 10:55:30 -0800791 EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
792 EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800793 } else if (index == 6) {
794 // starting outer layer
Chris Craik98787e62015-11-13 10:55:30 -0800795 EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
796 EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800797 } else { ADD_FAILURE(); }
798 }
799 void onRectOp(const RectOp& op, const BakedOpState& state) override {
800 int index = mIndex++;
801 if (index == 1) {
802 // inner layer's rect (white)
803 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
804 } else if (index == 7) {
805 // outer layer's rect (grey)
806 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
807 } else { ADD_FAILURE(); }
808 }
809 void endLayer() override {
810 int index = mIndex++;
811 EXPECT_TRUE(index == 2 || index == 5 || index == 9);
812 }
Chris Craik98787e62015-11-13 10:55:30 -0800813 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800814 EXPECT_EQ(10, mIndex++);
815 }
816 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
Chris Craik98787e62015-11-13 10:55:30 -0800817 OffscreenBuffer* layer = *op.layerHandle;
Chris Craikd3daa312015-11-06 10:59:56 -0800818 int index = mIndex++;
819 if (index == 4) {
Chris Craik98787e62015-11-13 10:55:30 -0800820 EXPECT_EQ(100u, layer->viewportWidth);
821 EXPECT_EQ(100u, layer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800822 } else if (index == 8) {
823 EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
824 } else if (index == 11) {
Chris Craik98787e62015-11-13 10:55:30 -0800825 EXPECT_EQ(200u, layer->viewportWidth);
826 EXPECT_EQ(200u, layer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800827 } else { ADD_FAILURE(); }
828 }
Chris Craike4db79d2015-12-22 16:32:23 -0800829 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800830 EXPECT_EQ(12, mIndex++);
831 }
832 };
833
John Reck16c9d6a2015-11-17 15:51:08 -0800834 auto child = TestUtils::createNode(50, 50, 150, 150,
835 [](RenderProperties& props, RecordingCanvas& canvas) {
836 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700837 SkPaint paint;
838 paint.setColor(SK_ColorWHITE);
839 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -0800840 });
Chris Craik98787e62015-11-13 10:55:30 -0800841 OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
842 *(child->getLayerHandle()) = &childLayer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700843
844 RenderNode* childPtr = child.get();
John Reck16c9d6a2015-11-17 15:51:08 -0800845 auto parent = TestUtils::createNode(0, 0, 200, 200,
846 [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
847 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700848 SkPaint paint;
849 paint.setColor(SK_ColorDKGRAY);
850 canvas.drawRect(0, 0, 200, 200, paint);
851
852 canvas.saveLayerAlpha(50, 50, 150, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
853 canvas.drawRenderNode(childPtr);
854 canvas.restore();
John Reck16c9d6a2015-11-17 15:51:08 -0800855 });
Chris Craik98787e62015-11-13 10:55:30 -0800856 OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
857 *(parent->getLayerHandle()) = &parentLayer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700858
John Reck7db5ffb2016-01-15 13:17:09 -0800859 auto syncedList = TestUtils::createSyncedNodeList(parent);
Chris Craik0b7e8242015-10-28 16:50:44 -0700860
Chris Craik98787e62015-11-13 10:55:30 -0800861 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
Chris Craik0b7e8242015-10-28 16:50:44 -0700862 layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
863 layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
864
Chris Craikf158b492016-01-12 14:45:08 -0800865 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik98787e62015-11-13 10:55:30 -0800866 syncedList, sLightCenter);
Chris Craik0b7e8242015-10-28 16:50:44 -0700867 HwLayerComplexTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800868 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700869 EXPECT_EQ(13, renderer.getIndex());
870
871 // clean up layer pointers, so we can safely destruct RenderNodes
872 *(child->getLayerHandle()) = nullptr;
873 *(parent->getLayerHandle()) = nullptr;
874}
875
Chris Craik161f54b2015-11-05 11:08:52 -0800876static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
877 SkPaint paint;
878 paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
879 canvas->drawRect(0, 0, 100, 100, paint);
880}
881static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
John Reck16c9d6a2015-11-17 15:51:08 -0800882 auto node = TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -0800883 [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik161f54b2015-11-05 11:08:52 -0800884 drawOrderedRect(&canvas, expectedDrawOrder);
885 });
886 node->mutateStagingProperties().setTranslationZ(z);
887 node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
888 canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
889}
Chris Craikf158b492016-01-12 14:45:08 -0800890TEST(FrameBuilder, zReorder) {
Chris Craikd3daa312015-11-06 10:59:56 -0800891 class ZReorderTestRenderer : public TestRendererBase {
892 public:
893 void onRectOp(const RectOp& op, const BakedOpState& state) override {
894 int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
895 EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
896 }
897 };
898
John Reck16c9d6a2015-11-17 15:51:08 -0800899 auto parent = TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -0800900 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik161f54b2015-11-05 11:08:52 -0800901 drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
902 drawOrderedRect(&canvas, 1);
903 canvas.insertReorderBarrier(true);
904 drawOrderedNode(&canvas, 6, 2.0f);
905 drawOrderedRect(&canvas, 3);
906 drawOrderedNode(&canvas, 4, 0.0f);
907 drawOrderedRect(&canvas, 5);
908 drawOrderedNode(&canvas, 2, -2.0f);
909 drawOrderedNode(&canvas, 7, 2.0f);
910 canvas.insertReorderBarrier(false);
911 drawOrderedRect(&canvas, 8);
912 drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
913 });
Chris Craikf158b492016-01-12 14:45:08 -0800914 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
John Reck7db5ffb2016-01-15 13:17:09 -0800915 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik161f54b2015-11-05 11:08:52 -0800916 ZReorderTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800917 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik161f54b2015-11-05 11:08:52 -0800918 EXPECT_EQ(10, renderer.getIndex());
919};
920
Chris Craikf158b492016-01-12 14:45:08 -0800921TEST(FrameBuilder, projectionReorder) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800922 static const int scrollX = 5;
923 static const int scrollY = 10;
924 class ProjectionReorderTestRenderer : public TestRendererBase {
925 public:
926 void onRectOp(const RectOp& op, const BakedOpState& state) override {
927 const int index = mIndex++;
928
929 Matrix4 expectedMatrix;
930 switch (index) {
931 case 0:
932 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
933 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
934 expectedMatrix.loadIdentity();
935 break;
936 case 1:
937 EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
938 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
939 expectedMatrix.loadTranslate(50, 50, 0); // TODO: should scroll be respected here?
940 break;
941 case 2:
942 EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
943 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
944 expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
945 break;
946 default:
947 ADD_FAILURE();
948 }
949 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
950 }
951 };
952
953 /**
954 * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
955 * with a projecting child (P) of its own. P would normally draw between B and C's "background"
956 * draw, but because it is projected backwards, it's drawn in between B and C.
957 *
958 * The parent is scrolled by scrollX/scrollY, but this does not affect the background
959 * (which isn't affected by scroll).
960 */
961 auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
962 [](RenderProperties& properties, RecordingCanvas& canvas) {
963 properties.setProjectionReceiver(true);
964 // scroll doesn't apply to background, so undone via translationX/Y
965 // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
966 properties.setTranslationX(scrollX);
967 properties.setTranslationY(scrollY);
968
969 SkPaint paint;
970 paint.setColor(SK_ColorWHITE);
971 canvas.drawRect(0, 0, 100, 100, paint);
972 });
973 auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
974 [](RenderProperties& properties, RecordingCanvas& canvas) {
975 properties.setProjectBackwards(true);
976 properties.setClipToBounds(false);
977 SkPaint paint;
978 paint.setColor(SK_ColorDKGRAY);
979 canvas.drawRect(-10, -10, 60, 60, paint);
980 });
981 auto child = TestUtils::createNode(0, 50, 100, 100,
982 [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
983 SkPaint paint;
984 paint.setColor(SK_ColorBLUE);
985 canvas.drawRect(0, 0, 100, 50, paint);
986 canvas.drawRenderNode(projectingRipple.get());
987 });
988 auto parent = TestUtils::createNode(0, 0, 100, 100,
989 [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
990 canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
991 canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
992 canvas.drawRenderNode(receiverBackground.get());
993 canvas.drawRenderNode(child.get());
994 canvas.restore();
995 });
996
Chris Craikf158b492016-01-12 14:45:08 -0800997 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
John Reck7db5ffb2016-01-15 13:17:09 -0800998 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik8d1f2122015-11-24 16:40:09 -0800999 ProjectionReorderTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001000 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik8d1f2122015-11-24 16:40:09 -08001001 EXPECT_EQ(3, renderer.getIndex());
1002}
1003
Chris Craik98787e62015-11-13 10:55:30 -08001004// creates a 100x100 shadow casting node with provided translationZ
1005static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
John Reck16c9d6a2015-11-17 15:51:08 -08001006 return TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -08001007 [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
John Reck16c9d6a2015-11-17 15:51:08 -08001008 properties.setTranslationZ(translationZ);
1009 properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
Chris Craik98787e62015-11-13 10:55:30 -08001010 SkPaint paint;
1011 paint.setColor(SK_ColorWHITE);
1012 canvas.drawRect(0, 0, 100, 100, paint);
Chris Craik98787e62015-11-13 10:55:30 -08001013 });
1014}
1015
Chris Craikf158b492016-01-12 14:45:08 -08001016TEST(FrameBuilder, shadow) {
Chris Craikd3daa312015-11-06 10:59:56 -08001017 class ShadowTestRenderer : public TestRendererBase {
1018 public:
1019 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1020 EXPECT_EQ(0, mIndex++);
Chris Craik98787e62015-11-13 10:55:30 -08001021 EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
1022 EXPECT_TRUE(op.casterPath->isRect(nullptr));
1023 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowMatrixXY);
1024
1025 Matrix4 expectedZ;
1026 expectedZ.loadTranslate(0, 0, 5);
1027 EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowMatrixZ);
Chris Craikd3daa312015-11-06 10:59:56 -08001028 }
1029 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1030 EXPECT_EQ(1, mIndex++);
1031 }
1032 };
Chris Craik161f54b2015-11-05 11:08:52 -08001033
Chris Craik8d1f2122015-11-24 16:40:09 -08001034 auto parent = TestUtils::createNode(0, 0, 200, 200,
1035 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikd3daa312015-11-06 10:59:56 -08001036 canvas.insertReorderBarrier(true);
Chris Craik98787e62015-11-13 10:55:30 -08001037 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
Chris Craikd3daa312015-11-06 10:59:56 -08001038 });
1039
Chris Craikf158b492016-01-12 14:45:08 -08001040 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001041 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craikd3daa312015-11-06 10:59:56 -08001042 ShadowTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001043 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd3daa312015-11-06 10:59:56 -08001044 EXPECT_EQ(2, renderer.getIndex());
1045}
Chris Craik76caecf2015-11-02 19:17:45 -08001046
Chris Craikf158b492016-01-12 14:45:08 -08001047TEST(FrameBuilder, shadowSaveLayer) {
Chris Craik98787e62015-11-13 10:55:30 -08001048 class ShadowSaveLayerTestRenderer : public TestRendererBase {
1049 public:
1050 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
1051 EXPECT_EQ(0, mIndex++);
1052 return nullptr;
1053 }
1054 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1055 EXPECT_EQ(1, mIndex++);
1056 EXPECT_FLOAT_EQ(50, op.lightCenter.x);
1057 EXPECT_FLOAT_EQ(40, op.lightCenter.y);
1058 }
1059 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1060 EXPECT_EQ(2, mIndex++);
1061 }
1062 void endLayer() override {
1063 EXPECT_EQ(3, mIndex++);
1064 }
1065 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1066 EXPECT_EQ(4, mIndex++);
1067 }
1068 };
1069
Chris Craik8d1f2122015-11-24 16:40:09 -08001070 auto parent = TestUtils::createNode(0, 0, 200, 200,
1071 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik98787e62015-11-13 10:55:30 -08001072 // save/restore outside of reorderBarrier, so they don't get moved out of place
1073 canvas.translate(20, 10);
1074 int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
1075 canvas.insertReorderBarrier(true);
1076 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1077 canvas.insertReorderBarrier(false);
1078 canvas.restoreToCount(count);
1079 });
1080
Chris Craikf158b492016-01-12 14:45:08 -08001081 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001082 TestUtils::createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
Chris Craik98787e62015-11-13 10:55:30 -08001083 ShadowSaveLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001084 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001085 EXPECT_EQ(5, renderer.getIndex());
1086}
1087
Chris Craikf158b492016-01-12 14:45:08 -08001088RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
Chris Craik98787e62015-11-13 10:55:30 -08001089 class ShadowHwLayerTestRenderer : public TestRendererBase {
1090 public:
1091 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1092 EXPECT_EQ(0, mIndex++);
1093 }
1094 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1095 EXPECT_EQ(1, mIndex++);
1096 EXPECT_FLOAT_EQ(50, op.lightCenter.x);
1097 EXPECT_FLOAT_EQ(40, op.lightCenter.y);
1098 }
1099 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1100 EXPECT_EQ(2, mIndex++);
1101 }
1102 void endLayer() override {
1103 EXPECT_EQ(3, mIndex++);
1104 }
1105 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1106 EXPECT_EQ(4, mIndex++);
1107 }
1108 };
1109
Chris Craik8d1f2122015-11-24 16:40:09 -08001110 auto parent = TestUtils::createNode(50, 60, 150, 160,
John Reck16c9d6a2015-11-17 15:51:08 -08001111 [](RenderProperties& props, RecordingCanvas& canvas) {
1112 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik98787e62015-11-13 10:55:30 -08001113 canvas.insertReorderBarrier(true);
1114 canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
1115 canvas.translate(20, 10);
1116 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1117 canvas.restore();
John Reck16c9d6a2015-11-17 15:51:08 -08001118 });
Chris Craik98787e62015-11-13 10:55:30 -08001119 OffscreenBuffer** layerHandle = parent->getLayerHandle();
1120
1121 // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1122 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
1123 Matrix4 windowTransform;
1124 windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
1125 layer.setWindowTransform(windowTransform);
1126 *layerHandle = &layer;
1127
John Reck7db5ffb2016-01-15 13:17:09 -08001128 auto syncedList = TestUtils::createSyncedNodeList(parent);
Chris Craik98787e62015-11-13 10:55:30 -08001129 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1130 layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
Chris Craikf158b492016-01-12 14:45:08 -08001131 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik98787e62015-11-13 10:55:30 -08001132 syncedList, (Vector3) { 100, 100, 100 });
Chris Craik98787e62015-11-13 10:55:30 -08001133 ShadowHwLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001134 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001135 EXPECT_EQ(5, renderer.getIndex());
1136
1137 // clean up layer pointer, so we can safely destruct RenderNode
1138 *layerHandle = nullptr;
1139}
1140
Chris Craikf158b492016-01-12 14:45:08 -08001141TEST(FrameBuilder, shadowLayering) {
Chris Craik98787e62015-11-13 10:55:30 -08001142 class ShadowLayeringTestRenderer : public TestRendererBase {
1143 public:
1144 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1145 int index = mIndex++;
1146 EXPECT_TRUE(index == 0 || index == 1);
1147 }
1148 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1149 int index = mIndex++;
1150 EXPECT_TRUE(index == 2 || index == 3);
1151 }
1152 };
Chris Craik8d1f2122015-11-24 16:40:09 -08001153 auto parent = TestUtils::createNode(0, 0, 200, 200,
1154 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik98787e62015-11-13 10:55:30 -08001155 canvas.insertReorderBarrier(true);
1156 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1157 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
1158 });
1159
Chris Craikf158b492016-01-12 14:45:08 -08001160 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001161 TestUtils::createSyncedNodeList(parent), sLightCenter);
Chris Craik98787e62015-11-13 10:55:30 -08001162 ShadowLayeringTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001163 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001164 EXPECT_EQ(4, renderer.getIndex());
1165}
1166
John Reck16c9d6a2015-11-17 15:51:08 -08001167static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
Chris Craik76caecf2015-11-02 19:17:45 -08001168 std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
Chris Craikd3daa312015-11-06 10:59:56 -08001169 class PropertyTestRenderer : public TestRendererBase {
1170 public:
1171 PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1172 : mCallback(callback) {}
1173 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1174 EXPECT_EQ(mIndex++, 0);
1175 mCallback(op, state);
1176 }
1177 std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1178 };
1179
John Reck16c9d6a2015-11-17 15:51:08 -08001180 auto node = TestUtils::createNode(0, 0, 100, 100,
1181 [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
1182 propSetupCallback(props);
Chris Craik76caecf2015-11-02 19:17:45 -08001183 SkPaint paint;
1184 paint.setColor(SK_ColorWHITE);
1185 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -08001186 });
Chris Craik76caecf2015-11-02 19:17:45 -08001187
Chris Craikf158b492016-01-12 14:45:08 -08001188 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
John Reck7db5ffb2016-01-15 13:17:09 -08001189 TestUtils::createSyncedNodeList(node), sLightCenter);
Chris Craik76caecf2015-11-02 19:17:45 -08001190 PropertyTestRenderer renderer(opValidateCallback);
Chris Craikf158b492016-01-12 14:45:08 -08001191 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik76caecf2015-11-02 19:17:45 -08001192 EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
1193}
1194
Chris Craikf158b492016-01-12 14:45:08 -08001195TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
Chris Craik76caecf2015-11-02 19:17:45 -08001196 testProperty([](RenderProperties& properties) {
1197 properties.setAlpha(0.5f);
1198 properties.setHasOverlappingRendering(false);
Chris Craik76caecf2015-11-02 19:17:45 -08001199 }, [](const RectOp& op, const BakedOpState& state) {
1200 EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
1201 });
1202}
1203
Chris Craikf158b492016-01-12 14:45:08 -08001204TEST(FrameBuilder, renderPropClipping) {
Chris Craik76caecf2015-11-02 19:17:45 -08001205 testProperty([](RenderProperties& properties) {
1206 properties.setClipToBounds(true);
1207 properties.setClipBounds(Rect(10, 20, 300, 400));
Chris Craik76caecf2015-11-02 19:17:45 -08001208 }, [](const RectOp& op, const BakedOpState& state) {
1209 EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
1210 << "Clip rect should be intersection of node bounds and clip bounds";
1211 });
1212}
1213
Chris Craikf158b492016-01-12 14:45:08 -08001214TEST(FrameBuilder, renderPropRevealClip) {
Chris Craik76caecf2015-11-02 19:17:45 -08001215 testProperty([](RenderProperties& properties) {
1216 properties.mutableRevealClip().set(true, 50, 50, 25);
Chris Craik76caecf2015-11-02 19:17:45 -08001217 }, [](const RectOp& op, const BakedOpState& state) {
1218 ASSERT_NE(nullptr, state.roundRectClipState);
1219 EXPECT_TRUE(state.roundRectClipState->highPriority);
1220 EXPECT_EQ(25, state.roundRectClipState->radius);
1221 EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
1222 });
1223}
1224
Chris Craikf158b492016-01-12 14:45:08 -08001225TEST(FrameBuilder, renderPropOutlineClip) {
Chris Craik76caecf2015-11-02 19:17:45 -08001226 testProperty([](RenderProperties& properties) {
1227 properties.mutableOutline().setShouldClip(true);
1228 properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
Chris Craik76caecf2015-11-02 19:17:45 -08001229 }, [](const RectOp& op, const BakedOpState& state) {
1230 ASSERT_NE(nullptr, state.roundRectClipState);
1231 EXPECT_FALSE(state.roundRectClipState->highPriority);
1232 EXPECT_EQ(5, state.roundRectClipState->radius);
1233 EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
1234 });
1235}
1236
Chris Craikf158b492016-01-12 14:45:08 -08001237TEST(FrameBuilder, renderPropTransform) {
Chris Craik76caecf2015-11-02 19:17:45 -08001238 testProperty([](RenderProperties& properties) {
1239 properties.setLeftTopRightBottom(10, 10, 110, 110);
1240
1241 SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
1242 properties.setStaticMatrix(&staticMatrix);
1243
1244 // ignored, since static overrides animation
1245 SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
1246 properties.setAnimationMatrix(&animationMatrix);
1247
1248 properties.setTranslationX(10);
1249 properties.setTranslationY(20);
1250 properties.setScaleX(0.5f);
1251 properties.setScaleY(0.7f);
Chris Craik76caecf2015-11-02 19:17:45 -08001252 }, [](const RectOp& op, const BakedOpState& state) {
1253 Matrix4 matrix;
1254 matrix.loadTranslate(10, 10, 0); // left, top
1255 matrix.scale(1.2f, 1.2f, 1); // static matrix
1256 // ignore animation matrix, since static overrides it
1257
1258 // translation xy
1259 matrix.translate(10, 20);
1260
1261 // scale xy (from default pivot - center)
1262 matrix.translate(50, 50);
1263 matrix.scale(0.5f, 0.7f, 1);
1264 matrix.translate(-50, -50);
1265 EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
1266 << "Op draw matrix must match expected combination of transformation properties";
1267 });
1268}
Chris Craik161f54b2015-11-05 11:08:52 -08001269
Chris Craik8ecf41c2015-11-16 10:27:59 -08001270struct SaveLayerAlphaData {
1271 uint32_t layerWidth = 0;
1272 uint32_t layerHeight = 0;
1273 Rect rectClippedBounds;
1274 Matrix4 rectMatrix;
1275};
1276/**
1277 * Constructs a view to hit the temporary layer alpha property implementation:
1278 * a) 0 < alpha < 1
1279 * b) too big for layer (larger than maxTextureSize)
1280 * c) overlapping rendering content
1281 * returning observed data about layer size and content clip/transform.
1282 *
1283 * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
1284 * (for efficiency, and to fit in layer size constraints) based on parent clip.
1285 */
1286void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
John Reck16c9d6a2015-11-17 15:51:08 -08001287 std::function<void(RenderProperties&)> propSetupCallback) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001288 class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
1289 public:
1290 SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
1291 : mOutData(outData) {}
1292
1293 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
1294 EXPECT_EQ(0, mIndex++);
1295 mOutData->layerWidth = width;
1296 mOutData->layerHeight = height;
1297 return nullptr;
1298 }
1299 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1300 EXPECT_EQ(1, mIndex++);
1301
1302 mOutData->rectClippedBounds = state.computedState.clippedBounds;
1303 mOutData->rectMatrix = state.computedState.transform;
1304 }
1305 void endLayer() override {
1306 EXPECT_EQ(2, mIndex++);
1307 }
1308 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1309 EXPECT_EQ(3, mIndex++);
1310 }
1311 private:
1312 SaveLayerAlphaData* mOutData;
1313 };
1314
1315 ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
1316 << "Node must be bigger than max texture size to exercise saveLayer codepath";
John Reck16c9d6a2015-11-17 15:51:08 -08001317 auto node = TestUtils::createNode(0, 0, 10000, 10000,
1318 [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
1319 properties.setHasOverlappingRendering(true);
1320 properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
1321 // apply other properties
1322 propSetupCallback(properties);
1323
Chris Craik8ecf41c2015-11-16 10:27:59 -08001324 SkPaint paint;
1325 paint.setColor(SK_ColorWHITE);
1326 canvas.drawRect(0, 0, 10000, 10000, paint);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001327 });
John Reck7db5ffb2016-01-15 13:17:09 -08001328 auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
Chris Craik8ecf41c2015-11-16 10:27:59 -08001329
Chris Craikf158b492016-01-12 14:45:08 -08001330 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001331 SaveLayerAlphaClipTestRenderer renderer(outObservedData);
Chris Craikf158b492016-01-12 14:45:08 -08001332 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001333
1334 // assert, since output won't be valid if we haven't seen a save layer triggered
1335 ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
1336}
1337
Chris Craikf158b492016-01-12 14:45:08 -08001338TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001339 SaveLayerAlphaData observedData;
1340 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1341 properties.setTranslationX(10); // offset rendering content
1342 properties.setTranslationY(-2000); // offset rendering content
Chris Craik8ecf41c2015-11-16 10:27:59 -08001343 });
1344 EXPECT_EQ(190u, observedData.layerWidth);
1345 EXPECT_EQ(200u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001346 EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
Chris Craik8ecf41c2015-11-16 10:27:59 -08001347 << "expect content to be clipped to screen area";
1348 Matrix4 expected;
1349 expected.loadTranslate(0, -2000, 0);
1350 EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
1351 << "expect content to be translated as part of being clipped";
1352}
1353
Chris Craikf158b492016-01-12 14:45:08 -08001354TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001355 SaveLayerAlphaData observedData;
1356 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1357 // Translate and rotate the view so that the only visible part is the top left corner of
Chris Craik8d1f2122015-11-24 16:40:09 -08001358 // 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 -08001359 // bottom of the viewport.
1360 properties.setTranslationX(100);
1361 properties.setTranslationY(100);
1362 properties.setPivotX(0);
1363 properties.setPivotY(0);
1364 properties.setRotation(45);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001365 });
1366 // ceil(sqrt(2) / 2 * 200) = 142
1367 EXPECT_EQ(142u, observedData.layerWidth);
1368 EXPECT_EQ(142u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001369 EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001370 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
1371}
1372
Chris Craikf158b492016-01-12 14:45:08 -08001373TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001374 SaveLayerAlphaData observedData;
1375 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1376 properties.setPivotX(0);
1377 properties.setPivotY(0);
1378 properties.setScaleX(2);
1379 properties.setScaleY(0.5f);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001380 });
1381 EXPECT_EQ(100u, observedData.layerWidth);
1382 EXPECT_EQ(400u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001383 EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001384 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
1385}
1386
Chris Craik6fe991e52015-10-20 09:39:42 -07001387} // namespace uirenderer
1388} // namespace android