1 /* 2 * Copyright 2013 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 <functional> 9 #include "SkCanvas.h" 10 #include "SkData.h" 11 #include "SkDevice.h" 12 #include "SkImage_Base.h" 13 #include "SkPath.h" 14 #include "SkRRect.h" 15 #include "SkSurface.h" 16 #include "SkUtils.h" 17 #include "Test.h" 18 19 #if SK_SUPPORT_GPU 20 #include "GrContext.h" 21 #include "GrGpu.h" 22 #endif 23 24 #include <initializer_list> 25 26 static void release_direct_surface_storage(void* pixels, void* context) { 27 SkASSERT(pixels == context); 28 sk_free(pixels); 29 } 30 static SkSurface* create_surface(SkAlphaType at = kPremul_SkAlphaType, 31 SkImageInfo* requestedInfo = nullptr) { 32 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at); 33 if (requestedInfo) { 34 *requestedInfo = info; 35 } 36 return SkSurface::NewRaster(info); 37 } 38 static SkSurface* create_direct_surface(SkAlphaType at = kPremul_SkAlphaType, 39 SkImageInfo* requestedInfo = nullptr) { 40 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at); 41 if (requestedInfo) { 42 *requestedInfo = info; 43 } 44 const size_t rowBytes = info.minRowBytes(); 45 void* storage = sk_malloc_throw(info.getSafeSize(rowBytes)); 46 return SkSurface::NewRasterDirectReleaseProc(info, storage, rowBytes, 47 release_direct_surface_storage, 48 storage); 49 } 50 #if SK_SUPPORT_GPU 51 static SkSurface* create_gpu_surface(GrContext* context, SkAlphaType at = kPremul_SkAlphaType, 52 SkImageInfo* requestedInfo = nullptr) { 53 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at); 54 if (requestedInfo) { 55 *requestedInfo = info; 56 } 57 return SkSurface::NewRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr); 58 } 59 static SkSurface* create_gpu_scratch_surface(GrContext* context, 60 SkAlphaType at = kPremul_SkAlphaType, 61 SkImageInfo* requestedInfo = nullptr) { 62 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at); 63 if (requestedInfo) { 64 *requestedInfo = info; 65 } 66 return SkSurface::NewRenderTarget(context, SkBudgeted::kYes, info, 0, nullptr); 67 } 68 #endif 69 70 DEF_TEST(SurfaceEmpty, reporter) { 71 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 72 REPORTER_ASSERT(reporter, nullptr == SkSurface::NewRaster(info)); 73 REPORTER_ASSERT(reporter, nullptr == SkSurface::NewRasterDirect(info, nullptr, 0)); 74 75 } 76 #if SK_SUPPORT_GPU 77 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceEmpty_Gpu, reporter, context) { 78 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 79 REPORTER_ASSERT(reporter, nullptr == 80 SkSurface::NewRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr)); 81 } 82 #endif 83 84 #if SK_SUPPORT_GPU 85 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceWrappedTexture, reporter, context) { 86 GrGpu* gpu = context->getGpu(); 87 if (!gpu) { 88 return; 89 } 90 91 // Test the wrapped factory for SkSurface by creating a backend texture and then wrap it in 92 // a SkSurface. 93 static const int kW = 100; 94 static const int kH = 100; 95 static const uint32_t kOrigColor = 0xFFAABBCC; 96 SkAutoTArray<uint32_t> pixels(kW * kH); 97 sk_memset32(pixels.get(), kOrigColor, kW * kH); 98 GrBackendObject texHandle = gpu->createTestingOnlyBackendTexture(pixels.get(), kW, kH, 99 kRGBA_8888_GrPixelConfig); 100 101 GrBackendTextureDesc wrappedDesc; 102 wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig; 103 wrappedDesc.fWidth = kW; 104 wrappedDesc.fHeight = kH; 105 wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin; 106 wrappedDesc.fSampleCnt = 0; 107 wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag; 108 wrappedDesc.fTextureHandle = texHandle; 109 110 SkAutoTUnref<SkSurface> surface( 111 SkSurface::NewWrappedRenderTarget(context, wrappedDesc, nullptr)); 112 REPORTER_ASSERT(reporter, surface); 113 if (surface) { 114 // Validate that we can draw to the canvas and that the original texture color is preserved 115 // in pixels that aren't rendered to via the surface. 116 SkPaint paint; 117 static const SkColor kRectColor = ~kOrigColor | 0xFF000000; 118 paint.setColor(kRectColor); 119 surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2), 120 paint); 121 SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH); 122 surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0); 123 bool stop = false; 124 SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF), 125 (kOrigColor >> 0 & 0xFF), 126 (kOrigColor >> 8 & 0xFF), 127 (kOrigColor >> 16 & 0xFF)); 128 SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF), 129 (kRectColor >> 16 & 0xFF), 130 (kRectColor >> 8 & 0xFF), 131 (kRectColor >> 0 & 0xFF)); 132 for (int y = 0; y < kH/2 && !stop; ++y) { 133 for (int x = 0; x < kW && !stop; ++x) { 134 REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]); 135 if (rectColorPM != pixels[x + y * kW]) { 136 stop = true; 137 } 138 } 139 } 140 stop = false; 141 for (int y = kH/2; y < kH && !stop; ++y) { 142 for (int x = 0; x < kW && !stop; ++x) { 143 REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]); 144 if (origColorPM != pixels[x + y * kW]) { 145 stop = true; 146 } 147 } 148 } 149 } 150 gpu->deleteTestingOnlyBackendTexture(texHandle); 151 } 152 #endif 153 154 static void test_canvas_peek(skiatest::Reporter* reporter, 155 SkSurface* surface, 156 const SkImageInfo& requestInfo, 157 bool expectPeekSuccess) { 158 const SkColor color = SK_ColorRED; 159 const SkPMColor pmcolor = SkPreMultiplyColor(color); 160 SkImageInfo info; 161 size_t rowBytes; 162 surface->getCanvas()->clear(color); 163 164 const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes); 165 bool success = SkToBool(addr); 166 REPORTER_ASSERT(reporter, expectPeekSuccess == success); 167 168 SkImageInfo info2; 169 size_t rb2; 170 const void* addr2 = surface->peekPixels(&info2, &rb2); 171 172 if (success) { 173 REPORTER_ASSERT(reporter, requestInfo == info); 174 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes); 175 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); 176 177 REPORTER_ASSERT(reporter, addr2 == addr); 178 REPORTER_ASSERT(reporter, info2 == info); 179 REPORTER_ASSERT(reporter, rb2 == rowBytes); 180 } else { 181 REPORTER_ASSERT(reporter, nullptr == addr2); 182 } 183 } 184 DEF_TEST(SurfaceCanvasPeek, reporter) { 185 for (auto& surface_func : { &create_surface, &create_direct_surface }) { 186 SkImageInfo requestInfo; 187 SkAutoTUnref<SkSurface> surface(surface_func(kPremul_SkAlphaType, &requestInfo)); 188 test_canvas_peek(reporter, surface, requestInfo, true); 189 } 190 } 191 #if SK_SUPPORT_GPU 192 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCanvasPeek_Gpu, reporter, context) { 193 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 194 SkImageInfo requestInfo; 195 SkAutoTUnref<SkSurface> surface(surface_func(context, kPremul_SkAlphaType, &requestInfo)); 196 test_canvas_peek(reporter, surface, requestInfo, false); 197 } 198 } 199 #endif 200 201 // For compatibility with clients that still call accessBitmap(), we need to ensure that we bump 202 // the bitmap's genID when we draw to it, else they won't know it has new values. When they are 203 // exclusively using surface/image, and we can hide accessBitmap from device, we can remove this 204 // test. 205 void test_access_pixels(skiatest::Reporter* reporter, SkSurface* surface) { 206 SkCanvas* canvas = surface->getCanvas(); 207 canvas->clear(0); 208 209 SkBaseDevice* device = canvas->getDevice_just_for_deprecated_compatibility_testing(); 210 SkBitmap bm = device->accessBitmap(false); 211 uint32_t genID0 = bm.getGenerationID(); 212 // Now we draw something, which needs to "dirty" the genID (sorta like copy-on-write) 213 canvas->drawColor(SK_ColorBLUE); 214 // Now check that we get a different genID 215 uint32_t genID1 = bm.getGenerationID(); 216 REPORTER_ASSERT(reporter, genID0 != genID1); 217 } 218 DEF_TEST(SurfaceAccessPixels, reporter) { 219 for (auto& surface_func : { &create_surface, &create_direct_surface }) { 220 SkAutoTUnref<SkSurface> surface(surface_func(kPremul_SkAlphaType, nullptr)); 221 test_access_pixels(reporter, surface); 222 } 223 } 224 #if SK_SUPPORT_GPU 225 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceAccessPixels_Gpu, reporter, context) { 226 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 227 SkAutoTUnref<SkSurface> surface(surface_func(context, kPremul_SkAlphaType, nullptr)); 228 test_access_pixels(reporter, surface); 229 } 230 } 231 #endif 232 233 static void test_snapshot_alphatype(skiatest::Reporter* reporter, SkSurface* surface, 234 bool expectOpaque) { 235 REPORTER_ASSERT(reporter, surface); 236 if (surface) { 237 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 238 REPORTER_ASSERT(reporter, image); 239 if (image) { 240 REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(expectOpaque)); 241 } 242 } 243 } 244 DEF_TEST(SurfaceSnapshotAlphaType, reporter) { 245 for (auto& surface_func : { &create_surface, &create_direct_surface }) { 246 for (auto& isOpaque : { true, false }) { 247 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; 248 SkAutoTUnref<SkSurface> surface(surface_func(alphaType, nullptr)); 249 test_snapshot_alphatype(reporter, surface, isOpaque); 250 } 251 } 252 } 253 #if SK_SUPPORT_GPU 254 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceSnapshotAlphaType_Gpu, reporter, context) { 255 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 256 for (auto& isOpaque : { true, false }) { 257 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; 258 SkAutoTUnref<SkSurface> surface(surface_func(context, alphaType, nullptr)); 259 test_snapshot_alphatype(reporter, surface, isOpaque); 260 } 261 } 262 } 263 #endif 264 265 static GrBackendObject get_surface_backend_texture_handle( 266 SkSurface* s, SkSurface::BackendHandleAccess a) { 267 return s->getTextureHandle(a); 268 } 269 static GrBackendObject get_surface_backend_render_target_handle( 270 SkSurface* s, SkSurface::BackendHandleAccess a) { 271 GrBackendObject result; 272 if (!s->getRenderTargetHandle(&result, a)) { 273 return 0; 274 } 275 return result; 276 } 277 278 static void test_backend_handle_access_copy_on_write( 279 skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess mode, 280 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) { 281 GrBackendObject obj1 = func(surface, mode); 282 SkAutoTUnref<SkImage> snap1(surface->newImageSnapshot()); 283 284 GrBackendObject obj2 = func(surface, mode); 285 SkAutoTUnref<SkImage> snap2(surface->newImageSnapshot()); 286 287 // If the access mode triggers CoW, then the backend objects should reflect it. 288 REPORTER_ASSERT(reporter, (obj1 == obj2) == (snap1 == snap2)); 289 } 290 DEF_TEST(SurfaceBackendHandleAccessCopyOnWrite, reporter) { 291 const SkSurface::BackendHandleAccess accessModes[] = { 292 SkSurface::kFlushRead_BackendHandleAccess, 293 SkSurface::kFlushWrite_BackendHandleAccess, 294 SkSurface::kDiscardWrite_BackendHandleAccess, 295 }; 296 for (auto& handle_access_func : 297 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) { 298 for (auto& accessMode : accessModes) { 299 SkAutoTUnref<SkSurface> surface(create_surface()); 300 test_backend_handle_access_copy_on_write(reporter, surface, accessMode, 301 handle_access_func); 302 } 303 } 304 } 305 #if SK_SUPPORT_GPU 306 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessCopyOnWrite_Gpu, reporter, context) { 307 const SkSurface::BackendHandleAccess accessModes[] = { 308 SkSurface::kFlushRead_BackendHandleAccess, 309 SkSurface::kFlushWrite_BackendHandleAccess, 310 SkSurface::kDiscardWrite_BackendHandleAccess, 311 }; 312 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 313 for (auto& handle_access_func : 314 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) { 315 for (auto& accessMode : accessModes) { 316 SkAutoTUnref<SkSurface> surface(surface_func(context, kPremul_SkAlphaType, 317 nullptr)); 318 test_backend_handle_access_copy_on_write(reporter, surface, accessMode, 319 handle_access_func); 320 } 321 } 322 } 323 } 324 #endif 325 326 static bool same_image(SkImage* a, SkImage* b, 327 std::function<intptr_t(SkImage*)> getImageBackingStore) { 328 return getImageBackingStore(a) == getImageBackingStore(b); 329 } 330 331 static bool same_image_surf(SkImage* a, SkSurface* b, 332 std::function<intptr_t(SkImage*)> getImageBackingStore, 333 std::function<intptr_t(SkSurface*)> getSurfaceBackingStore) { 334 return getImageBackingStore(a) == getSurfaceBackingStore(b); 335 } 336 337 static void test_unique_image_snap(skiatest::Reporter* reporter, SkSurface* surface, 338 bool surfaceIsDirect, 339 std::function<intptr_t(SkImage*)> imageBackingStore, 340 std::function<intptr_t(SkSurface*)> surfaceBackingStore) { 341 std::function<intptr_t(SkImage*)> ibs = imageBackingStore; 342 std::function<intptr_t(SkSurface*)> sbs = surfaceBackingStore; 343 static const SkBudgeted kB = SkBudgeted::kNo; 344 { 345 SkAutoTUnref<SkImage> image(surface->newImageSnapshot(kB, SkSurface::kYes_ForceUnique)); 346 REPORTER_ASSERT(reporter, !same_image_surf(image, surface, ibs, sbs)); 347 REPORTER_ASSERT(reporter, image->unique()); 348 } 349 { 350 SkAutoTUnref<SkImage> image1(surface->newImageSnapshot(kB, SkSurface::kYes_ForceUnique)); 351 REPORTER_ASSERT(reporter, !same_image_surf(image1, surface, ibs, sbs)); 352 REPORTER_ASSERT(reporter, image1->unique()); 353 SkAutoTUnref<SkImage> image2(surface->newImageSnapshot(kB, SkSurface::kYes_ForceUnique)); 354 REPORTER_ASSERT(reporter, !same_image_surf(image2, surface, ibs, sbs)); 355 REPORTER_ASSERT(reporter, !same_image(image1, image2, ibs)); 356 REPORTER_ASSERT(reporter, image2->unique()); 357 } 358 { 359 SkAutoTUnref<SkImage> image1(surface->newImageSnapshot(kB, SkSurface::kNo_ForceUnique)); 360 SkAutoTUnref<SkImage> image2(surface->newImageSnapshot(kB, SkSurface::kYes_ForceUnique)); 361 SkAutoTUnref<SkImage> image3(surface->newImageSnapshot(kB, SkSurface::kNo_ForceUnique)); 362 SkAutoTUnref<SkImage> image4(surface->newImageSnapshot(kB, SkSurface::kYes_ForceUnique)); 363 // Image 1 and 3 ought to be the same (or we're missing an optimization). 364 REPORTER_ASSERT(reporter, same_image(image1, image3, ibs)); 365 // If the surface is not direct then images 1 and 3 should alias the surface's 366 // store. 367 REPORTER_ASSERT(reporter, !surfaceIsDirect == same_image_surf(image1, surface, ibs, sbs)); 368 // Image 2 should not be shared with any other image. 369 REPORTER_ASSERT(reporter, !same_image(image1, image2, ibs) && 370 !same_image(image3, image2, ibs) && 371 !same_image(image4, image2, ibs)); 372 REPORTER_ASSERT(reporter, image2->unique()); 373 REPORTER_ASSERT(reporter, !same_image_surf(image2, surface, ibs, sbs)); 374 // Image 4 should not be shared with any other image. 375 REPORTER_ASSERT(reporter, !same_image(image1, image4, ibs) && 376 !same_image(image3, image4, ibs)); 377 REPORTER_ASSERT(reporter, !same_image_surf(image4, surface, ibs, sbs)); 378 REPORTER_ASSERT(reporter, image4->unique()); 379 } 380 } 381 382 DEF_TEST(UniqueImageSnapshot, reporter) { 383 auto getImageBackingStore = [reporter](SkImage* image) { 384 SkPixmap pm; 385 bool success = image->peekPixels(&pm); 386 REPORTER_ASSERT(reporter, success); 387 return reinterpret_cast<intptr_t>(pm.addr()); 388 }; 389 auto getSufaceBackingStore = [reporter](SkSurface* surface) { 390 SkImageInfo info; 391 size_t rowBytes; 392 const void* pixels = surface->getCanvas()->peekPixels(&info, &rowBytes); 393 REPORTER_ASSERT(reporter, pixels); 394 return reinterpret_cast<intptr_t>(pixels); 395 }; 396 397 SkAutoTUnref<SkSurface> surface(create_surface()); 398 test_unique_image_snap(reporter, surface, false, getImageBackingStore, getSufaceBackingStore); 399 surface.reset(create_direct_surface()); 400 test_unique_image_snap(reporter, surface, true, getImageBackingStore, getSufaceBackingStore); 401 } 402 403 #if SK_SUPPORT_GPU 404 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(UniqueImageSnapshot_Gpu, reporter, context) { 405 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 406 SkAutoTUnref<SkSurface> surface(surface_func(context, kOpaque_SkAlphaType, nullptr)); 407 408 auto imageBackingStore = [reporter](SkImage* image) { 409 GrTexture* texture = as_IB(image)->peekTexture(); 410 if (!texture) { 411 ERRORF(reporter, "Not texture backed."); 412 return static_cast<intptr_t>(0); 413 } 414 return static_cast<intptr_t>(texture->getUniqueID()); 415 }; 416 417 auto surfaceBackingStore = [reporter](SkSurface* surface) { 418 GrRenderTarget* rt = 419 surface->getCanvas()->internal_private_accessTopLayerRenderTarget(); 420 if (!rt) { 421 ERRORF(reporter, "Not render target backed."); 422 return static_cast<intptr_t>(0); 423 } 424 return static_cast<intptr_t>(rt->getUniqueID()); 425 }; 426 427 test_unique_image_snap(reporter, surface, false, imageBackingStore, surfaceBackingStore); 428 429 // Test again with a "direct" render target; 430 GrBackendObject textureObject = context->getGpu()->createTestingOnlyBackendTexture(nullptr, 431 10, 10, kRGBA_8888_GrPixelConfig); 432 GrBackendTextureDesc desc; 433 desc.fConfig = kRGBA_8888_GrPixelConfig; 434 desc.fWidth = 10; 435 desc.fHeight = 10; 436 desc.fFlags = kRenderTarget_GrBackendTextureFlag; 437 desc.fTextureHandle = textureObject; 438 GrTexture* texture = context->textureProvider()->wrapBackendTexture(desc); 439 { 440 SkAutoTUnref<SkSurface> surface( 441 SkSurface::NewRenderTargetDirect(texture->asRenderTarget())); 442 // We should be able to pass true here, but disallowing copy on write for direct GPU 443 // surfaces is not yet implemented. 444 test_unique_image_snap(reporter, surface, false, imageBackingStore, 445 surfaceBackingStore); 446 } 447 texture->unref(); 448 context->getGpu()->deleteTestingOnlyBackendTexture(textureObject); 449 } 450 } 451 #endif 452 453 #if SK_SUPPORT_GPU 454 // May we (soon) eliminate the need to keep testing this, by hiding the bloody device! 455 static uint32_t get_legacy_gen_id(SkSurface* surface) { 456 SkBaseDevice* device = 457 surface->getCanvas()->getDevice_just_for_deprecated_compatibility_testing(); 458 return device->accessBitmap(false).getGenerationID(); 459 } 460 /* 461 * Test legacy behavor of bumping the surface's device's bitmap's genID when we access its 462 * texture handle for writing. 463 * 464 * Note: this needs to be tested separately from checking newImageSnapshot, as calling that 465 * can also incidentally bump the genID (when a new backing surface is created). 466 */ 467 static void test_backend_handle_gen_id( 468 skiatest::Reporter* reporter, SkSurface* surface, 469 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) { 470 const uint32_t gen0 = get_legacy_gen_id(surface); 471 func(surface, SkSurface::kFlushRead_BackendHandleAccess); 472 const uint32_t gen1 = get_legacy_gen_id(surface); 473 REPORTER_ASSERT(reporter, gen0 == gen1); 474 475 func(surface, SkSurface::kFlushWrite_BackendHandleAccess); 476 const uint32_t gen2 = get_legacy_gen_id(surface); 477 REPORTER_ASSERT(reporter, gen0 != gen2); 478 479 func(surface, SkSurface::kDiscardWrite_BackendHandleAccess); 480 const uint32_t gen3 = get_legacy_gen_id(surface); 481 REPORTER_ASSERT(reporter, gen0 != gen3); 482 REPORTER_ASSERT(reporter, gen2 != gen3); 483 } 484 static void test_backend_handle_unique_id( 485 skiatest::Reporter* reporter, SkSurface* surface, 486 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) { 487 SkAutoTUnref<SkImage> image0(surface->newImageSnapshot()); 488 GrBackendObject obj = func(surface, SkSurface::kFlushRead_BackendHandleAccess); 489 REPORTER_ASSERT(reporter, obj != 0); 490 SkAutoTUnref<SkImage> image1(surface->newImageSnapshot()); 491 // just read access should not affect the snapshot 492 REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID()); 493 494 obj = func(surface, SkSurface::kFlushWrite_BackendHandleAccess); 495 REPORTER_ASSERT(reporter, obj != 0); 496 SkAutoTUnref<SkImage> image2(surface->newImageSnapshot()); 497 // expect a new image, since we claimed we would write 498 REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID()); 499 500 obj = func(surface, SkSurface::kDiscardWrite_BackendHandleAccess); 501 REPORTER_ASSERT(reporter, obj != 0); 502 SkAutoTUnref<SkImage> image3(surface->newImageSnapshot()); 503 // expect a new(er) image, since we claimed we would write 504 REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID()); 505 REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID()); 506 } 507 // No CPU test. 508 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessIDs_Gpu, reporter, context) { 509 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 510 for (auto& test_func : { &test_backend_handle_unique_id, &test_backend_handle_gen_id }) { 511 for (auto& handle_access_func : 512 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle}) { 513 SkAutoTUnref<SkSurface> surface(surface_func(context, kPremul_SkAlphaType, 514 nullptr)); 515 test_func(reporter, surface, handle_access_func); 516 } 517 } 518 } 519 } 520 #endif 521 522 // Verify that the right canvas commands trigger a copy on write. 523 static void test_copy_on_write(skiatest::Reporter* reporter, SkSurface* surface) { 524 SkCanvas* canvas = surface->getCanvas(); 525 526 const SkRect testRect = 527 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 528 SkIntToScalar(4), SkIntToScalar(5)); 529 SkPath testPath; 530 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 531 SkIntToScalar(2), SkIntToScalar(1))); 532 533 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1); 534 535 SkRegion testRegion; 536 testRegion.setRect(testIRect); 537 538 539 const SkColor testColor = 0x01020304; 540 const SkPaint testPaint; 541 const SkPoint testPoints[3] = { 542 {SkIntToScalar(0), SkIntToScalar(0)}, 543 {SkIntToScalar(2), SkIntToScalar(1)}, 544 {SkIntToScalar(0), SkIntToScalar(2)} 545 }; 546 const size_t testPointCount = 3; 547 548 SkBitmap testBitmap; 549 testBitmap.allocN32Pixels(10, 10); 550 testBitmap.eraseColor(0); 551 552 SkRRect testRRect; 553 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1); 554 555 SkString testText("Hello World"); 556 const SkPoint testPoints2[] = { 557 { SkIntToScalar(0), SkIntToScalar(1) }, 558 { SkIntToScalar(1), SkIntToScalar(1) }, 559 { SkIntToScalar(2), SkIntToScalar(1) }, 560 { SkIntToScalar(3), SkIntToScalar(1) }, 561 { SkIntToScalar(4), SkIntToScalar(1) }, 562 { SkIntToScalar(5), SkIntToScalar(1) }, 563 { SkIntToScalar(6), SkIntToScalar(1) }, 564 { SkIntToScalar(7), SkIntToScalar(1) }, 565 { SkIntToScalar(8), SkIntToScalar(1) }, 566 { SkIntToScalar(9), SkIntToScalar(1) }, 567 { SkIntToScalar(10), SkIntToScalar(1) }, 568 }; 569 570 #define EXPECT_COPY_ON_WRITE(command) \ 571 { \ 572 SkImage* imageBefore = surface->newImageSnapshot(); \ 573 SkAutoTUnref<SkImage> aur_before(imageBefore); \ 574 canvas-> command ; \ 575 SkImage* imageAfter = surface->newImageSnapshot(); \ 576 SkAutoTUnref<SkImage> aur_after(imageAfter); \ 577 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \ 578 } 579 580 EXPECT_COPY_ON_WRITE(clear(testColor)) 581 EXPECT_COPY_ON_WRITE(drawPaint(testPaint)) 582 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \ 583 testPaint)) 584 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint)) 585 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint)) 586 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint)) 587 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint)) 588 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0)) 589 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, testRect, nullptr)) 590 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, nullptr)) 591 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint)) 592 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \ 593 testPaint)) 594 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, nullptr, \ 595 testPaint)) 596 } 597 DEF_TEST(SurfaceCopyOnWrite, reporter) { 598 SkAutoTUnref<SkSurface> surface(create_surface()); 599 test_copy_on_write(reporter, surface); 600 } 601 #if SK_SUPPORT_GPU 602 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCopyOnWrite_Gpu, reporter, context) { 603 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 604 SkAutoTUnref<SkSurface> surface(surface_func(context, kPremul_SkAlphaType, nullptr)); 605 test_copy_on_write(reporter, surface); 606 } 607 } 608 #endif 609 610 static void test_writable_after_snapshot_release(skiatest::Reporter* reporter, 611 SkSurface* surface) { 612 // This test succeeds by not triggering an assertion. 613 // The test verifies that the surface remains writable (usable) after 614 // acquiring and releasing a snapshot without triggering a copy on write. 615 SkCanvas* canvas = surface->getCanvas(); 616 canvas->clear(1); 617 surface->newImageSnapshot()->unref(); // Create and destroy SkImage 618 canvas->clear(2); // Must not assert internally 619 } 620 DEF_TEST(SurfaceWriteableAfterSnapshotRelease, reporter) { 621 SkAutoTUnref<SkSurface> surface(create_surface()); 622 test_writable_after_snapshot_release(reporter, surface); 623 } 624 #if SK_SUPPORT_GPU 625 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceWriteableAfterSnapshotRelease_Gpu, reporter, context) { 626 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 627 SkAutoTUnref<SkSurface> surface(surface_func(context, kPremul_SkAlphaType, nullptr)); 628 test_writable_after_snapshot_release(reporter, surface); 629 } 630 } 631 #endif 632 633 #if SK_SUPPORT_GPU 634 static void test_crbug263329(skiatest::Reporter* reporter, 635 SkSurface* surface1, 636 SkSurface* surface2) { 637 // This is a regression test for crbug.com/263329 638 // Bug was caused by onCopyOnWrite releasing the old surface texture 639 // back to the scratch texture pool even though the texture is used 640 // by and active SkImage_Gpu. 641 SkCanvas* canvas1 = surface1->getCanvas(); 642 SkCanvas* canvas2 = surface2->getCanvas(); 643 canvas1->clear(1); 644 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot()); 645 // Trigger copy on write, new backing is a scratch texture 646 canvas1->clear(2); 647 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot()); 648 // Trigger copy on write, old backing should not be returned to scratch 649 // pool because it is held by image2 650 canvas1->clear(3); 651 652 canvas2->clear(4); 653 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot()); 654 // Trigger copy on write on surface2. The new backing store should not 655 // be recycling a texture that is held by an existing image. 656 canvas2->clear(5); 657 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot()); 658 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image3)->getTexture()); 659 // The following assertion checks crbug.com/263329 660 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image2)->getTexture()); 661 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image1)->getTexture()); 662 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image2)->getTexture()); 663 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image1)->getTexture()); 664 REPORTER_ASSERT(reporter, as_IB(image2)->getTexture() != as_IB(image1)->getTexture()); 665 } 666 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCRBug263329_Gpu, reporter, context) { 667 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 668 SkAutoTUnref<SkSurface> surface1(surface_func(context, kPremul_SkAlphaType, nullptr)); 669 SkAutoTUnref<SkSurface> surface2(surface_func(context, kPremul_SkAlphaType, nullptr)); 670 test_crbug263329(reporter, surface1, surface2); 671 } 672 } 673 #endif 674 675 DEF_TEST(SurfaceGetTexture, reporter) { 676 SkAutoTUnref<SkSurface> surface(create_surface()); 677 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 678 REPORTER_ASSERT(reporter, as_IB(image)->getTexture() == nullptr); 679 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 680 REPORTER_ASSERT(reporter, as_IB(image)->getTexture() == nullptr); 681 } 682 #if SK_SUPPORT_GPU 683 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceGetTexture_Gpu, reporter, context) { 684 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 685 SkAutoTUnref<SkSurface> surface(surface_func(context, kPremul_SkAlphaType, nullptr)); 686 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 687 GrTexture* texture = as_IB(image)->getTexture(); 688 REPORTER_ASSERT(reporter, texture); 689 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle()); 690 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 691 REPORTER_ASSERT(reporter, as_IB(image)->getTexture() == texture); 692 } 693 } 694 #endif 695 696 #if SK_SUPPORT_GPU 697 #include "GrGpuResourcePriv.h" 698 #include "SkGpuDevice.h" 699 #include "SkImage_Gpu.h" 700 #include "SkSurface_Gpu.h" 701 702 static SkBudgeted is_budgeted(SkSurface* surf) { 703 return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted(); 704 } 705 706 static SkBudgeted is_budgeted(SkImage* image) { 707 return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted(); 708 } 709 710 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBudget, reporter, context) { 711 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8); 712 for (auto sbudgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) { 713 for (auto ibudgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) { 714 SkAutoTUnref<SkSurface> 715 surface(SkSurface::NewRenderTarget(context, sbudgeted, info, 0)); 716 SkASSERT(surface); 717 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface)); 718 719 SkAutoTUnref<SkImage> image(surface->newImageSnapshot(ibudgeted)); 720 721 // Initially the image shares a texture with the surface, and the surface decides 722 // whether it is budgeted or not. 723 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface)); 724 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image)); 725 726 // Now trigger copy-on-write 727 surface->getCanvas()->clear(SK_ColorBLUE); 728 729 // They don't share a texture anymore. They should each have made their own budget 730 // decision. 731 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface)); 732 REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image)); 733 } 734 } 735 } 736 #endif 737 738 static void test_no_canvas1(skiatest::Reporter* reporter, 739 SkSurface* surface, 740 SkSurface::ContentChangeMode mode) { 741 // Test passes by not asserting 742 surface->notifyContentWillChange(mode); 743 SkDEBUGCODE(surface->validate();) 744 } 745 static void test_no_canvas2(skiatest::Reporter* reporter, 746 SkSurface* surface, 747 SkSurface::ContentChangeMode mode) { 748 // Verifies the robustness of SkSurface for handling use cases where calls 749 // are made before a canvas is created. 750 SkImage* image1 = surface->newImageSnapshot(); 751 SkAutoTUnref<SkImage> aur_image1(image1); 752 SkDEBUGCODE(image1->validate();) 753 SkDEBUGCODE(surface->validate();) 754 surface->notifyContentWillChange(mode); 755 SkDEBUGCODE(image1->validate();) 756 SkDEBUGCODE(surface->validate();) 757 SkImage* image2 = surface->newImageSnapshot(); 758 SkAutoTUnref<SkImage> aur_image2(image2); 759 SkDEBUGCODE(image2->validate();) 760 SkDEBUGCODE(surface->validate();) 761 REPORTER_ASSERT(reporter, image1 != image2); 762 } 763 DEF_TEST(SurfaceNoCanvas, reporter) { 764 SkSurface::ContentChangeMode modes[] = 765 { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode}; 766 for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) { 767 for (auto& mode : modes) { 768 SkAutoTUnref<SkSurface> surface(create_surface()); 769 test_func(reporter, surface, mode); 770 } 771 } 772 } 773 #if SK_SUPPORT_GPU 774 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceNoCanvas_Gpu, reporter, context) { 775 SkSurface::ContentChangeMode modes[] = 776 { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode}; 777 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 778 for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) { 779 for (auto& mode : modes) { 780 SkAutoTUnref<SkSurface> surface( 781 surface_func(context, kPremul_SkAlphaType, nullptr)); 782 test_func(reporter, surface, mode); 783 } 784 } 785 } 786 } 787 #endif 788 789 static void check_rowbytes_remain_consistent(SkSurface* surface, skiatest::Reporter* reporter) { 790 SkImageInfo info; 791 size_t rowBytes; 792 REPORTER_ASSERT(reporter, surface->peekPixels(&info, &rowBytes)); 793 794 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 795 SkImageInfo im_info; 796 size_t im_rowbytes; 797 REPORTER_ASSERT(reporter, image->peekPixels(&im_info, &im_rowbytes)); 798 799 REPORTER_ASSERT(reporter, rowBytes == im_rowbytes); 800 801 // trigger a copy-on-write 802 surface->getCanvas()->drawPaint(SkPaint()); 803 SkAutoTUnref<SkImage> image2(surface->newImageSnapshot()); 804 REPORTER_ASSERT(reporter, image->uniqueID() != image2->uniqueID()); 805 806 SkImageInfo im_info2; 807 size_t im_rowbytes2; 808 REPORTER_ASSERT(reporter, image2->peekPixels(&im_info2, &im_rowbytes2)); 809 810 REPORTER_ASSERT(reporter, im_rowbytes2 == im_rowbytes); 811 } 812 813 DEF_TEST(surface_rowbytes, reporter) { 814 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 815 816 SkAutoTUnref<SkSurface> surf0(SkSurface::NewRaster(info)); 817 check_rowbytes_remain_consistent(surf0, reporter); 818 819 // specify a larger rowbytes 820 SkAutoTUnref<SkSurface> surf1(SkSurface::NewRaster(info, 500, nullptr)); 821 check_rowbytes_remain_consistent(surf1, reporter); 822 823 // Try some illegal rowByte values 824 SkSurface* s = SkSurface::NewRaster(info, 396, nullptr); // needs to be at least 400 825 REPORTER_ASSERT(reporter, nullptr == s); 826 s = SkSurface::NewRaster(info, 1 << 30, nullptr); // allocation to large 827 REPORTER_ASSERT(reporter, nullptr == s); 828 } 829 830 #if SK_SUPPORT_GPU 831 832 void test_surface_clear(skiatest::Reporter* reporter, SkSurface* surfacePtr, 833 std::function<GrSurface*(SkSurface*)> grSurfaceGetter, 834 uint32_t expectedValue) { 835 SkAutoTUnref<SkSurface> surface(surfacePtr); 836 if (!surface) { 837 ERRORF(reporter, "Could not create GPU SkSurface."); 838 return; 839 } 840 int w = surface->width(); 841 int h = surface->height(); 842 SkAutoTDeleteArray<uint32_t> pixels(new uint32_t[w * h]); 843 memset(pixels.get(), ~expectedValue, sizeof(uint32_t) * w * h); 844 845 SkAutoTUnref<GrSurface> grSurface(SkSafeRef(grSurfaceGetter(surface))); 846 if (!grSurface) { 847 ERRORF(reporter, "Could access render target of GPU SkSurface."); 848 return; 849 } 850 SkASSERT(surface->unique()); 851 surface.reset(); 852 grSurface->readPixels(0, 0, w, h, kRGBA_8888_GrPixelConfig, pixels.get()); 853 for (int y = 0; y < h; ++y) { 854 for (int x = 0; x < w; ++x) { 855 uint32_t pixel = pixels.get()[y * w + x]; 856 if (pixel != expectedValue) { 857 SkString msg; 858 if (expectedValue) { 859 msg = "SkSurface should have left render target unmodified"; 860 } else { 861 msg = "SkSurface should have cleared the render target"; 862 } 863 ERRORF(reporter, 864 "%s but read 0x%08x (instead of 0x%08x) at %x,%d", msg.c_str(), pixel, 865 expectedValue, x, y); 866 return; 867 } 868 } 869 } 870 } 871 872 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceClear_Gpu, reporter, context) { 873 std::function<GrSurface*(SkSurface*)> grSurfaceGetters[] = { 874 [] (SkSurface* s){ return s->getCanvas()->internal_private_accessTopLayerRenderTarget(); }, 875 [] (SkSurface* s){ 876 SkBaseDevice* d = 877 s->getCanvas()->getDevice_just_for_deprecated_compatibility_testing(); 878 return d->accessRenderTarget(); }, 879 [] (SkSurface* s){ SkAutoTUnref<SkImage> i(s->newImageSnapshot()); 880 return i->getTexture(); }, 881 [] (SkSurface* s){ SkAutoTUnref<SkImage> i(s->newImageSnapshot()); 882 return as_IB(i)->peekTexture(); }, 883 }; 884 for (auto grSurfaceGetter : grSurfaceGetters) { 885 for (auto& surface_func : {&create_gpu_surface, &create_gpu_scratch_surface}) { 886 SkSurface* surface = surface_func(context, kPremul_SkAlphaType, nullptr); 887 test_surface_clear(reporter, surface, grSurfaceGetter, 0x0); 888 } 889 // Wrapped RTs are *not* supposed to clear (to allow client to partially update a surface). 890 static const int kWidth = 10; 891 static const int kHeight = 10; 892 SkAutoTDeleteArray<uint32_t> pixels(new uint32_t[kWidth * kHeight]); 893 memset(pixels.get(), 0xAB, sizeof(uint32_t) * kWidth * kHeight); 894 895 GrBackendObject textureObject = 896 context->getGpu()->createTestingOnlyBackendTexture(pixels.get(), kWidth, kHeight, 897 kRGBA_8888_GrPixelConfig); 898 899 GrBackendTextureDesc desc; 900 desc.fConfig = kRGBA_8888_GrPixelConfig; 901 desc.fWidth = kWidth; 902 desc.fHeight = kHeight; 903 desc.fFlags = kRenderTarget_GrBackendTextureFlag; 904 desc.fTextureHandle = textureObject; 905 906 SkSurface* surface = SkSurface::NewFromBackendTexture(context, desc, nullptr); 907 test_surface_clear(reporter, surface, grSurfaceGetter, 0xABABABAB); 908 context->getGpu()->deleteTestingOnlyBackendTexture(textureObject); 909 } 910 } 911 #endif 912