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(¬ificationCounter); 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(¬ificationCounter); 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(¬ificationCounter); 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