• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "../src/image/SkImagePriv.h"
9 #include "../src/image/SkSurface_Base.h"
10 #include "SkBitmap.h"
11 #include "SkBitmapDevice.h"
12 #include "SkBitmapProcShader.h"
13 #include "SkDeferredCanvas.h"
14 #include "SkGradientShader.h"
15 #include "SkShader.h"
16 #include "SkSurface.h"
17 #include "Test.h"
18 #include "sk_tool_utils.h"
19 
20 #if SK_SUPPORT_GPU
21 #include "GrContextFactory.h"
22 #else
23 class GrContextFactory;
24 #endif
25 
26 static const int gWidth = 2;
27 static const int gHeight = 2;
28 
create(SkBitmap * bm,SkColor color)29 static void create(SkBitmap* bm, SkColor color) {
30     bm->allocN32Pixels(gWidth, gHeight);
31     bm->eraseColor(color);
32 }
33 
createSurface(SkColor color)34 static SkSurface* createSurface(SkColor color) {
35     SkSurface* surface = SkSurface::NewRasterPMColor(gWidth, gHeight);
36     surface->getCanvas()->clear(color);
37     return surface;
38 }
39 
read_pixel(SkSurface * surface,int x,int y)40 static SkPMColor read_pixel(SkSurface* surface, int x, int y) {
41     SkPMColor pixel = 0;
42     SkBitmap bitmap;
43     bitmap.installPixels(SkImageInfo::MakeN32Premul(1, 1), &pixel, 4);
44     SkCanvas canvas(bitmap);
45 
46     SkPaint paint;
47     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
48     surface->draw(&canvas, -SkIntToScalar(x), -SkIntToScalar(y), &paint);
49     return pixel;
50 }
51 
TestDeferredCanvasBitmapAccess(skiatest::Reporter * reporter)52 static void TestDeferredCanvasBitmapAccess(skiatest::Reporter* reporter) {
53     SkBitmap store;
54 
55     SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
56     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
57 
58     canvas->clear(0x00000000);
59 
60     // verify that the clear() was deferred
61     REPORTER_ASSERT(reporter, 0xFFFFFFFF == read_pixel(surface, 0, 0));
62 
63     SkBitmap accessed = canvas->getDevice()->accessBitmap(false);
64 
65     // verify that clear was executed
66     REPORTER_ASSERT(reporter, 0 == read_pixel(surface, 0, 0));
67 }
68 
69 class MockSurface : public SkSurface_Base {
70 public:
MockSurface(int width,int height)71     MockSurface(int width, int height) : SkSurface_Base(width, height) {
72         clearCounts();
73         fBitmap.allocN32Pixels(width, height);
74     }
75 
onNewCanvas()76     virtual SkCanvas* onNewCanvas() SK_OVERRIDE {
77         return SkNEW_ARGS(SkCanvas, (fBitmap));
78     }
79 
onNewSurface(const SkImageInfo &)80     virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE {
81         return NULL;
82     }
83 
onNewImageSnapshot()84     virtual SkImage* onNewImageSnapshot() SK_OVERRIDE {
85         return SkNewImageFromBitmap(fBitmap, true);
86     }
87 
onCopyOnWrite(ContentChangeMode mode)88     virtual void onCopyOnWrite(ContentChangeMode mode) SK_OVERRIDE {
89         if (mode == SkSurface::kDiscard_ContentChangeMode) {
90             fDiscardCount++;
91         } else {
92             fRetainCount++;
93         }
94     }
95 
clearCounts()96     void clearCounts() {
97         fDiscardCount = 0;
98         fRetainCount = 0;
99     }
100 
101     int fDiscardCount, fRetainCount;
102     SkBitmap fBitmap;
103 };
104 
TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter * reporter)105 static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) {
106     SkAutoTUnref<MockSurface> surface(SkNEW_ARGS(MockSurface, (10, 10)));
107     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
108 
109     SkBitmap srcBitmap;
110     srcBitmap.allocPixels(SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType));
111     srcBitmap.eraseColor(SK_ColorGREEN);
112     // Tests below depend on this bitmap being recognized as opaque
113 
114     // Preliminary sanity check: no copy on write if no active snapshot
115     surface->clearCounts();
116     canvas->clear(SK_ColorWHITE);
117     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
118     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
119 
120     surface->clearCounts();
121     canvas->flush();
122     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
123     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
124 
125     // Case 1: Discard notification happens upon flushing
126     // with an Image attached.
127     surface->clearCounts();
128     SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
129     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
130     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
131 
132     surface->clearCounts();
133     canvas->clear(SK_ColorWHITE);
134     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
135     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
136 
137     surface->clearCounts();
138     canvas->flush();
139     REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
140     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
141 
142     // Case 2: Opaque writePixels
143     surface->clearCounts();
144     SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
145     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
146     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
147 
148     // Case 3: writePixels that partially covers the canvas
149     surface->clearCounts();
150     SkAutoTUnref<SkImage> image3(canvas->newImageSnapshot());
151     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
152     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
153 
154     // Case 4: unpremultiplied opaque writePixels that entirely
155     // covers the canvas
156     surface->clearCounts();
157     SkAutoTUnref<SkImage> image4(canvas->newImageSnapshot());
158     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
159     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
160 
161     surface->clearCounts();
162     canvas->writePixels(srcBitmap, 0, 0);
163     REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
164     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
165 
166     surface->clearCounts();
167     canvas->flush();
168     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
169     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
170 
171     // Case 5: unpremultiplied opaque writePixels that partially
172     // covers the canvas
173     surface->clearCounts();
174     SkAutoTUnref<SkImage> image5(canvas->newImageSnapshot());
175     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
176     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
177 
178     surface->clearCounts();
179     canvas->writePixels(srcBitmap, 5, 0);
180     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
181     REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
182 
183     surface->clearCounts();
184     canvas->flush();
185     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
186     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
187 
188     // Case 6: unpremultiplied opaque writePixels that entirely
189     // covers the canvas, preceded by clear
190     surface->clearCounts();
191     SkAutoTUnref<SkImage> image6(canvas->newImageSnapshot());
192     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
193     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
194 
195     surface->clearCounts();
196     canvas->clear(SK_ColorWHITE);
197     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
198     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
199 
200     surface->clearCounts();
201     canvas->writePixels(srcBitmap, 0, 0);
202     REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
203     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
204 
205     surface->clearCounts();
206     canvas->flush();
207     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
208     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
209 
210     // Case 7: unpremultiplied opaque writePixels that partially
211     // covers the canvas, preceeded by a clear
212     surface->clearCounts();
213     SkAutoTUnref<SkImage> image7(canvas->newImageSnapshot());
214     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
215     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
216 
217     surface->clearCounts();
218     canvas->clear(SK_ColorWHITE);
219     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
220     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
221 
222     surface->clearCounts();
223     canvas->writePixels(srcBitmap, 5, 0);
224     REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear
225     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
226 
227     surface->clearCounts();
228     canvas->flush();
229     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
230     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
231 
232     // Case 8: unpremultiplied opaque writePixels that partially
233     // covers the canvas, preceeded by a drawREct that partially
234     // covers the canvas
235     surface->clearCounts();
236     SkAutoTUnref<SkImage> image8(canvas->newImageSnapshot());
237     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
238     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
239 
240     surface->clearCounts();
241     SkPaint paint;
242     canvas->drawRect(SkRect::MakeLTRB(0, 0, 5, 5), paint);
243     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
244     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
245 
246     surface->clearCounts();
247     canvas->writePixels(srcBitmap, 5, 0);
248     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
249     REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
250 
251     surface->clearCounts();
252     canvas->flush();
253     REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
254     REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
255 }
256 
TestDeferredCanvasFlush(skiatest::Reporter * reporter)257 static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
258     SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
259     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
260 
261     canvas->clear(0x00000000);
262 
263     // verify that clear was deferred
264     REPORTER_ASSERT(reporter, 0xFFFFFFFF == read_pixel(surface, 0, 0));
265 
266     canvas->flush();
267 
268     // verify that clear was executed
269     REPORTER_ASSERT(reporter, 0 == read_pixel(surface, 0, 0));
270 }
271 
TestDeferredCanvasFreshFrame(skiatest::Reporter * reporter)272 static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
273     SkRect fullRect;
274     fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
275         SkIntToScalar(gHeight));
276     SkRect partialRect;
277     partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
278         SkIntToScalar(1), SkIntToScalar(1));
279 
280     SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF));
281     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
282 
283     // verify that frame is intially fresh
284     REPORTER_ASSERT(reporter, canvas->isFreshFrame());
285     // no clearing op since last call to isFreshFrame -> not fresh
286     REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
287 
288     // Verify that clear triggers a fresh frame
289     canvas->clear(0x00000000);
290     REPORTER_ASSERT(reporter, canvas->isFreshFrame());
291 
292     // Verify that clear with saved state triggers a fresh frame
293     canvas->save();
294     canvas->clear(0x00000000);
295     canvas->restore();
296     REPORTER_ASSERT(reporter, canvas->isFreshFrame());
297 
298     // Verify that clear within a layer does NOT trigger a fresh frame
299     canvas->saveLayer(NULL, NULL);
300     canvas->clear(0x00000000);
301     canvas->restore();
302     REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
303 
304     // Verify that a clear with clipping triggers a fresh frame
305     // (clear is not affected by clipping)
306     canvas->save();
307     canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
308     canvas->clear(0x00000000);
309     canvas->restore();
310     REPORTER_ASSERT(reporter, canvas->isFreshFrame());
311 
312     // Verify that full frame rects with different forms of opaque paint
313     // trigger frames to be marked as fresh
314     {
315         SkPaint paint;
316         paint.setStyle(SkPaint::kFill_Style);
317         paint.setAlpha(255);
318         canvas->drawRect(fullRect, paint);
319         REPORTER_ASSERT(reporter, canvas->isFreshFrame());
320     }
321     {
322         SkPaint paint;
323         paint.setStyle(SkPaint::kFill_Style);
324         paint.setAlpha(255);
325         paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
326         canvas->drawRect(fullRect, paint);
327         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
328     }
329     {
330         SkPaint paint;
331         paint.setStyle(SkPaint::kFill_Style);
332         SkBitmap bmp;
333         create(&bmp, 0xFFFFFFFF);
334         bmp.setAlphaType(kOpaque_SkAlphaType);
335         SkShader* shader = SkShader::CreateBitmapShader(bmp,
336             SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
337         paint.setShader(shader)->unref();
338         canvas->drawRect(fullRect, paint);
339         REPORTER_ASSERT(reporter, canvas->isFreshFrame());
340     }
341 
342     // Verify that full frame rects with different forms of non-opaque paint
343     // do not trigger frames to be marked as fresh
344     {
345         SkPaint paint;
346         paint.setStyle(SkPaint::kFill_Style);
347         paint.setAlpha(254);
348         canvas->drawRect(fullRect, paint);
349         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
350     }
351     {
352         SkPaint paint;
353         paint.setStyle(SkPaint::kFill_Style);
354         // Defining a cone that partially overlaps the canvas
355         const SkPoint pt1 = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
356         const SkScalar r1 = SkIntToScalar(1);
357         const SkPoint pt2 = SkPoint::Make(SkIntToScalar(10), SkIntToScalar(0));
358         const SkScalar r2 = SkIntToScalar(5);
359         const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
360         const SkScalar pos[2] = {0, SK_Scalar1};
361         SkShader* shader = SkGradientShader::CreateTwoPointConical(
362             pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode);
363         paint.setShader(shader)->unref();
364         canvas->drawRect(fullRect, paint);
365         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
366     }
367     {
368         SkPaint paint;
369         paint.setStyle(SkPaint::kFill_Style);
370         SkBitmap bmp;
371         create(&bmp, 0xFFFFFFFF);
372         bmp.setAlphaType(kPremul_SkAlphaType);
373         SkShader* shader = SkShader::CreateBitmapShader(bmp,
374             SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
375         paint.setShader(shader)->unref();
376         canvas->drawRect(fullRect, paint);
377         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
378     }
379 
380     // Verify that incomplete coverage does not trigger a fresh frame
381     {
382         SkPaint paint;
383         paint.setStyle(SkPaint::kFill_Style);
384         paint.setAlpha(255);
385         canvas->drawRect(partialRect, paint);
386         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
387     }
388 
389     // Verify that incomplete coverage due to clipping does not trigger a fresh
390     // frame
391     {
392         canvas->save();
393         canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
394         SkPaint paint;
395         paint.setStyle(SkPaint::kFill_Style);
396         paint.setAlpha(255);
397         canvas->drawRect(fullRect, paint);
398         canvas->restore();
399         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
400     }
401     {
402         canvas->save();
403         SkPaint paint;
404         paint.setStyle(SkPaint::kFill_Style);
405         paint.setAlpha(255);
406         SkPath path;
407         path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
408         canvas->clipPath(path, SkRegion::kIntersect_Op, false);
409         canvas->drawRect(fullRect, paint);
410         canvas->restore();
411         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
412     }
413 
414     // Verify that stroked rect does not trigger a fresh frame
415     {
416         SkPaint paint;
417         paint.setStyle(SkPaint::kStroke_Style);
418         paint.setAlpha(255);
419         canvas->drawRect(fullRect, paint);
420         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
421     }
422 
423     // Verify kSrcMode triggers a fresh frame even with transparent color
424     {
425         SkPaint paint;
426         paint.setStyle(SkPaint::kFill_Style);
427         paint.setAlpha(100);
428         paint.setXfermodeMode(SkXfermode::kSrc_Mode);
429         canvas->drawRect(fullRect, paint);
430         REPORTER_ASSERT(reporter, canvas->isFreshFrame());
431     }
432 }
433 
434 class MockDevice : public SkBitmapDevice {
435 public:
MockDevice(const SkBitmap & bm)436     MockDevice(const SkBitmap& bm) : SkBitmapDevice(bm) {
437         fDrawBitmapCallCount = 0;
438     }
drawBitmap(const SkDraw &,const SkBitmap &,const SkMatrix &,const SkPaint &)439     virtual void drawBitmap(const SkDraw&, const SkBitmap&,
440                             const SkMatrix&, const SkPaint&) SK_OVERRIDE {
441         fDrawBitmapCallCount++;
442     }
443 
444     int fDrawBitmapCallCount;
445 };
446 
447 class NotificationCounter : public SkDeferredCanvas::NotificationClient {
448 public:
NotificationCounter()449     NotificationCounter() {
450         fPrepareForDrawCount = fStorageAllocatedChangedCount =
451             fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
452     }
453 
prepareForDraw()454     virtual void prepareForDraw() SK_OVERRIDE {
455         fPrepareForDrawCount++;
456     }
storageAllocatedForRecordingChanged(size_t)457     virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {
458         fStorageAllocatedChangedCount++;
459     }
flushedDrawCommands()460     virtual void flushedDrawCommands() SK_OVERRIDE {
461         fFlushedDrawCommandsCount++;
462     }
skippedPendingDrawCommands()463     virtual void skippedPendingDrawCommands() SK_OVERRIDE {
464         fSkippedPendingDrawCommandsCount++;
465     }
466 
467     int fPrepareForDrawCount;
468     int fStorageAllocatedChangedCount;
469     int fFlushedDrawCommandsCount;
470     int fSkippedPendingDrawCommandsCount;
471 
472 private:
473     typedef SkDeferredCanvas::NotificationClient INHERITED;
474 };
475 
476 // Verifies that the deferred canvas triggers a flush when its memory
477 // limit is exceeded
TestDeferredCanvasMemoryLimit(skiatest::Reporter * reporter)478 static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
479     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
480     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
481 
482     NotificationCounter notificationCounter;
483     canvas->setNotificationClient(&notificationCounter);
484 
485     canvas->setMaxRecordingStorage(160000);
486 
487     SkBitmap sourceImage;
488     // 100 by 100 image, takes 40,000 bytes in memory
489     sourceImage.allocN32Pixels(100, 100);
490 
491     for (int i = 0; i < 5; i++) {
492         sourceImage.notifyPixelsChanged(); // to force re-serialization
493         canvas->drawBitmap(sourceImage, 0, 0, NULL);
494     }
495 
496     REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
497 }
498 
TestDeferredCanvasSilentFlush(skiatest::Reporter * reporter)499 static void TestDeferredCanvasSilentFlush(skiatest::Reporter* reporter) {
500     SkAutoTUnref<SkSurface> surface(createSurface(0));
501     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
502 
503     NotificationCounter notificationCounter;
504     canvas->setNotificationClient(&notificationCounter);
505 
506     canvas->silentFlush(); // will skip the initial clear that was recorded in createSurface
507 
508     REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
509     REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
510 }
511 
TestDeferredCanvasBitmapCaching(skiatest::Reporter * reporter)512 static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
513     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
514     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
515 
516     NotificationCounter notificationCounter;
517     canvas->setNotificationClient(&notificationCounter);
518 
519     const int imageCount = 2;
520     SkBitmap sourceImages[imageCount];
521     for (int i = 0; i < imageCount; i++) {
522         sourceImages[i].allocN32Pixels(100, 100);
523     }
524 
525     size_t bitmapSize = sourceImages[0].getSize();
526 
527     canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
528     REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
529     // stored bitmap + drawBitmap command
530     REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > bitmapSize);
531 
532     // verify that nothing can be freed at this point
533     REPORTER_ASSERT(reporter, 0 == canvas->freeMemoryIfPossible(~0U));
534 
535     // verify that flush leaves image in cache
536     REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
537     REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
538     canvas->flush();
539     REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
540     REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
541     REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() >= bitmapSize);
542 
543     // verify that after a flush, cached image can be freed
544     REPORTER_ASSERT(reporter, canvas->freeMemoryIfPossible(~0U) >= bitmapSize);
545 
546     // Verify that caching works for avoiding multiple copies of the same bitmap
547     canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
548     REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
549     canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
550     REPORTER_ASSERT(reporter, 3 == notificationCounter.fStorageAllocatedChangedCount);
551     REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
552     REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < 2 * bitmapSize);
553 
554     // Verify partial eviction based on bytesToFree
555     canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
556     REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
557     canvas->flush();
558     REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
559     REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2 * bitmapSize);
560     size_t bytesFreed = canvas->freeMemoryIfPossible(1);
561     REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
562     REPORTER_ASSERT(reporter,  bytesFreed >= bitmapSize);
563     REPORTER_ASSERT(reporter,  bytesFreed < 2*bitmapSize);
564 
565     // Verifiy that partial purge works, image zero is in cache but not reffed by
566     // a pending draw, while image 1 is locked-in.
567     canvas->freeMemoryIfPossible(~0U);
568     REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
569     canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
570     canvas->flush();
571     canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
572     bytesFreed = canvas->freeMemoryIfPossible(~0U);
573     // only one bitmap should have been freed.
574     REPORTER_ASSERT(reporter,  bytesFreed >= bitmapSize);
575     REPORTER_ASSERT(reporter,  bytesFreed < 2*bitmapSize);
576     // Clear for next test
577     canvas->flush();
578     canvas->freeMemoryIfPossible(~0U);
579     REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < bitmapSize);
580 
581     // Verify the image cache is sensitive to genID bumps
582     canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
583     sourceImages[1].notifyPixelsChanged();
584     canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
585     REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2*bitmapSize);
586 
587     // Verify that nothing in this test caused commands to be skipped
588     REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
589 }
590 
TestDeferredCanvasSkip(skiatest::Reporter * reporter)591 static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
592     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
593     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
594 
595     NotificationCounter notificationCounter;
596     canvas->setNotificationClient(&notificationCounter);
597     canvas->clear(0x0);
598     REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
599     REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
600     canvas->flush();
601     REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
602     REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
603 
604 }
605 
TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter * reporter)606 static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
607     // This is a regression test for crbug.com/155875
608     // This test covers a code path that inserts bitmaps into the bitmap heap through the
609     // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
610     // the flattening and unflattening of the shader.
611     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
612     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
613     // test will fail if nbIterations is not in sync with
614     // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
615     const int nbIterations = 5;
616     size_t bytesAllocated = 0;
617     for(int pass = 0; pass < 2; ++pass) {
618         for(int i = 0; i < nbIterations; ++i) {
619             SkPaint paint;
620             SkBitmap paintPattern;
621             paintPattern.allocN32Pixels(10, 10);
622             paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
623                 (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
624             canvas->drawPaint(paint);
625             canvas->flush();
626 
627             // In the first pass, memory allocation should be monotonically increasing as
628             // the bitmap heap slots fill up.  In the second pass memory allocation should be
629             // stable as bitmap heap slots get recycled.
630             size_t newBytesAllocated = canvas->storageAllocatedForRecording();
631             if (pass == 0) {
632                 REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
633                 bytesAllocated = newBytesAllocated;
634             } else {
635                 REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
636             }
637         }
638     }
639     // All cached resources should be evictable since last canvas call was flush()
640     canvas->freeMemoryIfPossible(~0U);
641     REPORTER_ASSERT(reporter, 0 == canvas->storageAllocatedForRecording());
642 }
643 
TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter * reporter)644 static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
645     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
646 
647     SkBitmap sourceImage;
648     // 100 by 100 image, takes 40,000 bytes in memory
649     sourceImage.allocN32Pixels(100, 100);
650 
651     // 1 under : should not store the image
652     {
653         SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
654         canvas->setBitmapSizeThreshold(39999);
655         canvas->drawBitmap(sourceImage, 0, 0, NULL);
656         size_t newBytesAllocated = canvas->storageAllocatedForRecording();
657         REPORTER_ASSERT(reporter, newBytesAllocated == 0);
658     }
659 
660     // exact value : should store the image
661     {
662         SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
663         canvas->setBitmapSizeThreshold(40000);
664         canvas->drawBitmap(sourceImage, 0, 0, NULL);
665         size_t newBytesAllocated = canvas->storageAllocatedForRecording();
666         REPORTER_ASSERT(reporter, newBytesAllocated > 0);
667     }
668 
669     // 1 over : should still store the image
670     {
671         SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
672         canvas->setBitmapSizeThreshold(40001);
673         canvas->drawBitmap(sourceImage, 0, 0, NULL);
674         size_t newBytesAllocated = canvas->storageAllocatedForRecording();
675         REPORTER_ASSERT(reporter, newBytesAllocated > 0);
676     }
677 }
678 
679 
680 typedef void* PixelPtr;
681 // Returns an opaque pointer which, either points to a GrTexture or RAM pixel
682 // buffer. Used to test pointer equality do determine whether a surface points
683 // to the same pixel data storage as before.
getSurfacePixelPtr(SkSurface * surface,bool useGpu)684 static PixelPtr getSurfacePixelPtr(SkSurface* surface, bool useGpu) {
685     return useGpu ? surface->getCanvas()->getDevice()->accessBitmap(false).getTexture() :
686         surface->getCanvas()->getDevice()->accessBitmap(false).getPixels();
687 }
688 
TestDeferredCanvasSurface(skiatest::Reporter * reporter,GrContextFactory * factory)689 static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
690     SkImageInfo imageSpec = SkImageInfo::MakeN32Premul(10, 10);
691     SkSurface* surface;
692     bool useGpu = NULL != factory;
693 #if SK_SUPPORT_GPU
694     if (useGpu) {
695         GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
696         if (NULL == context) {
697             return;
698         }
699 
700         surface = SkSurface::NewRenderTarget(context, imageSpec);
701     } else {
702         surface = SkSurface::NewRaster(imageSpec);
703     }
704 #else
705     SkASSERT(!useGpu);
706     surface = SkSurface::NewRaster(imageSpec);
707 #endif
708     SkASSERT(NULL != surface);
709     SkAutoTUnref<SkSurface> aur(surface);
710     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
711 
712     SkImage* image1 = canvas->newImageSnapshot();
713     SkAutoTUnref<SkImage> aur_i1(image1);
714     PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
715     // The following clear would normally trigger a copy on write, but
716     // it won't because rendering is deferred.
717     canvas->clear(SK_ColorBLACK);
718     // Obtaining a snapshot directly from the surface (as opposed to the
719     // SkDeferredCanvas) will not trigger a flush of deferred draw operations
720     // and will therefore return the same image as the previous snapshot.
721     SkImage* image2 = surface->newImageSnapshot();
722     SkAutoTUnref<SkImage> aur_i2(image2);
723     // Images identical because of deferral
724     REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID());
725     // Now we obtain a snpshot via the deferred canvas, which triggers a flush.
726     // Because there is a pending clear, this will generate a different image.
727     SkImage* image3 = canvas->newImageSnapshot();
728     SkAutoTUnref<SkImage> aur_i3(image3);
729     REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID());
730     // Verify that backing store is now a different buffer because of copy on
731     // write
732     PixelPtr pixels2 = getSurfacePixelPtr(surface, useGpu);
733     REPORTER_ASSERT(reporter, pixels1 != pixels2);
734     // Verify copy-on write with a draw operation that gets deferred by
735     // the in order draw buffer.
736     SkPaint paint;
737     canvas->drawPaint(paint);
738     SkImage* image4 = canvas->newImageSnapshot();  // implicit flush
739     SkAutoTUnref<SkImage> aur_i4(image4);
740     REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID());
741     PixelPtr pixels3 = getSurfacePixelPtr(surface, useGpu);
742     REPORTER_ASSERT(reporter, pixels2 != pixels3);
743     // Verify that a direct canvas flush with a pending draw does not trigger
744     // a copy on write when the surface is not sharing its buffer with an
745     // SkImage.
746     canvas->clear(SK_ColorWHITE);
747     canvas->flush();
748     PixelPtr pixels4 = getSurfacePixelPtr(surface, useGpu);
749     canvas->drawPaint(paint);
750     canvas->flush();
751     PixelPtr pixels5 = getSurfacePixelPtr(surface, useGpu);
752     REPORTER_ASSERT(reporter, pixels4 == pixels5);
753 }
754 
TestDeferredCanvasSetSurface(skiatest::Reporter * reporter,GrContextFactory * factory)755 static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
756     SkImageInfo imageSpec = SkImageInfo::MakeN32Premul(10, 10);
757     SkSurface* surface;
758     SkSurface* alternateSurface;
759     bool useGpu = NULL != factory;
760 #if SK_SUPPORT_GPU
761     if (useGpu) {
762         GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
763         if (NULL == context) {
764             return;
765         }
766         surface = SkSurface::NewRenderTarget(context, imageSpec);
767         alternateSurface = SkSurface::NewRenderTarget(context, imageSpec);
768     } else {
769         surface = SkSurface::NewRaster(imageSpec);
770         alternateSurface = SkSurface::NewRaster(imageSpec);
771     }
772 #else
773     SkASSERT(!useGpu);
774     surface = SkSurface::NewRaster(imageSpec);
775     alternateSurface = SkSurface::NewRaster(imageSpec);
776 #endif
777     SkASSERT(NULL != surface);
778     SkASSERT(NULL != alternateSurface);
779     SkAutoTUnref<SkSurface> aur1(surface);
780     SkAutoTUnref<SkSurface> aur2(alternateSurface);
781     PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
782     PixelPtr pixels2 = getSurfacePixelPtr(alternateSurface, useGpu);
783     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface));
784     SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
785     canvas->setSurface(alternateSurface);
786     SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
787     REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID());
788     // Verify that none of the above operations triggered a surface copy on write.
789     REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
790     REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) == pixels2);
791     // Verify that a flushed draw command will trigger a copy on write on alternateSurface.
792     canvas->clear(SK_ColorWHITE);
793     canvas->flush();
794     REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
795     REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) != pixels2);
796 }
797 
TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter * reporter)798 static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) {
799     SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterPMColor(100, 100));
800     SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get()));
801 
802     NotificationCounter notificationCounter;
803     canvas->setNotificationClient(&notificationCounter);
804 
805     SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
806     SkAutoTUnref<SkSurface> secondarySurface(canvas->newSurface(info));
807 
808     SkRect rect = SkRect::MakeWH(5, 5);
809     SkPaint paint;
810     // After spawning a compatible canvas:
811     // 1) Verify that secondary canvas is usable and does not report to the notification client.
812     surface->getCanvas()->drawRect(rect, paint);
813     REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0);
814     // 2) Verify that original canvas is usable and still reports to the notification client.
815     canvas->drawRect(rect, paint);
816     REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1);
817 }
818 
DEF_TEST(DeferredCanvas_CPU,reporter)819 DEF_TEST(DeferredCanvas_CPU, reporter) {
820     TestDeferredCanvasBitmapAccess(reporter);
821     TestDeferredCanvasFlush(reporter);
822     TestDeferredCanvasSilentFlush(reporter);
823     TestDeferredCanvasFreshFrame(reporter);
824     TestDeferredCanvasMemoryLimit(reporter);
825     TestDeferredCanvasBitmapCaching(reporter);
826     TestDeferredCanvasSkip(reporter);
827     TestDeferredCanvasBitmapShaderNoLeak(reporter);
828     TestDeferredCanvasBitmapSizeThreshold(reporter);
829     TestDeferredCanvasCreateCompatibleDevice(reporter);
830     TestDeferredCanvasWritePixelsToSurface(reporter);
831     TestDeferredCanvasSurface(reporter, NULL);
832     TestDeferredCanvasSetSurface(reporter, NULL);
833 }
834 
DEF_GPUTEST(DeferredCanvas_GPU,reporter,factory)835 DEF_GPUTEST(DeferredCanvas_GPU, reporter, factory) {
836     if (factory != NULL) {
837         TestDeferredCanvasSurface(reporter, factory);
838         TestDeferredCanvasSetSurface(reporter, factory);
839     }
840 }
841