blob: 7593ba877ccd611f74f498e0928056b4e0ea4632 [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"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000010#include "SkBitmapDevice.h"
junov@chromium.orgce65f382012-10-17 19:36:09 +000011#include "SkBitmapProcShader.h"
junov@chromium.org1f9767c2012-02-07 16:27:57 +000012#include "SkDeferredCanvas.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);
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000036 SkBitmapDevice device(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +000037 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org1f9767c2012-02-07 16:27:57 +000038
junov@chromium.org66070a52013-05-28 17:39:08 +000039 canvas->clear(0x00000000);
junov@chromium.org1f9767c2012-02-07 16:27:57 +000040
41 SkAutoLockPixels alp(store);
42 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
junov@chromium.org66070a52013-05-28 17:39:08 +000043 SkBitmap accessed = canvas->getDevice()->accessBitmap(false);
junov@chromium.org1f9767c2012-02-07 16:27:57 +000044 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
45 REPORTER_ASSERT(reporter, accessed.pixelRef() == store.pixelRef());
46}
47
junov@chromium.org44324fa2013-08-02 15:36:02 +000048class MockSurface : public SkSurface_Base {
49public:
50 MockSurface(int width, int height) : SkSurface_Base(width, height) {
51 clearCounts();
52 fBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
53 fBitmap.allocPixels();
54 }
55
56 virtual SkCanvas* onNewCanvas() SK_OVERRIDE {
57 return SkNEW_ARGS(SkCanvas, (fBitmap));
58 }
59
60 virtual SkSurface* onNewSurface(const SkImage::Info&) SK_OVERRIDE {
61 return NULL;
62 }
63
64 virtual SkImage* onNewImageSnapshot() SK_OVERRIDE {
65 return SkNewImageFromBitmap(fBitmap, true);
66 }
67
68 virtual void onCopyOnWrite(ContentChangeMode mode) SK_OVERRIDE {
69 if (mode == SkSurface::kDiscard_ContentChangeMode) {
70 fDiscardCount++;
71 } else {
72 fRetainCount++;
73 }
74 }
75
76 void clearCounts() {
77 fDiscardCount = 0;
skia.committer@gmail.comea4b7972013-08-06 07:01:27 +000078 fRetainCount = 0;
junov@chromium.org44324fa2013-08-02 15:36:02 +000079 }
80
81 int fDiscardCount, fRetainCount;
82 SkBitmap fBitmap;
83};
84
85static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) {
86 SkAutoTUnref<MockSurface> surface(SkNEW_ARGS(MockSurface, (10, 10)));
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +000087 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
junov@chromium.org44324fa2013-08-02 15:36:02 +000088
89 SkBitmap srcBitmap;
90 srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
91 srcBitmap.allocPixels();
92 srcBitmap.eraseColor(SK_ColorGREEN);
93 // Tests below depend on this bitmap being recognized as opaque
94
95 // Preliminary sanity check: no copy on write if no active snapshot
96 surface->clearCounts();
97 canvas->clear(SK_ColorWHITE);
98 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
99 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
100
101 surface->clearCounts();
102 canvas->flush();
103 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
104 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
105
106 // Case 1: Discard notification happens upon flushing
107 // with an Image attached.
108 surface->clearCounts();
109 SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
110 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
111 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
112
113 surface->clearCounts();
114 canvas->clear(SK_ColorWHITE);
115 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
116 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
117
118 surface->clearCounts();
119 canvas->flush();
120 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
121 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
122
123 // Case 2: Opaque writePixels
124 surface->clearCounts();
125 SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
126 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
127 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
128
129 surface->clearCounts();
130 canvas->writePixels(srcBitmap, 0, 0);
131 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
132 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
133
134 surface->clearCounts();
135 canvas->flush();
136 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
137 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
138
139 // Case 3: writePixels that partially covers the canvas
140 surface->clearCounts();
141 SkAutoTUnref<SkImage> image3(canvas->newImageSnapshot());
142 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
143 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
144
145 surface->clearCounts();
146 canvas->writePixels(srcBitmap, 5, 0);
147 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
148 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
149
150 surface->clearCounts();
151 canvas->flush();
152 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
153 REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
154
155 // Case 4: unpremultiplied opaque writePixels that entirely
156 // covers the canvas
157 surface->clearCounts();
158 SkAutoTUnref<SkImage> image4(canvas->newImageSnapshot());
159 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
160 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
161
162 surface->clearCounts();
163 canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
164 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
165 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
166
167 surface->clearCounts();
168 canvas->flush();
169 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
170 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
171
172 // Case 5: unpremultiplied opaque writePixels that partially
173 // covers the canvas
174 surface->clearCounts();
175 SkAutoTUnref<SkImage> image5(canvas->newImageSnapshot());
176 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
177 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
178
179 surface->clearCounts();
180 canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
181 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
182 REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
183
184 surface->clearCounts();
185 canvas->flush();
186 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
187 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
188
189 // Case 6: unpremultiplied opaque writePixels that entirely
190 // covers the canvas, preceded by clear
191 surface->clearCounts();
192 SkAutoTUnref<SkImage> image6(canvas->newImageSnapshot());
193 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
194 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
195
196 surface->clearCounts();
197 canvas->clear(SK_ColorWHITE);
198 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
199 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
200
201 surface->clearCounts();
202 canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
203 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
204 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
205
206 surface->clearCounts();
207 canvas->flush();
208 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
209 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
210
211 // Case 7: unpremultiplied opaque writePixels that partially
212 // covers the canvas, preceeded by a clear
213 surface->clearCounts();
214 SkAutoTUnref<SkImage> image7(canvas->newImageSnapshot());
215 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
216 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
217
218 surface->clearCounts();
219 canvas->clear(SK_ColorWHITE);
220 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
221 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
222
223 surface->clearCounts();
224 canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
225 REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear
226 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
227
228 surface->clearCounts();
229 canvas->flush();
230 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
231 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
232
233 // Case 8: unpremultiplied opaque writePixels that partially
234 // covers the canvas, preceeded by a drawREct that partially
235 // covers the canvas
236 surface->clearCounts();
237 SkAutoTUnref<SkImage> image8(canvas->newImageSnapshot());
238 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
239 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
240
241 surface->clearCounts();
242 SkPaint paint;
243 canvas->drawRect(SkRect::MakeLTRB(0, 0, 5, 5), paint);
244 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
245 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
246
247 surface->clearCounts();
248 canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
249 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
250 REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
251
252 surface->clearCounts();
253 canvas->flush();
254 REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
255 REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
256}
257
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000258static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
259 SkBitmap store;
260
261 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000262 SkBitmapDevice device(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000263 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000264
junov@chromium.org66070a52013-05-28 17:39:08 +0000265 canvas->clear(0x00000000);
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000266
267 SkAutoLockPixels alp(store);
268 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
junov@chromium.org66070a52013-05-28 17:39:08 +0000269 canvas->flush();
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000270 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
271}
272
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000273static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
274 SkBitmap store;
275 SkRect fullRect;
276 fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
277 SkIntToScalar(gHeight));
278 SkRect partialRect;
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000279 partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
280 SkIntToScalar(1), SkIntToScalar(1));
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000281 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000282 SkBitmapDevice device(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000283 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000284
285 // verify that frame is intially fresh
junov@chromium.org66070a52013-05-28 17:39:08 +0000286 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000287 // no clearing op since last call to isFreshFrame -> not fresh
junov@chromium.org66070a52013-05-28 17:39:08 +0000288 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000289
290 // Verify that clear triggers a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +0000291 canvas->clear(0x00000000);
292 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000293
294 // Verify that clear with saved state triggers a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +0000295 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
296 canvas->clear(0x00000000);
297 canvas->restore();
298 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000299
300 // Verify that clear within a layer does NOT trigger a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +0000301 canvas->saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
302 canvas->clear(0x00000000);
303 canvas->restore();
304 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000305
306 // Verify that a clear with clipping triggers a fresh frame
307 // (clear is not affected by clipping)
junov@chromium.org66070a52013-05-28 17:39:08 +0000308 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
309 canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
310 canvas->clear(0x00000000);
311 canvas->restore();
312 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000313
314 // Verify that full frame rects with different forms of opaque paint
315 // trigger frames to be marked as fresh
316 {
317 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000318 paint.setStyle(SkPaint::kFill_Style);
319 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000320 canvas->drawRect(fullRect, paint);
321 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000322 }
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +0000323 {
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000324 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000325 paint.setStyle(SkPaint::kFill_Style);
326 paint.setAlpha(255);
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000327 paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
junov@chromium.org66070a52013-05-28 17:39:08 +0000328 canvas->drawRect(fullRect, paint);
329 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000330 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000331 {
332 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000333 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000334 SkBitmap bmp;
335 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
336 bmp.setIsOpaque(true);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000337 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000338 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
339 paint.setShader(shader)->unref();
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 }
343
344 // Verify that full frame rects with different forms of non-opaque paint
345 // do not trigger frames to be marked as fresh
346 {
347 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000348 paint.setStyle(SkPaint::kFill_Style);
349 paint.setAlpha(254);
junov@chromium.org66070a52013-05-28 17:39:08 +0000350 canvas->drawRect(fullRect, paint);
351 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000352 }
353 {
354 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000355 paint.setStyle(SkPaint::kFill_Style);
356 // Defining a cone that partially overlaps the canvas
357 const SkPoint pt1 = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
358 const SkScalar r1 = SkIntToScalar(1);
359 const SkPoint pt2 = SkPoint::Make(SkIntToScalar(10), SkIntToScalar(0));
360 const SkScalar r2 = SkIntToScalar(5);
361 const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
362 const SkScalar pos[2] = {0, SK_Scalar1};
363 SkShader* shader = SkGradientShader::CreateTwoPointConical(
364 pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode, NULL);
365 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000366 canvas->drawRect(fullRect, paint);
367 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000368 }
369 {
370 SkPaint paint;
371 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000372 SkBitmap bmp;
373 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
374 bmp.setIsOpaque(false);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000375 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000376 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
377 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000378 canvas->drawRect(fullRect, paint);
379 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000380 }
381
382 // Verify that incomplete coverage does not trigger a fresh frame
383 {
384 SkPaint paint;
385 paint.setStyle(SkPaint::kFill_Style);
386 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000387 canvas->drawRect(partialRect, paint);
388 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000389 }
390
391 // Verify that incomplete coverage due to clipping does not trigger a fresh
392 // frame
393 {
junov@chromium.org66070a52013-05-28 17:39:08 +0000394 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
395 canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000396 SkPaint paint;
397 paint.setStyle(SkPaint::kFill_Style);
398 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000399 canvas->drawRect(fullRect, paint);
400 canvas->restore();
401 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000402 }
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000403 {
junov@chromium.org66070a52013-05-28 17:39:08 +0000404 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000405 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000406 paint.setStyle(SkPaint::kFill_Style);
407 paint.setAlpha(255);
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000408 SkPath path;
409 path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
junov@chromium.org66070a52013-05-28 17:39:08 +0000410 canvas->clipPath(path, SkRegion::kIntersect_Op, false);
411 canvas->drawRect(fullRect, paint);
412 canvas->restore();
413 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000414 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000415
416 // Verify that stroked rect does not trigger a fresh frame
417 {
418 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000419 paint.setStyle(SkPaint::kStroke_Style);
420 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000421 canvas->drawRect(fullRect, paint);
422 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000423 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000424
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000425 // Verify kSrcMode triggers a fresh frame even with transparent color
426 {
427 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000428 paint.setStyle(SkPaint::kFill_Style);
429 paint.setAlpha(100);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000430 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
junov@chromium.org66070a52013-05-28 17:39:08 +0000431 canvas->drawRect(fullRect, paint);
432 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000433 }
434}
435
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000436class MockDevice : public SkBitmapDevice {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000437public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000438 MockDevice(const SkBitmap& bm) : SkBitmapDevice(bm) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000439 fDrawBitmapCallCount = 0;
440 }
441 virtual void drawBitmap(const SkDraw&, const SkBitmap&,
commit-bot@chromium.org3e2ea252013-07-23 11:28:45 +0000442 const SkMatrix&, const SkPaint&) SK_OVERRIDE {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000443 fDrawBitmapCallCount++;
444 }
445
446 int fDrawBitmapCallCount;
447};
448
449// Verifies that the deferred canvas triggers a flush when its memory
450// limit is exceeded
451static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
452 SkBitmap store;
453 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
454 store.allocPixels();
455 MockDevice mockDevice(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000456 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&mockDevice));
junov@chromium.org66070a52013-05-28 17:39:08 +0000457 canvas->setMaxRecordingStorage(160000);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000458
459 SkBitmap sourceImage;
460 // 100 by 100 image, takes 40,000 bytes in memory
461 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
462 sourceImage.allocPixels();
463
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000464 for (int i = 0; i < 5; i++) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000465 sourceImage.notifyPixelsChanged(); // to force re-serialization
junov@chromium.org66070a52013-05-28 17:39:08 +0000466 canvas->drawBitmap(sourceImage, 0, 0, NULL);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000467 }
468
scroggo@google.com15011ee2012-07-26 20:03:32 +0000469 REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000470}
471
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000472class NotificationCounter : public SkDeferredCanvas::NotificationClient {
473public:
474 NotificationCounter() {
junov@google.com52a00ca2012-10-01 15:27:14 +0000475 fPrepareForDrawCount = fStorageAllocatedChangedCount =
476 fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000477 }
478
479 virtual void prepareForDraw() SK_OVERRIDE {
480 fPrepareForDrawCount++;
481 }
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000482 virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000483 fStorageAllocatedChangedCount++;
484 }
485 virtual void flushedDrawCommands() SK_OVERRIDE {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000486 fFlushedDrawCommandsCount++;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000487 }
junov@google.com52a00ca2012-10-01 15:27:14 +0000488 virtual void skippedPendingDrawCommands() SK_OVERRIDE {
489 fSkippedPendingDrawCommandsCount++;
490 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000491
492 int fPrepareForDrawCount;
493 int fStorageAllocatedChangedCount;
494 int fFlushedDrawCommandsCount;
junov@google.com52a00ca2012-10-01 15:27:14 +0000495 int fSkippedPendingDrawCommandsCount;
robertphillips@google.com59903972013-02-07 21:02:23 +0000496
497private:
498 typedef SkDeferredCanvas::NotificationClient INHERITED;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000499};
500
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000501static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
502 SkBitmap store;
503 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
504 store.allocPixels();
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000505 SkBitmapDevice device(store);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000506 NotificationCounter notificationCounter;
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000507 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org66070a52013-05-28 17:39:08 +0000508 canvas->setNotificationClient(&notificationCounter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000509
510 const int imageCount = 2;
511 SkBitmap sourceImages[imageCount];
512 for (int i = 0; i < imageCount; i++)
513 {
514 sourceImages[i].setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
515 sourceImages[i].allocPixels();
516 }
517
518 size_t bitmapSize = sourceImages[0].getSize();
519
junov@chromium.org66070a52013-05-28 17:39:08 +0000520 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000521 REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000522 // stored bitmap + drawBitmap command
junov@chromium.org66070a52013-05-28 17:39:08 +0000523 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > bitmapSize);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000524
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000525 // verify that nothing can be freed at this point
junov@chromium.org66070a52013-05-28 17:39:08 +0000526 REPORTER_ASSERT(reporter, 0 == canvas->freeMemoryIfPossible(~0U));
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000527
528 // verify that flush leaves image in cache
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000529 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
530 REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000531 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000532 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
533 REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000534 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000535
536 // verify that after a flush, cached image can be freed
junov@chromium.org66070a52013-05-28 17:39:08 +0000537 REPORTER_ASSERT(reporter, canvas->freeMemoryIfPossible(~0U) >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000538
539 // Verify that caching works for avoiding multiple copies of the same bitmap
junov@chromium.org66070a52013-05-28 17:39:08 +0000540 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000541 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000542 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000543 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
544 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000545 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < 2 * bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000546
547 // Verify partial eviction based on bytesToFree
junov@chromium.org66070a52013-05-28 17:39:08 +0000548 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000549 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000550 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000551 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000552 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2 * bitmapSize);
553 size_t bytesFreed = canvas->freeMemoryIfPossible(1);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000554 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000555 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
556 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
557
rmistry@google.comd6176b02012-08-23 18:14:13 +0000558 // Verifiy that partial purge works, image zero is in cache but not reffed by
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000559 // a pending draw, while image 1 is locked-in.
junov@chromium.org66070a52013-05-28 17:39:08 +0000560 canvas->freeMemoryIfPossible(~0U);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000561 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000562 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
563 canvas->flush();
564 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
565 bytesFreed = canvas->freeMemoryIfPossible(~0U);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000566 // only one bitmap should have been freed.
567 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
568 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
569 // Clear for next test
junov@chromium.org66070a52013-05-28 17:39:08 +0000570 canvas->flush();
571 canvas->freeMemoryIfPossible(~0U);
572 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000573
574 // Verify the image cache is sensitive to genID bumps
junov@chromium.org66070a52013-05-28 17:39:08 +0000575 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000576 sourceImages[1].notifyPixelsChanged();
junov@chromium.org66070a52013-05-28 17:39:08 +0000577 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
578 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2*bitmapSize);
junov@google.com52a00ca2012-10-01 15:27:14 +0000579
580 // Verify that nothing in this test caused commands to be skipped
581 REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
582}
583
584static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
585 SkBitmap store;
586 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
587 store.allocPixels();
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000588 SkBitmapDevice device(store);
junov@google.com52a00ca2012-10-01 15:27:14 +0000589 NotificationCounter notificationCounter;
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000590 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org66070a52013-05-28 17:39:08 +0000591 canvas->setNotificationClient(&notificationCounter);
592 canvas->clear(0x0);
junov@google.com52a00ca2012-10-01 15:27:14 +0000593 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
594 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000595 canvas->flush();
junov@google.com52a00ca2012-10-01 15:27:14 +0000596 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
597 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
598
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000599}
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000600
junov@chromium.orgce65f382012-10-17 19:36:09 +0000601static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
602 // This is a regression test for crbug.com/155875
603 // This test covers a code path that inserts bitmaps into the bitmap heap through the
604 // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
605 // the flattening and unflattening of the shader.
606 SkBitmap store;
607 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
608 store.allocPixels();
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000609 SkBitmapDevice device(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000610 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.orgce65f382012-10-17 19:36:09 +0000611 // test will fail if nbIterations is not in sync with
612 // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
613 const int nbIterations = 5;
614 size_t bytesAllocated = 0;
615 for(int pass = 0; pass < 2; ++pass) {
616 for(int i = 0; i < nbIterations; ++i) {
617 SkPaint paint;
618 SkBitmap paintPattern;
619 paintPattern.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
620 paintPattern.allocPixels();
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000621 paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
junov@chromium.orgce65f382012-10-17 19:36:09 +0000622 (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000623 canvas->drawPaint(paint);
624 canvas->flush();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000625
626 // In the first pass, memory allocation should be monotonically increasing as
627 // the bitmap heap slots fill up. In the second pass memory allocation should be
628 // stable as bitmap heap slots get recycled.
junov@chromium.org66070a52013-05-28 17:39:08 +0000629 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000630 if (pass == 0) {
631 REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
632 bytesAllocated = newBytesAllocated;
633 } else {
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000634 REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000635 }
636 }
637 }
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000638 // All cached resources should be evictable since last canvas call was flush()
junov@chromium.org66070a52013-05-28 17:39:08 +0000639 canvas->freeMemoryIfPossible(~0U);
640 REPORTER_ASSERT(reporter, 0 == canvas->storageAllocatedForRecording());
junov@chromium.orgce65f382012-10-17 19:36:09 +0000641}
642
sugoi@google.com7775fd52012-11-21 15:47:04 +0000643static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
644 SkBitmap store;
645 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
646 store.allocPixels();
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000647
sugoi@google.com7775fd52012-11-21 15:47:04 +0000648 SkBitmap sourceImage;
649 // 100 by 100 image, takes 40,000 bytes in memory
650 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
651 sourceImage.allocPixels();
652
653 // 1 under : should not store the image
654 {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000655 SkBitmapDevice device(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000656 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org66070a52013-05-28 17:39:08 +0000657 canvas->setBitmapSizeThreshold(39999);
658 canvas->drawBitmap(sourceImage, 0, 0, NULL);
659 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000660 REPORTER_ASSERT(reporter, newBytesAllocated == 0);
661 }
662
663 // exact value : should store the image
664 {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000665 SkBitmapDevice device(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000666 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org66070a52013-05-28 17:39:08 +0000667 canvas->setBitmapSizeThreshold(40000);
668 canvas->drawBitmap(sourceImage, 0, 0, NULL);
669 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000670 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
671 }
672
673 // 1 over : should still store the image
674 {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000675 SkBitmapDevice device(store);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000676 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org66070a52013-05-28 17:39:08 +0000677 canvas->setBitmapSizeThreshold(40001);
678 canvas->drawBitmap(sourceImage, 0, 0, NULL);
679 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000680 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
681 }
682}
683
junov@chromium.org67d74222013-04-12 13:33:01 +0000684
685typedef void* PixelPtr;
686// Returns an opaque pointer which, either points to a GrTexture or RAM pixel
687// buffer. Used to test pointer equality do determine whether a surface points
688// to the same pixel data storage as before.
junov@chromium.org3c5ec8d2013-04-12 13:34:47 +0000689static PixelPtr getSurfacePixelPtr(SkSurface* surface, bool useGpu) {
junov@chromium.org67d74222013-04-12 13:33:01 +0000690 return useGpu ? surface->getCanvas()->getDevice()->accessBitmap(false).getTexture() :
691 surface->getCanvas()->getDevice()->accessBitmap(false).getPixels();
692}
693
694static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
695 SkImage::Info imageSpec = {
696 10, // width
697 10, // height
698 SkImage::kPMColor_ColorType,
699 SkImage::kPremul_AlphaType
700 };
701 SkSurface* surface;
702 bool useGpu = NULL != factory;
703#if SK_SUPPORT_GPU
704 if (useGpu) {
705 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
706 surface = SkSurface::NewRenderTarget(context, imageSpec);
707 } else {
708 surface = SkSurface::NewRaster(imageSpec);
709 }
710#else
711 SkASSERT(!useGpu);
712 surface = SkSurface::NewRaster(imageSpec);
713#endif
714 SkASSERT(NULL != surface);
715 SkAutoTUnref<SkSurface> aur(surface);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000716 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
junov@chromium.org67d74222013-04-12 13:33:01 +0000717
junov@chromium.org66070a52013-05-28 17:39:08 +0000718 SkImage* image1 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000719 SkAutoTUnref<SkImage> aur_i1(image1);
720 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
721 // The following clear would normally trigger a copy on write, but
722 // it won't because rendering is deferred.
junov@chromium.org66070a52013-05-28 17:39:08 +0000723 canvas->clear(SK_ColorBLACK);
junov@chromium.org67d74222013-04-12 13:33:01 +0000724 // Obtaining a snapshot directly from the surface (as opposed to the
725 // SkDeferredCanvas) will not trigger a flush of deferred draw operations
726 // and will therefore return the same image as the previous snapshot.
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000727 SkImage* image2 = surface->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000728 SkAutoTUnref<SkImage> aur_i2(image2);
729 // Images identical because of deferral
730 REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID());
731 // Now we obtain a snpshot via the deferred canvas, which triggers a flush.
732 // Because there is a pending clear, this will generate a different image.
junov@chromium.org66070a52013-05-28 17:39:08 +0000733 SkImage* image3 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000734 SkAutoTUnref<SkImage> aur_i3(image3);
735 REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID());
736 // Verify that backing store is now a different buffer because of copy on
737 // write
738 PixelPtr pixels2 = getSurfacePixelPtr(surface, useGpu);
739 REPORTER_ASSERT(reporter, pixels1 != pixels2);
junov@chromium.org9becf002013-04-15 18:15:23 +0000740 // Verify copy-on write with a draw operation that gets deferred by
741 // the in order draw buffer.
742 SkPaint paint;
junov@chromium.org66070a52013-05-28 17:39:08 +0000743 canvas->drawPaint(paint);
744 SkImage* image4 = canvas->newImageSnapshot(); // implicit flush
junov@chromium.org9becf002013-04-15 18:15:23 +0000745 SkAutoTUnref<SkImage> aur_i4(image4);
746 REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID());
junov@chromium.org67d74222013-04-12 13:33:01 +0000747 PixelPtr pixels3 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org9becf002013-04-15 18:15:23 +0000748 REPORTER_ASSERT(reporter, pixels2 != pixels3);
junov@chromium.org67d74222013-04-12 13:33:01 +0000749 // Verify that a direct canvas flush with a pending draw does not trigger
750 // a copy on write when the surface is not sharing its buffer with an
751 // SkImage.
junov@chromium.org66070a52013-05-28 17:39:08 +0000752 canvas->clear(SK_ColorWHITE);
753 canvas->flush();
junov@chromium.org67d74222013-04-12 13:33:01 +0000754 PixelPtr pixels4 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org66070a52013-05-28 17:39:08 +0000755 canvas->drawPaint(paint);
756 canvas->flush();
junov@chromium.org9becf002013-04-15 18:15:23 +0000757 PixelPtr pixels5 = getSurfacePixelPtr(surface, useGpu);
758 REPORTER_ASSERT(reporter, pixels4 == pixels5);
junov@chromium.org67d74222013-04-12 13:33:01 +0000759}
760
junov@chromium.org7070f762013-05-24 17:13:00 +0000761static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
762 SkImage::Info imageSpec = {
763 10, // width
764 10, // height
765 SkImage::kPMColor_ColorType,
766 SkImage::kPremul_AlphaType
767 };
768 SkSurface* surface;
769 SkSurface* alternateSurface;
770 bool useGpu = NULL != factory;
771#if SK_SUPPORT_GPU
772 if (useGpu) {
773 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
774 surface = SkSurface::NewRenderTarget(context, imageSpec);
775 alternateSurface = SkSurface::NewRenderTarget(context, imageSpec);
776 } else {
777 surface = SkSurface::NewRaster(imageSpec);
778 alternateSurface = SkSurface::NewRaster(imageSpec);
779 }
780#else
781 SkASSERT(!useGpu);
782 surface = SkSurface::NewRaster(imageSpec);
783 alternateSurface = SkSurface::NewRaster(imageSpec);
784#endif
785 SkASSERT(NULL != surface);
786 SkASSERT(NULL != alternateSurface);
787 SkAutoTUnref<SkSurface> aur1(surface);
788 SkAutoTUnref<SkSurface> aur2(alternateSurface);
789 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
790 PixelPtr pixels2 = getSurfacePixelPtr(alternateSurface, useGpu);
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000791 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
junov@chromium.org66070a52013-05-28 17:39:08 +0000792 SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
793 canvas->setSurface(alternateSurface);
794 SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
junov@chromium.org7070f762013-05-24 17:13:00 +0000795 REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID());
796 // Verify that none of the above operations triggered a surface copy on write.
797 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
798 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) == pixels2);
799 // Verify that a flushed draw command will trigger a copy on write on alternateSurface.
junov@chromium.org66070a52013-05-28 17:39:08 +0000800 canvas->clear(SK_ColorWHITE);
801 canvas->flush();
junov@chromium.org7070f762013-05-24 17:13:00 +0000802 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
803 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) != pixels2);
804}
805
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000806static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) {
807 SkBitmap store;
808 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
809 store.allocPixels();
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000810 SkBitmapDevice device(store);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000811 NotificationCounter notificationCounter;
commit-bot@chromium.orgcb622242013-08-09 14:24:59 +0000812 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device));
junov@chromium.org66070a52013-05-28 17:39:08 +0000813 canvas->setNotificationClient(&notificationCounter);
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000814 SkAutoTUnref<SkBaseDevice> secondaryDevice(canvas->createCompatibleDevice(
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000815 SkBitmap::kARGB_8888_Config, 10, 10, device.isOpaque()));
816 SkCanvas secondaryCanvas(secondaryDevice.get());
817 SkRect rect = SkRect::MakeWH(5, 5);
818 SkPaint paint;
819 // After spawning a compatible canvas:
820 // 1) Verify that secondary canvas is usable and does not report to the notification client.
821 secondaryCanvas.drawRect(rect, paint);
822 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0);
823 // 2) Verify that original canvas is usable and still reports to the notification client.
junov@chromium.org66070a52013-05-28 17:39:08 +0000824 canvas->drawRect(rect, paint);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000825 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1);
826}
827
junov@chromium.org67d74222013-04-12 13:33:01 +0000828static void TestDeferredCanvas(skiatest::Reporter* reporter, GrContextFactory* factory) {
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000829 TestDeferredCanvasBitmapAccess(reporter);
830 TestDeferredCanvasFlush(reporter);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000831 TestDeferredCanvasFreshFrame(reporter);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000832 TestDeferredCanvasMemoryLimit(reporter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000833 TestDeferredCanvasBitmapCaching(reporter);
junov@google.com52a00ca2012-10-01 15:27:14 +0000834 TestDeferredCanvasSkip(reporter);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000835 TestDeferredCanvasBitmapShaderNoLeak(reporter);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000836 TestDeferredCanvasBitmapSizeThreshold(reporter);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000837 TestDeferredCanvasCreateCompatibleDevice(reporter);
junov@chromium.org44324fa2013-08-02 15:36:02 +0000838 TestDeferredCanvasWritePixelsToSurface(reporter);
junov@chromium.org67d74222013-04-12 13:33:01 +0000839 TestDeferredCanvasSurface(reporter, NULL);
junov@chromium.org7070f762013-05-24 17:13:00 +0000840 TestDeferredCanvasSetSurface(reporter, NULL);
junov@chromium.org67d74222013-04-12 13:33:01 +0000841 if (NULL != factory) {
842 TestDeferredCanvasSurface(reporter, factory);
junov@chromium.org7070f762013-05-24 17:13:00 +0000843 TestDeferredCanvasSetSurface(reporter, factory);
junov@chromium.org67d74222013-04-12 13:33:01 +0000844 }
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000845}
846
847#include "TestClassDef.h"
junov@chromium.org67d74222013-04-12 13:33:01 +0000848DEFINE_GPUTESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas)