blob: e1af257839d766a40cb66682b5d91ad7320d197a [file] [log] [blame]
junov@chromium.org1f9767c2012-02-07 16:27:57 +00001
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "Test.h"
9#include "SkBitmap.h"
junov@chromium.orgce65f382012-10-17 19:36:09 +000010#include "SkBitmapProcShader.h"
junov@chromium.org1f9767c2012-02-07 16:27:57 +000011#include "SkDeferredCanvas.h"
junov@chromium.org88e29142012-08-07 16:48:22 +000012#include "SkDevice.h"
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +000013#include "SkGradientShader.h"
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000014#include "SkShader.h"
junov@chromium.org44324fa2013-08-02 15:36:02 +000015#include "../src/image/SkSurface_Base.h"
16#include "../src/image/SkImagePriv.h"
junov@chromium.org67d74222013-04-12 13:33:01 +000017#if SK_SUPPORT_GPU
18#include "GrContextFactory.h"
19#else
20class GrContextFactory;
21#endif
junov@chromium.org1f9767c2012-02-07 16:27:57 +000022
junov@chromium.org1f9767c2012-02-07 16:27:57 +000023static const int gWidth = 2;
24static const int gHeight = 2;
25
26static void create(SkBitmap* bm, SkBitmap::Config config, SkColor color) {
27 bm->setConfig(config, gWidth, gHeight);
28 bm->allocPixels();
29 bm->eraseColor(color);
30}
31
32static void TestDeferredCanvasBitmapAccess(skiatest::Reporter* reporter) {
33 SkBitmap store;
34
35 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
36 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +000037 SkAutoTUnref<SkDeferredCanvas> canvas(
38#if SK_DEFERRED_CANVAS_USES_FACTORIES
39 SkDeferredCanvas::Create(&device));
40#else
41 SkNEW_ARGS(SkDeferredCanvas, (&device)));
42#endif
junov@chromium.org1f9767c2012-02-07 16:27:57 +000043
junov@chromium.org66070a52013-05-28 17:39:08 +000044 canvas->clear(0x00000000);
junov@chromium.org1f9767c2012-02-07 16:27:57 +000045
46 SkAutoLockPixels alp(store);
47 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
junov@chromium.org66070a52013-05-28 17:39:08 +000048 SkBitmap accessed = canvas->getDevice()->accessBitmap(false);
junov@chromium.org1f9767c2012-02-07 16:27:57 +000049 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
50 REPORTER_ASSERT(reporter, accessed.pixelRef() == store.pixelRef());
51}
52
junov@chromium.org44324fa2013-08-02 15:36:02 +000053class MockSurface : public SkSurface_Base {
54public:
55 MockSurface(int width, int height) : SkSurface_Base(width, height) {
56 clearCounts();
57 fBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
58 fBitmap.allocPixels();
59 }
60
61 virtual SkCanvas* onNewCanvas() SK_OVERRIDE {
62 return SkNEW_ARGS(SkCanvas, (fBitmap));
63 }
64
65 virtual SkSurface* onNewSurface(const SkImage::Info&) SK_OVERRIDE {
66 return NULL;
67 }
68
69 virtual SkImage* onNewImageSnapshot() SK_OVERRIDE {
70 return SkNewImageFromBitmap(fBitmap, true);
71 }
72
73 virtual void onCopyOnWrite(ContentChangeMode mode) SK_OVERRIDE {
74 if (mode == SkSurface::kDiscard_ContentChangeMode) {
75 fDiscardCount++;
76 } else {
77 fRetainCount++;
78 }
79 }
80
81 void clearCounts() {
82 fDiscardCount = 0;
83 fRetainCount = 0;
84 }
85
86 int fDiscardCount, fRetainCount;
87 SkBitmap fBitmap;
88};
89
90static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) {
91 SkAutoTUnref<MockSurface> surface(SkNEW_ARGS(MockSurface, (10, 10)));
92 SkAutoTUnref<SkDeferredCanvas> canvas(
93#if SK_DEFERRED_CANVAS_USES_FACTORIES
94 SkDeferredCanvas::Create(surface.get()));
95#else
96 SkNEW_ARGS(SkDeferredCanvas, (surface.get())));
97#endif
98
99 SkBitmap srcBitmap;
100 srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
101 srcBitmap.allocPixels();
102 srcBitmap.eraseColor(SK_ColorGREEN);
103 // Tests below depend on this bitmap being recognized as opaque
104
105 // Preliminary sanity check: no copy on write if no active snapshot
106 surface->clearCounts();
107 canvas->clear(SK_ColorWHITE);
108 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
109 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
110
111 surface->clearCounts();
112 canvas->flush();
113 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
114 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
115
116 // Case 1: Discard notification happens upon flushing
117 // with an Image attached.
118 surface->clearCounts();
119 SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
120 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
121 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
122
123 surface->clearCounts();
124 canvas->clear(SK_ColorWHITE);
125 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
126 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
127
128 surface->clearCounts();
129 canvas->flush();
130 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
131 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
132
133 // Case 2: Opaque writePixels
134 surface->clearCounts();
135 SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
136 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
137 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
138
139 surface->clearCounts();
140 canvas->writePixels(srcBitmap, 0, 0);
141 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
142 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
143
144 surface->clearCounts();
145 canvas->flush();
146 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
147 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
148
149 // Case 3: writePixels that partially covers the canvas
150 surface->clearCounts();
151 SkAutoTUnref<SkImage> image3(canvas->newImageSnapshot());
152 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
153 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
154
155 surface->clearCounts();
156 canvas->writePixels(srcBitmap, 5, 0);
157 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
158 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
159
160 surface->clearCounts();
161 canvas->flush();
162 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
163 REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
164
165 // Case 4: unpremultiplied opaque writePixels that entirely
166 // covers the canvas
167 surface->clearCounts();
168 SkAutoTUnref<SkImage> image4(canvas->newImageSnapshot());
169 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
170 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
171
172 surface->clearCounts();
173 canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
174 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
175 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
176
177 surface->clearCounts();
178 canvas->flush();
179 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
180 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
181
182 // Case 5: unpremultiplied opaque writePixels that partially
183 // covers the canvas
184 surface->clearCounts();
185 SkAutoTUnref<SkImage> image5(canvas->newImageSnapshot());
186 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
187 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
188
189 surface->clearCounts();
190 canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
191 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
192 REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
193
194 surface->clearCounts();
195 canvas->flush();
196 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
197 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
198
199 // Case 6: unpremultiplied opaque writePixels that entirely
200 // covers the canvas, preceded by clear
201 surface->clearCounts();
202 SkAutoTUnref<SkImage> image6(canvas->newImageSnapshot());
203 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
204 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
205
206 surface->clearCounts();
207 canvas->clear(SK_ColorWHITE);
208 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
209 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
210
211 surface->clearCounts();
212 canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
213 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
214 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
215
216 surface->clearCounts();
217 canvas->flush();
218 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
219 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
220
221 // Case 7: unpremultiplied opaque writePixels that partially
222 // covers the canvas, preceeded by a clear
223 surface->clearCounts();
224 SkAutoTUnref<SkImage> image7(canvas->newImageSnapshot());
225 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
226 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
227
228 surface->clearCounts();
229 canvas->clear(SK_ColorWHITE);
230 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
231 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
232
233 surface->clearCounts();
234 canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
235 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear
236 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
237
238 surface->clearCounts();
239 canvas->flush();
240 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
241 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
242
243 // Case 8: unpremultiplied opaque writePixels that partially
244 // covers the canvas, preceeded by a drawREct that partially
245 // covers the canvas
246 surface->clearCounts();
247 SkAutoTUnref<SkImage> image8(canvas->newImageSnapshot());
248 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
249 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
250
251 surface->clearCounts();
252 SkPaint paint;
253 canvas->drawRect(SkRect::MakeLTRB(0, 0, 5, 5), paint);
254 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
255 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
256
257 surface->clearCounts();
258 canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
259 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
260 REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
261
262 surface->clearCounts();
263 canvas->flush();
264 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
265 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
266}
267
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000268static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
269 SkBitmap store;
270
271 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
272 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000273 SkAutoTUnref<SkDeferredCanvas> canvas(
274#if SK_DEFERRED_CANVAS_USES_FACTORIES
275 SkDeferredCanvas::Create(&device));
276#else
277 SkNEW_ARGS(SkDeferredCanvas, (&device)));
278#endif
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000279
junov@chromium.org66070a52013-05-28 17:39:08 +0000280 canvas->clear(0x00000000);
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000281
282 SkAutoLockPixels alp(store);
283 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
junov@chromium.org66070a52013-05-28 17:39:08 +0000284 canvas->flush();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000285 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
286}
287
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000288static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
289 SkBitmap store;
290 SkRect fullRect;
291 fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
292 SkIntToScalar(gHeight));
293 SkRect partialRect;
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000294 partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
295 SkIntToScalar(1), SkIntToScalar(1));
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000296 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
297 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000298 SkAutoTUnref<SkDeferredCanvas> canvas(
299#if SK_DEFERRED_CANVAS_USES_FACTORIES
300 SkDeferredCanvas::Create(&device));
301#else
302 SkNEW_ARGS(SkDeferredCanvas, (&device)));
303#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000304
305 // verify that frame is intially fresh
junov@chromium.org66070a52013-05-28 17:39:08 +0000306 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000307 // no clearing op since last call to isFreshFrame -> not fresh
junov@chromium.org66070a52013-05-28 17:39:08 +0000308 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000309
310 // Verify that clear triggers a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +0000311 canvas->clear(0x00000000);
312 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000313
314 // Verify that clear with saved state triggers a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +0000315 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
316 canvas->clear(0x00000000);
317 canvas->restore();
318 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000319
320 // Verify that clear within a layer does NOT trigger a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +0000321 canvas->saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
322 canvas->clear(0x00000000);
323 canvas->restore();
324 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000325
326 // Verify that a clear with clipping triggers a fresh frame
327 // (clear is not affected by clipping)
junov@chromium.org66070a52013-05-28 17:39:08 +0000328 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
329 canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
330 canvas->clear(0x00000000);
331 canvas->restore();
332 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000333
334 // Verify that full frame rects with different forms of opaque paint
335 // trigger frames to be marked as fresh
336 {
337 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000338 paint.setStyle(SkPaint::kFill_Style);
339 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000340 canvas->drawRect(fullRect, paint);
341 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000342 }
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +0000343 {
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000344 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000345 paint.setStyle(SkPaint::kFill_Style);
346 paint.setAlpha(255);
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000347 paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
junov@chromium.org66070a52013-05-28 17:39:08 +0000348 canvas->drawRect(fullRect, paint);
349 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000350 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000351 {
352 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000353 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000354 SkBitmap bmp;
355 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
356 bmp.setIsOpaque(true);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000357 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000358 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
359 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000360 canvas->drawRect(fullRect, paint);
361 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000362 }
363
364 // Verify that full frame rects with different forms of non-opaque paint
365 // do not trigger frames to be marked as fresh
366 {
367 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000368 paint.setStyle(SkPaint::kFill_Style);
369 paint.setAlpha(254);
junov@chromium.org66070a52013-05-28 17:39:08 +0000370 canvas->drawRect(fullRect, paint);
371 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000372 }
373 {
374 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000375 paint.setStyle(SkPaint::kFill_Style);
376 // Defining a cone that partially overlaps the canvas
377 const SkPoint pt1 = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
378 const SkScalar r1 = SkIntToScalar(1);
379 const SkPoint pt2 = SkPoint::Make(SkIntToScalar(10), SkIntToScalar(0));
380 const SkScalar r2 = SkIntToScalar(5);
381 const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
382 const SkScalar pos[2] = {0, SK_Scalar1};
383 SkShader* shader = SkGradientShader::CreateTwoPointConical(
384 pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode, NULL);
385 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000386 canvas->drawRect(fullRect, paint);
387 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000388 }
389 {
390 SkPaint paint;
391 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000392 SkBitmap bmp;
393 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
394 bmp.setIsOpaque(false);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000395 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000396 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
397 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000398 canvas->drawRect(fullRect, paint);
399 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000400 }
401
402 // Verify that incomplete coverage does not trigger a fresh frame
403 {
404 SkPaint paint;
405 paint.setStyle(SkPaint::kFill_Style);
406 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000407 canvas->drawRect(partialRect, paint);
408 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000409 }
410
411 // Verify that incomplete coverage due to clipping does not trigger a fresh
412 // frame
413 {
junov@chromium.org66070a52013-05-28 17:39:08 +0000414 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
415 canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000416 SkPaint paint;
417 paint.setStyle(SkPaint::kFill_Style);
418 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000419 canvas->drawRect(fullRect, paint);
420 canvas->restore();
421 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000422 }
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000423 {
junov@chromium.org66070a52013-05-28 17:39:08 +0000424 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000425 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000426 paint.setStyle(SkPaint::kFill_Style);
427 paint.setAlpha(255);
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000428 SkPath path;
429 path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
junov@chromium.org66070a52013-05-28 17:39:08 +0000430 canvas->clipPath(path, SkRegion::kIntersect_Op, false);
431 canvas->drawRect(fullRect, paint);
432 canvas->restore();
433 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000434 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000435
436 // Verify that stroked rect does not trigger a fresh frame
437 {
438 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000439 paint.setStyle(SkPaint::kStroke_Style);
440 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000441 canvas->drawRect(fullRect, paint);
442 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000443 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000444
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000445 // Verify kSrcMode triggers a fresh frame even with transparent color
446 {
447 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000448 paint.setStyle(SkPaint::kFill_Style);
449 paint.setAlpha(100);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000450 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
junov@chromium.org66070a52013-05-28 17:39:08 +0000451 canvas->drawRect(fullRect, paint);
452 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000453 }
454}
455
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000456class MockDevice : public SkDevice {
457public:
458 MockDevice(const SkBitmap& bm) : SkDevice(bm) {
459 fDrawBitmapCallCount = 0;
460 }
461 virtual void drawBitmap(const SkDraw&, const SkBitmap&,
commit-bot@chromium.org3e2ea252013-07-23 11:28:45 +0000462 const SkMatrix&, const SkPaint&) SK_OVERRIDE {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000463 fDrawBitmapCallCount++;
464 }
465
466 int fDrawBitmapCallCount;
467};
468
469// Verifies that the deferred canvas triggers a flush when its memory
470// limit is exceeded
471static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
472 SkBitmap store;
473 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
474 store.allocPixels();
475 MockDevice mockDevice(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000476 SkAutoTUnref<SkDeferredCanvas> canvas(
477#if SK_DEFERRED_CANVAS_USES_FACTORIES
478 SkDeferredCanvas::Create(&mockDevice));
479#else
480 SkNEW_ARGS(SkDeferredCanvas, (&mockDevice)));
481#endif
482 canvas->setMaxRecordingStorage(160000);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000483
484 SkBitmap sourceImage;
485 // 100 by 100 image, takes 40,000 bytes in memory
486 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
487 sourceImage.allocPixels();
488
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000489 for (int i = 0; i < 5; i++) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000490 sourceImage.notifyPixelsChanged(); // to force re-serialization
junov@chromium.org66070a52013-05-28 17:39:08 +0000491 canvas->drawBitmap(sourceImage, 0, 0, NULL);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000492 }
493
scroggo@google.com15011ee2012-07-26 20:03:32 +0000494 REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000495}
496
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000497class NotificationCounter : public SkDeferredCanvas::NotificationClient {
498public:
499 NotificationCounter() {
junov@google.com52a00ca2012-10-01 15:27:14 +0000500 fPrepareForDrawCount = fStorageAllocatedChangedCount =
501 fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000502 }
503
504 virtual void prepareForDraw() SK_OVERRIDE {
505 fPrepareForDrawCount++;
506 }
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000507 virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000508 fStorageAllocatedChangedCount++;
509 }
510 virtual void flushedDrawCommands() SK_OVERRIDE {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000511 fFlushedDrawCommandsCount++;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000512 }
junov@google.com52a00ca2012-10-01 15:27:14 +0000513 virtual void skippedPendingDrawCommands() SK_OVERRIDE {
514 fSkippedPendingDrawCommandsCount++;
515 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000516
517 int fPrepareForDrawCount;
518 int fStorageAllocatedChangedCount;
519 int fFlushedDrawCommandsCount;
junov@google.com52a00ca2012-10-01 15:27:14 +0000520 int fSkippedPendingDrawCommandsCount;
robertphillips@google.com59903972013-02-07 21:02:23 +0000521
522private:
523 typedef SkDeferredCanvas::NotificationClient INHERITED;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000524};
525
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000526static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
527 SkBitmap store;
528 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
529 store.allocPixels();
530 SkDevice device(store);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000531 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000532 SkAutoTUnref<SkDeferredCanvas> canvas(
533#if SK_DEFERRED_CANVAS_USES_FACTORIES
534 SkDeferredCanvas::Create(&device));
535#else
536 SkNEW_ARGS(SkDeferredCanvas, (&device)));
537#endif
538 canvas->setNotificationClient(&notificationCounter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000539
540 const int imageCount = 2;
541 SkBitmap sourceImages[imageCount];
542 for (int i = 0; i < imageCount; i++)
543 {
544 sourceImages[i].setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
545 sourceImages[i].allocPixels();
546 }
547
548 size_t bitmapSize = sourceImages[0].getSize();
549
junov@chromium.org66070a52013-05-28 17:39:08 +0000550 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000551 REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000552 // stored bitmap + drawBitmap command
junov@chromium.org66070a52013-05-28 17:39:08 +0000553 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > bitmapSize);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000554
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000555 // verify that nothing can be freed at this point
junov@chromium.org66070a52013-05-28 17:39:08 +0000556 REPORTER_ASSERT(reporter, 0 == canvas->freeMemoryIfPossible(~0U));
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000557
558 // verify that flush leaves image in cache
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000559 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
560 REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000561 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000562 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
563 REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000564 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000565
566 // verify that after a flush, cached image can be freed
junov@chromium.org66070a52013-05-28 17:39:08 +0000567 REPORTER_ASSERT(reporter, canvas->freeMemoryIfPossible(~0U) >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000568
569 // Verify that caching works for avoiding multiple copies of the same bitmap
junov@chromium.org66070a52013-05-28 17:39:08 +0000570 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000571 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000572 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000573 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
574 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000575 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < 2 * bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000576
577 // Verify partial eviction based on bytesToFree
junov@chromium.org66070a52013-05-28 17:39:08 +0000578 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000579 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000580 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000581 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000582 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2 * bitmapSize);
583 size_t bytesFreed = canvas->freeMemoryIfPossible(1);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000584 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000585 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
586 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
587
rmistry@google.comd6176b02012-08-23 18:14:13 +0000588 // Verifiy that partial purge works, image zero is in cache but not reffed by
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000589 // a pending draw, while image 1 is locked-in.
junov@chromium.org66070a52013-05-28 17:39:08 +0000590 canvas->freeMemoryIfPossible(~0U);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000591 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000592 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
593 canvas->flush();
594 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
595 bytesFreed = canvas->freeMemoryIfPossible(~0U);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000596 // only one bitmap should have been freed.
597 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
598 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
599 // Clear for next test
junov@chromium.org66070a52013-05-28 17:39:08 +0000600 canvas->flush();
601 canvas->freeMemoryIfPossible(~0U);
602 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000603
604 // Verify the image cache is sensitive to genID bumps
junov@chromium.org66070a52013-05-28 17:39:08 +0000605 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000606 sourceImages[1].notifyPixelsChanged();
junov@chromium.org66070a52013-05-28 17:39:08 +0000607 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
608 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2*bitmapSize);
junov@google.com52a00ca2012-10-01 15:27:14 +0000609
610 // Verify that nothing in this test caused commands to be skipped
611 REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
612}
613
614static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
615 SkBitmap store;
616 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
617 store.allocPixels();
618 SkDevice device(store);
619 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000620 SkAutoTUnref<SkDeferredCanvas> canvas(
621#if SK_DEFERRED_CANVAS_USES_FACTORIES
622 SkDeferredCanvas::Create(&device));
623#else
624 SkNEW_ARGS(SkDeferredCanvas, (&device)));
625#endif
626 canvas->setNotificationClient(&notificationCounter);
627 canvas->clear(0x0);
junov@google.com52a00ca2012-10-01 15:27:14 +0000628 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
629 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000630 canvas->flush();
junov@google.com52a00ca2012-10-01 15:27:14 +0000631 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
632 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
633
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000634}
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000635
junov@chromium.orgce65f382012-10-17 19:36:09 +0000636static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
637 // This is a regression test for crbug.com/155875
638 // This test covers a code path that inserts bitmaps into the bitmap heap through the
639 // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
640 // the flattening and unflattening of the shader.
641 SkBitmap store;
642 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
643 store.allocPixels();
644 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000645 SkAutoTUnref<SkDeferredCanvas> canvas(
646#if SK_DEFERRED_CANVAS_USES_FACTORIES
647 SkDeferredCanvas::Create(&device));
648#else
649 SkNEW_ARGS(SkDeferredCanvas, (&device)));
650#endif
junov@chromium.orgce65f382012-10-17 19:36:09 +0000651 // test will fail if nbIterations is not in sync with
652 // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
653 const int nbIterations = 5;
654 size_t bytesAllocated = 0;
655 for(int pass = 0; pass < 2; ++pass) {
656 for(int i = 0; i < nbIterations; ++i) {
657 SkPaint paint;
658 SkBitmap paintPattern;
659 paintPattern.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
660 paintPattern.allocPixels();
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000661 paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
junov@chromium.orgce65f382012-10-17 19:36:09 +0000662 (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000663 canvas->drawPaint(paint);
664 canvas->flush();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000665
666 // In the first pass, memory allocation should be monotonically increasing as
667 // the bitmap heap slots fill up. In the second pass memory allocation should be
668 // stable as bitmap heap slots get recycled.
junov@chromium.org66070a52013-05-28 17:39:08 +0000669 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000670 if (pass == 0) {
671 REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
672 bytesAllocated = newBytesAllocated;
673 } else {
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000674 REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000675 }
676 }
677 }
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000678 // All cached resources should be evictable since last canvas call was flush()
junov@chromium.org66070a52013-05-28 17:39:08 +0000679 canvas->freeMemoryIfPossible(~0U);
680 REPORTER_ASSERT(reporter, 0 == canvas->storageAllocatedForRecording());
junov@chromium.orgce65f382012-10-17 19:36:09 +0000681}
682
sugoi@google.com7775fd52012-11-21 15:47:04 +0000683static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
684 SkBitmap store;
685 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
686 store.allocPixels();
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000687
sugoi@google.com7775fd52012-11-21 15:47:04 +0000688 SkBitmap sourceImage;
689 // 100 by 100 image, takes 40,000 bytes in memory
690 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
691 sourceImage.allocPixels();
692
693 // 1 under : should not store the image
694 {
695 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000696 SkAutoTUnref<SkDeferredCanvas> canvas(
697#if SK_DEFERRED_CANVAS_USES_FACTORIES
698 SkDeferredCanvas::Create(&device));
699#else
700 SkNEW_ARGS(SkDeferredCanvas, (&device)));
701#endif
702 canvas->setBitmapSizeThreshold(39999);
703 canvas->drawBitmap(sourceImage, 0, 0, NULL);
704 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000705 REPORTER_ASSERT(reporter, newBytesAllocated == 0);
706 }
707
708 // exact value : should store the image
709 {
710 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000711 SkAutoTUnref<SkDeferredCanvas> canvas(
712#if SK_DEFERRED_CANVAS_USES_FACTORIES
713 SkDeferredCanvas::Create(&device));
714#else
715 SkNEW_ARGS(SkDeferredCanvas, (&device)));
716#endif
717 canvas->setBitmapSizeThreshold(40000);
718 canvas->drawBitmap(sourceImage, 0, 0, NULL);
719 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000720 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
721 }
722
723 // 1 over : should still store the image
724 {
725 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000726 SkAutoTUnref<SkDeferredCanvas> canvas(
727#if SK_DEFERRED_CANVAS_USES_FACTORIES
728 SkDeferredCanvas::Create(&device));
729#else
730 SkNEW_ARGS(SkDeferredCanvas, (&device)));
731#endif
732 canvas->setBitmapSizeThreshold(40001);
733 canvas->drawBitmap(sourceImage, 0, 0, NULL);
734 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000735 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
736 }
737}
738
junov@chromium.org67d74222013-04-12 13:33:01 +0000739
740typedef void* PixelPtr;
741// Returns an opaque pointer which, either points to a GrTexture or RAM pixel
742// buffer. Used to test pointer equality do determine whether a surface points
743// to the same pixel data storage as before.
junov@chromium.org3c5ec8d2013-04-12 13:34:47 +0000744static PixelPtr getSurfacePixelPtr(SkSurface* surface, bool useGpu) {
junov@chromium.org67d74222013-04-12 13:33:01 +0000745 return useGpu ? surface->getCanvas()->getDevice()->accessBitmap(false).getTexture() :
746 surface->getCanvas()->getDevice()->accessBitmap(false).getPixels();
747}
748
749static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
750 SkImage::Info imageSpec = {
751 10, // width
752 10, // height
753 SkImage::kPMColor_ColorType,
754 SkImage::kPremul_AlphaType
755 };
756 SkSurface* surface;
757 bool useGpu = NULL != factory;
758#if SK_SUPPORT_GPU
759 if (useGpu) {
760 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
761 surface = SkSurface::NewRenderTarget(context, imageSpec);
762 } else {
763 surface = SkSurface::NewRaster(imageSpec);
764 }
765#else
766 SkASSERT(!useGpu);
767 surface = SkSurface::NewRaster(imageSpec);
768#endif
769 SkASSERT(NULL != surface);
770 SkAutoTUnref<SkSurface> aur(surface);
junov@chromium.org66070a52013-05-28 17:39:08 +0000771 SkAutoTUnref<SkDeferredCanvas> canvas(
772#if SK_DEFERRED_CANVAS_USES_FACTORIES
773 SkDeferredCanvas::Create(surface));
774#else
775 SkNEW_ARGS(SkDeferredCanvas, (surface)));
776#endif
junov@chromium.org67d74222013-04-12 13:33:01 +0000777
junov@chromium.org66070a52013-05-28 17:39:08 +0000778 SkImage* image1 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000779 SkAutoTUnref<SkImage> aur_i1(image1);
780 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
781 // The following clear would normally trigger a copy on write, but
782 // it won't because rendering is deferred.
junov@chromium.org66070a52013-05-28 17:39:08 +0000783 canvas->clear(SK_ColorBLACK);
junov@chromium.org67d74222013-04-12 13:33:01 +0000784 // Obtaining a snapshot directly from the surface (as opposed to the
785 // SkDeferredCanvas) will not trigger a flush of deferred draw operations
786 // and will therefore return the same image as the previous snapshot.
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000787 SkImage* image2 = surface->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000788 SkAutoTUnref<SkImage> aur_i2(image2);
789 // Images identical because of deferral
790 REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID());
791 // Now we obtain a snpshot via the deferred canvas, which triggers a flush.
792 // Because there is a pending clear, this will generate a different image.
junov@chromium.org66070a52013-05-28 17:39:08 +0000793 SkImage* image3 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000794 SkAutoTUnref<SkImage> aur_i3(image3);
795 REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID());
796 // Verify that backing store is now a different buffer because of copy on
797 // write
798 PixelPtr pixels2 = getSurfacePixelPtr(surface, useGpu);
799 REPORTER_ASSERT(reporter, pixels1 != pixels2);
junov@chromium.org9becf002013-04-15 18:15:23 +0000800 // Verify copy-on write with a draw operation that gets deferred by
801 // the in order draw buffer.
802 SkPaint paint;
junov@chromium.org66070a52013-05-28 17:39:08 +0000803 canvas->drawPaint(paint);
804 SkImage* image4 = canvas->newImageSnapshot(); // implicit flush
junov@chromium.org9becf002013-04-15 18:15:23 +0000805 SkAutoTUnref<SkImage> aur_i4(image4);
806 REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID());
junov@chromium.org67d74222013-04-12 13:33:01 +0000807 PixelPtr pixels3 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org9becf002013-04-15 18:15:23 +0000808 REPORTER_ASSERT(reporter, pixels2 != pixels3);
junov@chromium.org67d74222013-04-12 13:33:01 +0000809 // Verify that a direct canvas flush with a pending draw does not trigger
810 // a copy on write when the surface is not sharing its buffer with an
811 // SkImage.
junov@chromium.org66070a52013-05-28 17:39:08 +0000812 canvas->clear(SK_ColorWHITE);
813 canvas->flush();
junov@chromium.org67d74222013-04-12 13:33:01 +0000814 PixelPtr pixels4 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org66070a52013-05-28 17:39:08 +0000815 canvas->drawPaint(paint);
816 canvas->flush();
junov@chromium.org9becf002013-04-15 18:15:23 +0000817 PixelPtr pixels5 = getSurfacePixelPtr(surface, useGpu);
818 REPORTER_ASSERT(reporter, pixels4 == pixels5);
junov@chromium.org67d74222013-04-12 13:33:01 +0000819}
820
junov@chromium.org7070f762013-05-24 17:13:00 +0000821static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
822 SkImage::Info imageSpec = {
823 10, // width
824 10, // height
825 SkImage::kPMColor_ColorType,
826 SkImage::kPremul_AlphaType
827 };
828 SkSurface* surface;
829 SkSurface* alternateSurface;
830 bool useGpu = NULL != factory;
831#if SK_SUPPORT_GPU
832 if (useGpu) {
833 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
834 surface = SkSurface::NewRenderTarget(context, imageSpec);
835 alternateSurface = SkSurface::NewRenderTarget(context, imageSpec);
836 } else {
837 surface = SkSurface::NewRaster(imageSpec);
838 alternateSurface = SkSurface::NewRaster(imageSpec);
839 }
840#else
841 SkASSERT(!useGpu);
842 surface = SkSurface::NewRaster(imageSpec);
843 alternateSurface = SkSurface::NewRaster(imageSpec);
844#endif
845 SkASSERT(NULL != surface);
846 SkASSERT(NULL != alternateSurface);
847 SkAutoTUnref<SkSurface> aur1(surface);
848 SkAutoTUnref<SkSurface> aur2(alternateSurface);
849 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
850 PixelPtr pixels2 = getSurfacePixelPtr(alternateSurface, useGpu);
junov@chromium.org66070a52013-05-28 17:39:08 +0000851 SkAutoTUnref<SkDeferredCanvas> canvas(
852#if SK_DEFERRED_CANVAS_USES_FACTORIES
853 SkDeferredCanvas::Create(surface));
854#else
855 SkNEW_ARGS(SkDeferredCanvas, (surface)));
856#endif
857 SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
858 canvas->setSurface(alternateSurface);
859 SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
junov@chromium.org7070f762013-05-24 17:13:00 +0000860 REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID());
861 // Verify that none of the above operations triggered a surface copy on write.
862 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
863 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) == pixels2);
864 // Verify that a flushed draw command will trigger a copy on write on alternateSurface.
junov@chromium.org66070a52013-05-28 17:39:08 +0000865 canvas->clear(SK_ColorWHITE);
866 canvas->flush();
junov@chromium.org7070f762013-05-24 17:13:00 +0000867 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
868 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) != pixels2);
869}
870
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000871static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) {
872 SkBitmap store;
873 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
874 store.allocPixels();
875 SkDevice device(store);
876 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000877 SkAutoTUnref<SkDeferredCanvas> canvas(
878#if SK_DEFERRED_CANVAS_USES_FACTORIES
879 SkDeferredCanvas::Create(&device));
880#else
881 SkNEW_ARGS(SkDeferredCanvas, (&device)));
882#endif
883 canvas->setNotificationClient(&notificationCounter);
884 SkAutoTUnref<SkDevice> secondaryDevice(canvas->createCompatibleDevice(
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000885 SkBitmap::kARGB_8888_Config, 10, 10, device.isOpaque()));
886 SkCanvas secondaryCanvas(secondaryDevice.get());
887 SkRect rect = SkRect::MakeWH(5, 5);
888 SkPaint paint;
889 // After spawning a compatible canvas:
890 // 1) Verify that secondary canvas is usable and does not report to the notification client.
891 secondaryCanvas.drawRect(rect, paint);
892 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0);
893 // 2) Verify that original canvas is usable and still reports to the notification client.
junov@chromium.org66070a52013-05-28 17:39:08 +0000894 canvas->drawRect(rect, paint);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000895 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1);
896}
897
junov@chromium.org67d74222013-04-12 13:33:01 +0000898static void TestDeferredCanvas(skiatest::Reporter* reporter, GrContextFactory* factory) {
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000899 TestDeferredCanvasBitmapAccess(reporter);
900 TestDeferredCanvasFlush(reporter);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000901 TestDeferredCanvasFreshFrame(reporter);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000902 TestDeferredCanvasMemoryLimit(reporter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000903 TestDeferredCanvasBitmapCaching(reporter);
junov@google.com52a00ca2012-10-01 15:27:14 +0000904 TestDeferredCanvasSkip(reporter);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000905 TestDeferredCanvasBitmapShaderNoLeak(reporter);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000906 TestDeferredCanvasBitmapSizeThreshold(reporter);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000907 TestDeferredCanvasCreateCompatibleDevice(reporter);
junov@chromium.org44324fa2013-08-02 15:36:02 +0000908 TestDeferredCanvasWritePixelsToSurface(reporter);
junov@chromium.org67d74222013-04-12 13:33:01 +0000909 TestDeferredCanvasSurface(reporter, NULL);
junov@chromium.org7070f762013-05-24 17:13:00 +0000910 TestDeferredCanvasSetSurface(reporter, NULL);
junov@chromium.org67d74222013-04-12 13:33:01 +0000911 if (NULL != factory) {
912 TestDeferredCanvasSurface(reporter, factory);
junov@chromium.org7070f762013-05-24 17:13:00 +0000913 TestDeferredCanvasSetSurface(reporter, factory);
junov@chromium.org67d74222013-04-12 13:33:01 +0000914 }
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000915}
916
917#include "TestClassDef.h"
junov@chromium.org67d74222013-04-12 13:33:01 +0000918DEFINE_GPUTESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas)