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