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