blob: a95e09c5cc28b3088a4e6070c6aa57f9c1631ffd [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.org1f9767c2012-02-07 16:27:57 +000015
junov@chromium.org1f9767c2012-02-07 16:27:57 +000016static const int gWidth = 2;
17static const int gHeight = 2;
18
19static void create(SkBitmap* bm, SkBitmap::Config config, SkColor color) {
20 bm->setConfig(config, gWidth, gHeight);
21 bm->allocPixels();
22 bm->eraseColor(color);
23}
24
25static void TestDeferredCanvasBitmapAccess(skiatest::Reporter* reporter) {
26 SkBitmap store;
27
28 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
29 SkDevice device(store);
30 SkDeferredCanvas canvas(&device);
31
32 canvas.clear(0x00000000);
33
34 SkAutoLockPixels alp(store);
35 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
36 SkBitmap accessed = canvas.getDevice()->accessBitmap(false);
37 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
38 REPORTER_ASSERT(reporter, accessed.pixelRef() == store.pixelRef());
39}
40
41static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
42 SkBitmap store;
43
44 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
45 SkDevice device(store);
46 SkDeferredCanvas canvas(&device);
47
48 canvas.clear(0x00000000);
49
50 SkAutoLockPixels alp(store);
51 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
52 canvas.flush();
53 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
54}
55
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000056static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
57 SkBitmap store;
58 SkRect fullRect;
59 fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
60 SkIntToScalar(gHeight));
61 SkRect partialRect;
junov@chromium.orgb1e218e2012-02-13 22:27:58 +000062 partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
63 SkIntToScalar(1), SkIntToScalar(1));
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000064 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
65 SkDevice device(store);
66 SkDeferredCanvas canvas(&device);
67
68 // verify that frame is intially fresh
junov@chromium.org88e29142012-08-07 16:48:22 +000069 REPORTER_ASSERT(reporter, canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000070 // no clearing op since last call to isFreshFrame -> not fresh
junov@chromium.org88e29142012-08-07 16:48:22 +000071 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000072
73 // Verify that clear triggers a fresh frame
74 canvas.clear(0x00000000);
junov@chromium.org88e29142012-08-07 16:48:22 +000075 REPORTER_ASSERT(reporter, canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000076
77 // Verify that clear with saved state triggers a fresh frame
78 canvas.save(SkCanvas::kMatrixClip_SaveFlag);
79 canvas.clear(0x00000000);
80 canvas.restore();
junov@chromium.org88e29142012-08-07 16:48:22 +000081 REPORTER_ASSERT(reporter, canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000082
83 // Verify that clear within a layer does NOT trigger a fresh frame
84 canvas.saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
85 canvas.clear(0x00000000);
86 canvas.restore();
junov@chromium.org88e29142012-08-07 16:48:22 +000087 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000088
89 // Verify that a clear with clipping triggers a fresh frame
90 // (clear is not affected by clipping)
91 canvas.save(SkCanvas::kMatrixClip_SaveFlag);
92 canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false);
93 canvas.clear(0x00000000);
94 canvas.restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +000095 REPORTER_ASSERT(reporter, canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000096
97 // Verify that full frame rects with different forms of opaque paint
98 // trigger frames to be marked as fresh
99 {
100 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000101 paint.setStyle(SkPaint::kFill_Style);
102 paint.setAlpha(255);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000103 canvas.drawRect(fullRect, paint);
junov@chromium.org88e29142012-08-07 16:48:22 +0000104 REPORTER_ASSERT(reporter, canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000105 }
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +0000106 {
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000107 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000108 paint.setStyle(SkPaint::kFill_Style);
109 paint.setAlpha(255);
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000110 paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
111 canvas.drawRect(fullRect, paint);
112 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
113 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000114 {
115 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000116 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000117 SkBitmap bmp;
118 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
119 bmp.setIsOpaque(true);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000120 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000121 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
122 paint.setShader(shader)->unref();
123 canvas.drawRect(fullRect, paint);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000124 REPORTER_ASSERT(reporter, canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000125 }
126
127 // Verify that full frame rects with different forms of non-opaque paint
128 // do not trigger frames to be marked as fresh
129 {
130 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000131 paint.setStyle(SkPaint::kFill_Style);
132 paint.setAlpha(254);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000133 canvas.drawRect(fullRect, paint);
junov@chromium.org88e29142012-08-07 16:48:22 +0000134 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000135 }
136 {
137 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000138 paint.setStyle(SkPaint::kFill_Style);
139 // Defining a cone that partially overlaps the canvas
140 const SkPoint pt1 = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
141 const SkScalar r1 = SkIntToScalar(1);
142 const SkPoint pt2 = SkPoint::Make(SkIntToScalar(10), SkIntToScalar(0));
143 const SkScalar r2 = SkIntToScalar(5);
144 const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
145 const SkScalar pos[2] = {0, SK_Scalar1};
146 SkShader* shader = SkGradientShader::CreateTwoPointConical(
147 pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode, NULL);
148 paint.setShader(shader)->unref();
149 canvas.drawRect(fullRect, paint);
150 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
151 }
152 {
153 SkPaint paint;
154 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000155 SkBitmap bmp;
156 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
157 bmp.setIsOpaque(false);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000158 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000159 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
160 paint.setShader(shader)->unref();
161 canvas.drawRect(fullRect, paint);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000162 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000163 }
164
165 // Verify that incomplete coverage does not trigger a fresh frame
166 {
167 SkPaint paint;
168 paint.setStyle(SkPaint::kFill_Style);
169 paint.setAlpha(255);
170 canvas.drawRect(partialRect, paint);
junov@chromium.org88e29142012-08-07 16:48:22 +0000171 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000172 }
173
174 // Verify that incomplete coverage due to clipping does not trigger a fresh
175 // frame
176 {
177 canvas.save(SkCanvas::kMatrixClip_SaveFlag);
178 canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false);
179 SkPaint paint;
180 paint.setStyle(SkPaint::kFill_Style);
181 paint.setAlpha(255);
182 canvas.drawRect(fullRect, paint);
junov@chromium.org41e850f2012-12-10 21:24:38 +0000183 canvas.restore();
junov@chromium.org88e29142012-08-07 16:48:22 +0000184 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000185 }
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000186 {
187 canvas.save(SkCanvas::kMatrixClip_SaveFlag);
188 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000189 paint.setStyle(SkPaint::kFill_Style);
190 paint.setAlpha(255);
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000191 SkPath path;
192 path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
193 canvas.clipPath(path, SkRegion::kIntersect_Op, false);
194 canvas.drawRect(fullRect, paint);
195 canvas.restore();
196 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
197 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000198
199 // Verify that stroked rect does not trigger a fresh frame
200 {
201 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000202 paint.setStyle(SkPaint::kStroke_Style);
203 paint.setAlpha(255);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000204 canvas.drawRect(fullRect, paint);
junov@chromium.org88e29142012-08-07 16:48:22 +0000205 REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000206 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000207
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000208 // Verify kSrcMode triggers a fresh frame even with transparent color
209 {
210 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000211 paint.setStyle(SkPaint::kFill_Style);
212 paint.setAlpha(100);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000213 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
214 canvas.drawRect(fullRect, paint);
junov@chromium.org41e850f2012-12-10 21:24:38 +0000215 REPORTER_ASSERT(reporter, canvas.isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000216 }
217}
218
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000219class MockDevice : public SkDevice {
220public:
221 MockDevice(const SkBitmap& bm) : SkDevice(bm) {
222 fDrawBitmapCallCount = 0;
223 }
224 virtual void drawBitmap(const SkDraw&, const SkBitmap&,
225 const SkIRect*,
226 const SkMatrix&, const SkPaint&) {
227 fDrawBitmapCallCount++;
228 }
229
230 int fDrawBitmapCallCount;
231};
232
233// Verifies that the deferred canvas triggers a flush when its memory
234// limit is exceeded
235static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
236 SkBitmap store;
237 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
238 store.allocPixels();
239 MockDevice mockDevice(store);
240 SkDeferredCanvas canvas(&mockDevice);
241 canvas.setMaxRecordingStorage(160000);
242
243 SkBitmap sourceImage;
244 // 100 by 100 image, takes 40,000 bytes in memory
245 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
246 sourceImage.allocPixels();
247
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000248 for (int i = 0; i < 5; i++) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000249 sourceImage.notifyPixelsChanged(); // to force re-serialization
250 canvas.drawBitmap(sourceImage, 0, 0, NULL);
251 }
252
scroggo@google.com15011ee2012-07-26 20:03:32 +0000253 REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000254}
255
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000256class NotificationCounter : public SkDeferredCanvas::NotificationClient {
257public:
258 NotificationCounter() {
junov@google.com52a00ca2012-10-01 15:27:14 +0000259 fPrepareForDrawCount = fStorageAllocatedChangedCount =
260 fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000261 }
262
263 virtual void prepareForDraw() SK_OVERRIDE {
264 fPrepareForDrawCount++;
265 }
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000266 virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000267 fStorageAllocatedChangedCount++;
268 }
269 virtual void flushedDrawCommands() SK_OVERRIDE {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000270 fFlushedDrawCommandsCount++;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000271 }
junov@google.com52a00ca2012-10-01 15:27:14 +0000272 virtual void skippedPendingDrawCommands() SK_OVERRIDE {
273 fSkippedPendingDrawCommandsCount++;
274 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000275
276 int fPrepareForDrawCount;
277 int fStorageAllocatedChangedCount;
278 int fFlushedDrawCommandsCount;
junov@google.com52a00ca2012-10-01 15:27:14 +0000279 int fSkippedPendingDrawCommandsCount;
robertphillips@google.com59903972013-02-07 21:02:23 +0000280
281private:
282 typedef SkDeferredCanvas::NotificationClient INHERITED;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000283};
284
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000285static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
286 SkBitmap store;
287 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
288 store.allocPixels();
289 SkDevice device(store);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000290 NotificationCounter notificationCounter;
junov@chromium.orgd433c4e2012-08-17 14:50:16 +0000291 SkDeferredCanvas canvas(&device);
292 canvas.setNotificationClient(&notificationCounter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000293
294 const int imageCount = 2;
295 SkBitmap sourceImages[imageCount];
296 for (int i = 0; i < imageCount; i++)
297 {
298 sourceImages[i].setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
299 sourceImages[i].allocPixels();
300 }
301
302 size_t bitmapSize = sourceImages[0].getSize();
303
304 canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000305 REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000306 // stored bitmap + drawBitmap command
307 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > bitmapSize);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000308
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000309 // verify that nothing can be freed at this point
bsalomon@google.com100abf42012-09-05 17:40:04 +0000310 REPORTER_ASSERT(reporter, 0 == canvas.freeMemoryIfPossible(~0U));
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000311
312 // verify that flush leaves image in cache
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000313 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
314 REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000315 canvas.flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000316 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
317 REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000318 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() >= bitmapSize);
319
320 // verify that after a flush, cached image can be freed
bsalomon@google.com100abf42012-09-05 17:40:04 +0000321 REPORTER_ASSERT(reporter, canvas.freeMemoryIfPossible(~0U) >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000322
323 // Verify that caching works for avoiding multiple copies of the same bitmap
324 canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000325 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000326 canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000327 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
328 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000329 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() < 2 * bitmapSize);
330
331 // Verify partial eviction based on bytesToFree
332 canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000333 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000334 canvas.flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000335 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000336 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > 2 * bitmapSize);
337 size_t bytesFreed = canvas.freeMemoryIfPossible(1);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000338 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000339 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
340 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
341
rmistry@google.comd6176b02012-08-23 18:14:13 +0000342 // Verifiy that partial purge works, image zero is in cache but not reffed by
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000343 // a pending draw, while image 1 is locked-in.
bsalomon@google.com100abf42012-09-05 17:40:04 +0000344 canvas.freeMemoryIfPossible(~0U);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000345 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000346 canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
347 canvas.flush();
348 canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
bsalomon@google.com100abf42012-09-05 17:40:04 +0000349 bytesFreed = canvas.freeMemoryIfPossible(~0U);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000350 // only one bitmap should have been freed.
351 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
352 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
353 // Clear for next test
354 canvas.flush();
bsalomon@google.com100abf42012-09-05 17:40:04 +0000355 canvas.freeMemoryIfPossible(~0U);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000356 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() < bitmapSize);
357
358 // Verify the image cache is sensitive to genID bumps
359 canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
360 sourceImages[1].notifyPixelsChanged();
361 canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
362 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > 2*bitmapSize);
junov@google.com52a00ca2012-10-01 15:27:14 +0000363
364 // Verify that nothing in this test caused commands to be skipped
365 REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
366}
367
368static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
369 SkBitmap store;
370 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
371 store.allocPixels();
372 SkDevice device(store);
373 NotificationCounter notificationCounter;
374 SkDeferredCanvas canvas(&device);
375 canvas.setNotificationClient(&notificationCounter);
376 canvas.clear(0x0);
377 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
378 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
379 canvas.flush();
380 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
381 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
382
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000383}
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000384
junov@chromium.orgce65f382012-10-17 19:36:09 +0000385static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
386 // This is a regression test for crbug.com/155875
387 // This test covers a code path that inserts bitmaps into the bitmap heap through the
388 // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
389 // the flattening and unflattening of the shader.
390 SkBitmap store;
391 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
392 store.allocPixels();
393 SkDevice device(store);
394 SkDeferredCanvas canvas(&device);
395 // test will fail if nbIterations is not in sync with
396 // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
397 const int nbIterations = 5;
398 size_t bytesAllocated = 0;
399 for(int pass = 0; pass < 2; ++pass) {
400 for(int i = 0; i < nbIterations; ++i) {
401 SkPaint paint;
402 SkBitmap paintPattern;
403 paintPattern.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
404 paintPattern.allocPixels();
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000405 paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
junov@chromium.orgce65f382012-10-17 19:36:09 +0000406 (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
407 canvas.drawPaint(paint);
408 canvas.flush();
409
410 // In the first pass, memory allocation should be monotonically increasing as
411 // the bitmap heap slots fill up. In the second pass memory allocation should be
412 // stable as bitmap heap slots get recycled.
413 size_t newBytesAllocated = canvas.storageAllocatedForRecording();
414 if (pass == 0) {
415 REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
416 bytesAllocated = newBytesAllocated;
417 } else {
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000418 REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000419 }
420 }
421 }
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000422 // All cached resources should be evictable since last canvas call was flush()
reed@google.com2b57dc62013-01-08 13:23:32 +0000423 canvas.freeMemoryIfPossible(~0U);
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000424 REPORTER_ASSERT(reporter, 0 == canvas.storageAllocatedForRecording());
junov@chromium.orgce65f382012-10-17 19:36:09 +0000425}
426
sugoi@google.com7775fd52012-11-21 15:47:04 +0000427static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
428 SkBitmap store;
429 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
430 store.allocPixels();
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000431
sugoi@google.com7775fd52012-11-21 15:47:04 +0000432 SkBitmap sourceImage;
433 // 100 by 100 image, takes 40,000 bytes in memory
434 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
435 sourceImage.allocPixels();
436
437 // 1 under : should not store the image
438 {
439 SkDevice device(store);
440 SkDeferredCanvas canvas(&device);
441 canvas.setBitmapSizeThreshold(39999);
442 canvas.drawBitmap(sourceImage, 0, 0, NULL);
443 size_t newBytesAllocated = canvas.storageAllocatedForRecording();
444 REPORTER_ASSERT(reporter, newBytesAllocated == 0);
445 }
446
447 // exact value : should store the image
448 {
449 SkDevice device(store);
450 SkDeferredCanvas canvas(&device);
451 canvas.setBitmapSizeThreshold(40000);
452 canvas.drawBitmap(sourceImage, 0, 0, NULL);
453 size_t newBytesAllocated = canvas.storageAllocatedForRecording();
454 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
455 }
456
457 // 1 over : should still store the image
458 {
459 SkDevice device(store);
460 SkDeferredCanvas canvas(&device);
461 canvas.setBitmapSizeThreshold(40001);
462 canvas.drawBitmap(sourceImage, 0, 0, NULL);
463 size_t newBytesAllocated = canvas.storageAllocatedForRecording();
464 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
465 }
466}
467
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000468static void TestDeferredCanvas(skiatest::Reporter* reporter) {
469 TestDeferredCanvasBitmapAccess(reporter);
470 TestDeferredCanvasFlush(reporter);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000471 TestDeferredCanvasFreshFrame(reporter);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000472 TestDeferredCanvasMemoryLimit(reporter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000473 TestDeferredCanvasBitmapCaching(reporter);
junov@google.com52a00ca2012-10-01 15:27:14 +0000474 TestDeferredCanvasSkip(reporter);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000475 TestDeferredCanvasBitmapShaderNoLeak(reporter);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000476 TestDeferredCanvasBitmapSizeThreshold(reporter);
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000477}
478
479#include "TestClassDef.h"
480DEFINE_TESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas)