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