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 "SkBitmapDevice.h" 11 #include "SkBitmapProcShader.h" 12 #include "SkDeferredCanvas.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 SkBitmapDevice 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 SkImageInfo&) 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 SkBitmapDevice 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 SkBitmapDevice 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.setAlphaType(kOpaque_SkAlphaType); 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.setAlphaType(kPremul_SkAlphaType); 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 SkBitmapDevice { 437 public: 438 MockDevice(const SkBitmap& bm) : SkBitmapDevice(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 SkBitmapDevice device(store); 506 NotificationCounter notificationCounter; 507 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device)); 508 canvas->setNotificationClient(¬ificationCounter); 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 SkBitmapDevice device(store); 589 NotificationCounter notificationCounter; 590 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device)); 591 canvas->setNotificationClient(¬ificationCounter); 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 SkBitmapDevice 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 SkBitmapDevice 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 SkBitmapDevice 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 SkBitmapDevice 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 SkImageInfo imageSpec = { 696 10, // width 697 10, // height 698 kPMColor_SkColorType, 699 kPremul_SkAlphaType 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 if (NULL == context) { 707 return; 708 } 709 710 surface = SkSurface::NewRenderTarget(context, imageSpec); 711 } else { 712 surface = SkSurface::NewRaster(imageSpec); 713 } 714 #else 715 SkASSERT(!useGpu); 716 surface = SkSurface::NewRaster(imageSpec); 717 #endif 718 SkASSERT(NULL != surface); 719 SkAutoTUnref<SkSurface> aur(surface); 720 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface)); 721 722 SkImage* image1 = canvas->newImageSnapshot(); 723 SkAutoTUnref<SkImage> aur_i1(image1); 724 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu); 725 // The following clear would normally trigger a copy on write, but 726 // it won't because rendering is deferred. 727 canvas->clear(SK_ColorBLACK); 728 // Obtaining a snapshot directly from the surface (as opposed to the 729 // SkDeferredCanvas) will not trigger a flush of deferred draw operations 730 // and will therefore return the same image as the previous snapshot. 731 SkImage* image2 = surface->newImageSnapshot(); 732 SkAutoTUnref<SkImage> aur_i2(image2); 733 // Images identical because of deferral 734 REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID()); 735 // Now we obtain a snpshot via the deferred canvas, which triggers a flush. 736 // Because there is a pending clear, this will generate a different image. 737 SkImage* image3 = canvas->newImageSnapshot(); 738 SkAutoTUnref<SkImage> aur_i3(image3); 739 REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID()); 740 // Verify that backing store is now a different buffer because of copy on 741 // write 742 PixelPtr pixels2 = getSurfacePixelPtr(surface, useGpu); 743 REPORTER_ASSERT(reporter, pixels1 != pixels2); 744 // Verify copy-on write with a draw operation that gets deferred by 745 // the in order draw buffer. 746 SkPaint paint; 747 canvas->drawPaint(paint); 748 SkImage* image4 = canvas->newImageSnapshot(); // implicit flush 749 SkAutoTUnref<SkImage> aur_i4(image4); 750 REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID()); 751 PixelPtr pixels3 = getSurfacePixelPtr(surface, useGpu); 752 REPORTER_ASSERT(reporter, pixels2 != pixels3); 753 // Verify that a direct canvas flush with a pending draw does not trigger 754 // a copy on write when the surface is not sharing its buffer with an 755 // SkImage. 756 canvas->clear(SK_ColorWHITE); 757 canvas->flush(); 758 PixelPtr pixels4 = getSurfacePixelPtr(surface, useGpu); 759 canvas->drawPaint(paint); 760 canvas->flush(); 761 PixelPtr pixels5 = getSurfacePixelPtr(surface, useGpu); 762 REPORTER_ASSERT(reporter, pixels4 == pixels5); 763 } 764 765 static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) { 766 SkImageInfo imageSpec = { 767 10, // width 768 10, // height 769 kPMColor_SkColorType, 770 kPremul_SkAlphaType 771 }; 772 SkSurface* surface; 773 SkSurface* alternateSurface; 774 bool useGpu = NULL != factory; 775 #if SK_SUPPORT_GPU 776 if (useGpu) { 777 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType); 778 if (NULL == context) { 779 return; 780 } 781 surface = SkSurface::NewRenderTarget(context, imageSpec); 782 alternateSurface = SkSurface::NewRenderTarget(context, imageSpec); 783 } else { 784 surface = SkSurface::NewRaster(imageSpec); 785 alternateSurface = SkSurface::NewRaster(imageSpec); 786 } 787 #else 788 SkASSERT(!useGpu); 789 surface = SkSurface::NewRaster(imageSpec); 790 alternateSurface = SkSurface::NewRaster(imageSpec); 791 #endif 792 SkASSERT(NULL != surface); 793 SkASSERT(NULL != alternateSurface); 794 SkAutoTUnref<SkSurface> aur1(surface); 795 SkAutoTUnref<SkSurface> aur2(alternateSurface); 796 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu); 797 PixelPtr pixels2 = getSurfacePixelPtr(alternateSurface, useGpu); 798 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface)); 799 SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot()); 800 canvas->setSurface(alternateSurface); 801 SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot()); 802 REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID()); 803 // Verify that none of the above operations triggered a surface copy on write. 804 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1); 805 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) == pixels2); 806 // Verify that a flushed draw command will trigger a copy on write on alternateSurface. 807 canvas->clear(SK_ColorWHITE); 808 canvas->flush(); 809 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1); 810 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) != pixels2); 811 } 812 813 static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) { 814 SkBitmap store; 815 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); 816 store.allocPixels(); 817 SkBitmapDevice device(store); 818 NotificationCounter notificationCounter; 819 SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(&device)); 820 canvas->setNotificationClient(¬ificationCounter); 821 SkAutoTUnref<SkBaseDevice> secondaryDevice(canvas->createCompatibleDevice( 822 SkBitmap::kARGB_8888_Config, 10, 10, device.isOpaque())); 823 SkCanvas secondaryCanvas(secondaryDevice.get()); 824 SkRect rect = SkRect::MakeWH(5, 5); 825 SkPaint paint; 826 // After spawning a compatible canvas: 827 // 1) Verify that secondary canvas is usable and does not report to the notification client. 828 secondaryCanvas.drawRect(rect, paint); 829 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0); 830 // 2) Verify that original canvas is usable and still reports to the notification client. 831 canvas->drawRect(rect, paint); 832 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1); 833 } 834 835 static void TestDeferredCanvas(skiatest::Reporter* reporter, GrContextFactory* factory) { 836 TestDeferredCanvasBitmapAccess(reporter); 837 TestDeferredCanvasFlush(reporter); 838 TestDeferredCanvasFreshFrame(reporter); 839 TestDeferredCanvasMemoryLimit(reporter); 840 TestDeferredCanvasBitmapCaching(reporter); 841 TestDeferredCanvasSkip(reporter); 842 TestDeferredCanvasBitmapShaderNoLeak(reporter); 843 TestDeferredCanvasBitmapSizeThreshold(reporter); 844 TestDeferredCanvasCreateCompatibleDevice(reporter); 845 TestDeferredCanvasWritePixelsToSurface(reporter); 846 TestDeferredCanvasSurface(reporter, NULL); 847 TestDeferredCanvasSetSurface(reporter, NULL); 848 if (NULL != factory) { 849 TestDeferredCanvasSurface(reporter, factory); 850 TestDeferredCanvasSetSurface(reporter, factory); 851 } 852 } 853 854 #include "TestClassDef.h" 855 DEFINE_GPUTESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas) 856