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 "SkOverdrawCanvas.h" 14 #include "SkPath.h" 15 #include "SkRegion.h" 16 #include "SkRRect.h" 17 #include "SkSurface.h" 18 #include "SkUtils.h" 19 #include "Test.h" 20 21 #if SK_SUPPORT_GPU 22 #include <vector> 23 #include "GrContext.h" 24 #include "GrContextPriv.h" 25 #include "GrGpu.h" 26 #include "GrGpuResourcePriv.h" 27 #include "GrRenderTargetContext.h" 28 #include "GrResourceProvider.h" 29 #include "GrTest.h" 30 #include "SkGpuDevice.h" 31 #include "SkImage_Gpu.h" 32 #include "SkSurface_Gpu.h" 33 #endif 34 35 #include "sk_tool_utils.h" 36 37 #include <initializer_list> 38 39 static void release_direct_surface_storage(void* pixels, void* context) { 40 SkASSERT(pixels == context); 41 sk_free(pixels); 42 } 43 static sk_sp<SkSurface> create_surface(SkAlphaType at = kPremul_SkAlphaType, 44 SkImageInfo* requestedInfo = nullptr) { 45 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at); 46 if (requestedInfo) { 47 *requestedInfo = info; 48 } 49 return SkSurface::MakeRaster(info); 50 } 51 static sk_sp<SkSurface> create_direct_surface(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 const size_t rowBytes = info.minRowBytes(); 58 void* storage = sk_malloc_throw(info.computeByteSize(rowBytes)); 59 return SkSurface::MakeRasterDirectReleaseProc(info, storage, rowBytes, 60 release_direct_surface_storage, 61 storage); 62 } 63 #if SK_SUPPORT_GPU 64 static sk_sp<SkSurface> create_gpu_surface(GrContext* context, SkAlphaType at = kPremul_SkAlphaType, 65 SkImageInfo* requestedInfo = nullptr) { 66 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at); 67 if (requestedInfo) { 68 *requestedInfo = info; 69 } 70 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info); 71 } 72 static sk_sp<SkSurface> create_gpu_scratch_surface(GrContext* context, 73 SkAlphaType at = kPremul_SkAlphaType, 74 SkImageInfo* requestedInfo = nullptr) { 75 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at); 76 if (requestedInfo) { 77 *requestedInfo = info; 78 } 79 return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info); 80 } 81 #endif 82 83 DEF_TEST(SurfaceEmpty, reporter) { 84 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 85 REPORTER_ASSERT(reporter, nullptr == SkSurface::MakeRaster(info)); 86 REPORTER_ASSERT(reporter, nullptr == SkSurface::MakeRasterDirect(info, nullptr, 0)); 87 88 } 89 #if SK_SUPPORT_GPU 90 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceEmpty_Gpu, reporter, ctxInfo) { 91 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 92 REPORTER_ASSERT(reporter, nullptr == 93 SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo, info)); 94 } 95 #endif 96 97 #if SK_SUPPORT_GPU 98 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsSurface, reporter, ctxInfo) { 99 for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) { 100 static constexpr int kSize = 10; 101 102 SkColorType colorType = static_cast<SkColorType>(ct); 103 auto info = SkImageInfo::Make(kSize, kSize, colorType, kOpaque_SkAlphaType, nullptr); 104 bool can = ctxInfo.grContext()->colorTypeSupportedAsSurface(colorType); 105 auto surf = SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes, info, 1, 106 nullptr); 107 REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d", 108 colorType, can, SkToBool(surf)); 109 110 auto* gpu = ctxInfo.grContext()->contextPriv().getGpu(); 111 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 112 nullptr, kSize, kSize, colorType, true, GrMipMapped::kNo); 113 surf = SkSurface::MakeFromBackendTexture(ctxInfo.grContext(), backendTex, 114 kTopLeft_GrSurfaceOrigin, 0, colorType, nullptr, 115 nullptr); 116 REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d", 117 colorType, can, SkToBool(surf)); 118 119 surf = SkSurface::MakeFromBackendTextureAsRenderTarget(ctxInfo.grContext(), backendTex, 120 kTopLeft_GrSurfaceOrigin, 1, 121 colorType, nullptr, nullptr); 122 REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d", 123 colorType, can, SkToBool(surf)); 124 125 surf.reset(); 126 ctxInfo.grContext()->flush(); 127 if (backendTex.isValid()) { 128 gpu->deleteTestingOnlyBackendTexture(&backendTex); 129 } 130 131 static constexpr int kSampleCnt = 2; 132 133 can = ctxInfo.grContext()->maxSurfaceSampleCountForColorType(colorType) >= kSampleCnt; 134 surf = SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes, info, kSampleCnt, 135 nullptr); 136 REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d", 137 colorType, can, SkToBool(surf)); 138 139 backendTex = gpu->createTestingOnlyBackendTexture(nullptr, kSize, kSize, colorType, true, 140 GrMipMapped::kNo); 141 surf = SkSurface::MakeFromBackendTexture(ctxInfo.grContext(), backendTex, 142 kTopLeft_GrSurfaceOrigin, kSampleCnt, colorType, 143 nullptr, nullptr); 144 REPORTER_ASSERT(reporter, can == SkToBool(surf), 145 "colorTypeSupportedAsSurface:%d, surf:%d, ct:%d", can, SkToBool(surf), 146 colorType); 147 // Ensure that the sample count stored on the resulting SkSurface is a valid value. 148 if (surf) { 149 auto* rtc = ((SkSurface_Gpu*)(surf.get()))->getDevice()->accessRenderTargetContext(); 150 int storedCnt = rtc->numStencilSamples(); 151 int allowedCnt = ctxInfo.grContext()->caps()->getSampleCount( 152 storedCnt, rtc->asSurfaceProxy()->config()); 153 REPORTER_ASSERT(reporter, storedCnt == allowedCnt, 154 "Should store an allowed sample count (%d vs %d)", allowedCnt, 155 storedCnt); 156 } 157 158 surf = SkSurface::MakeFromBackendTextureAsRenderTarget(ctxInfo.grContext(), backendTex, 159 kTopLeft_GrSurfaceOrigin, kSampleCnt, 160 colorType, nullptr, nullptr); 161 REPORTER_ASSERT(reporter, can == SkToBool(surf), 162 "colorTypeSupportedAsSurface:%d, surf:%d, ct:%d", can, SkToBool(surf), 163 colorType); 164 if (surf) { 165 auto* rtc = ((SkSurface_Gpu*)(surf.get()))->getDevice()->accessRenderTargetContext(); 166 int storedCnt = rtc->numStencilSamples(); 167 int allowedCnt = ctxInfo.grContext()->caps()->getSampleCount( 168 storedCnt, rtc->asSurfaceProxy()->config()); 169 REPORTER_ASSERT(reporter, storedCnt == allowedCnt, 170 "Should store an allowed sample count (%d vs %d)", allowedCnt, 171 storedCnt); 172 } 173 174 surf.reset(); 175 ctxInfo.grContext()->flush(); 176 if (backendTex.isValid()) { 177 gpu->deleteTestingOnlyBackendTexture(&backendTex); 178 } 179 } 180 } 181 182 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_maxSurfaceSamplesForColorType, reporter, ctxInfo) { 183 for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) { 184 static constexpr int kSize = 10; 185 186 SkColorType colorType = static_cast<SkColorType>(ct); 187 int max = ctxInfo.grContext()->maxSurfaceSampleCountForColorType(colorType); 188 if (!max) { 189 continue; 190 } 191 auto* gpu = ctxInfo.grContext()->contextPriv().getGpu(); 192 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 193 nullptr, kSize, kSize, colorType, true, GrMipMapped::kNo); 194 195 auto info = SkImageInfo::Make(kSize, kSize, colorType, kOpaque_SkAlphaType, nullptr); 196 auto surf = SkSurface::MakeFromBackendTexture(ctxInfo.grContext(), backendTex, 197 kTopLeft_GrSurfaceOrigin, max, 198 colorType, nullptr, nullptr); 199 REPORTER_ASSERT(reporter, surf); 200 if (!surf) { 201 continue; 202 } 203 int sampleCnt = ((SkSurface_Gpu*)(surf.get())) 204 ->getDevice() 205 ->accessRenderTargetContext() 206 ->numStencilSamples(); 207 REPORTER_ASSERT(reporter, sampleCnt == max, "Exected: %d, actual: %d", max, sampleCnt); 208 } 209 } 210 #endif 211 212 static void test_canvas_peek(skiatest::Reporter* reporter, 213 sk_sp<SkSurface>& surface, 214 const SkImageInfo& requestInfo, 215 bool expectPeekSuccess) { 216 const SkColor color = SK_ColorRED; 217 const SkPMColor pmcolor = SkPreMultiplyColor(color); 218 surface->getCanvas()->clear(color); 219 220 SkPixmap pmap; 221 bool success = surface->getCanvas()->peekPixels(&pmap); 222 REPORTER_ASSERT(reporter, expectPeekSuccess == success); 223 224 SkPixmap pmap2; 225 const void* addr2 = surface->peekPixels(&pmap2) ? pmap2.addr() : nullptr; 226 227 if (success) { 228 REPORTER_ASSERT(reporter, requestInfo == pmap.info()); 229 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= pmap.rowBytes()); 230 REPORTER_ASSERT(reporter, pmcolor == *pmap.addr32()); 231 232 REPORTER_ASSERT(reporter, pmap.addr() == pmap2.addr()); 233 REPORTER_ASSERT(reporter, pmap.info() == pmap2.info()); 234 REPORTER_ASSERT(reporter, pmap.rowBytes() == pmap2.rowBytes()); 235 } else { 236 REPORTER_ASSERT(reporter, nullptr == addr2); 237 } 238 } 239 DEF_TEST(SurfaceCanvasPeek, reporter) { 240 for (auto& surface_func : { &create_surface, &create_direct_surface }) { 241 SkImageInfo requestInfo; 242 auto surface(surface_func(kPremul_SkAlphaType, &requestInfo)); 243 test_canvas_peek(reporter, surface, requestInfo, true); 244 } 245 } 246 #if SK_SUPPORT_GPU 247 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCanvasPeek_Gpu, reporter, ctxInfo) { 248 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 249 SkImageInfo requestInfo; 250 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, &requestInfo)); 251 test_canvas_peek(reporter, surface, requestInfo, false); 252 } 253 } 254 #endif 255 256 static void test_snapshot_alphatype(skiatest::Reporter* reporter, const sk_sp<SkSurface>& surface, 257 SkAlphaType expectedAlphaType) { 258 REPORTER_ASSERT(reporter, surface); 259 if (surface) { 260 sk_sp<SkImage> image(surface->makeImageSnapshot()); 261 REPORTER_ASSERT(reporter, image); 262 if (image) { 263 REPORTER_ASSERT(reporter, image->alphaType() == expectedAlphaType); 264 } 265 } 266 } 267 DEF_TEST(SurfaceSnapshotAlphaType, reporter) { 268 for (auto& surface_func : { &create_surface, &create_direct_surface }) { 269 for (auto& at: { kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType }) { 270 auto surface(surface_func(at, nullptr)); 271 test_snapshot_alphatype(reporter, surface, at); 272 } 273 } 274 } 275 #if SK_SUPPORT_GPU 276 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceSnapshotAlphaType_Gpu, reporter, ctxInfo) { 277 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 278 // GPU doesn't support creating unpremul surfaces, so only test opaque + premul 279 for (auto& at : { kOpaque_SkAlphaType, kPremul_SkAlphaType }) { 280 auto surface(surface_func(ctxInfo.grContext(), at, nullptr)); 281 test_snapshot_alphatype(reporter, surface, at); 282 } 283 } 284 } 285 #endif 286 287 static GrBackendObject get_surface_backend_texture_handle( 288 SkSurface* s, SkSurface::BackendHandleAccess a) { 289 return s->getTextureHandle(a); 290 } 291 static GrBackendObject get_surface_backend_render_target_handle( 292 SkSurface* s, SkSurface::BackendHandleAccess a) { 293 GrBackendObject result; 294 if (!s->getRenderTargetHandle(&result, a)) { 295 return 0; 296 } 297 return result; 298 } 299 300 static void test_backend_handle_access_copy_on_write( 301 skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess mode, 302 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) { 303 GrBackendObject obj1 = func(surface, mode); 304 sk_sp<SkImage> snap1(surface->makeImageSnapshot()); 305 306 GrBackendObject obj2 = func(surface, mode); 307 sk_sp<SkImage> snap2(surface->makeImageSnapshot()); 308 309 // If the access mode triggers CoW, then the backend objects should reflect it. 310 REPORTER_ASSERT(reporter, (obj1 == obj2) == (snap1 == snap2)); 311 } 312 DEF_TEST(SurfaceBackendHandleAccessCopyOnWrite, reporter) { 313 const SkSurface::BackendHandleAccess accessModes[] = { 314 SkSurface::kFlushRead_BackendHandleAccess, 315 SkSurface::kFlushWrite_BackendHandleAccess, 316 SkSurface::kDiscardWrite_BackendHandleAccess, 317 }; 318 for (auto& handle_access_func : 319 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) { 320 for (auto& accessMode : accessModes) { 321 auto surface(create_surface()); 322 test_backend_handle_access_copy_on_write(reporter, surface.get(), accessMode, 323 handle_access_func); 324 } 325 } 326 } 327 #if SK_SUPPORT_GPU 328 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessCopyOnWrite_Gpu, reporter, ctxInfo) { 329 const SkSurface::BackendHandleAccess accessModes[] = { 330 SkSurface::kFlushRead_BackendHandleAccess, 331 SkSurface::kFlushWrite_BackendHandleAccess, 332 SkSurface::kDiscardWrite_BackendHandleAccess, 333 }; 334 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 335 for (auto& handle_access_func : 336 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) { 337 for (auto& accessMode : accessModes) { 338 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 339 test_backend_handle_access_copy_on_write(reporter, surface.get(), accessMode, 340 handle_access_func); 341 } 342 } 343 } 344 } 345 #endif 346 347 #if SK_SUPPORT_GPU 348 349 static void test_backend_handle_unique_id( 350 skiatest::Reporter* reporter, SkSurface* surface, 351 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) { 352 sk_sp<SkImage> image0(surface->makeImageSnapshot()); 353 GrBackendObject obj = func(surface, SkSurface::kFlushRead_BackendHandleAccess); 354 REPORTER_ASSERT(reporter, obj != 0); 355 sk_sp<SkImage> image1(surface->makeImageSnapshot()); 356 // just read access should not affect the snapshot 357 REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID()); 358 359 obj = func(surface, SkSurface::kFlushWrite_BackendHandleAccess); 360 REPORTER_ASSERT(reporter, obj != 0); 361 sk_sp<SkImage> image2(surface->makeImageSnapshot()); 362 // expect a new image, since we claimed we would write 363 REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID()); 364 365 obj = func(surface, SkSurface::kDiscardWrite_BackendHandleAccess); 366 REPORTER_ASSERT(reporter, obj != 0); 367 sk_sp<SkImage> image3(surface->makeImageSnapshot()); 368 // expect a new(er) image, since we claimed we would write 369 REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID()); 370 REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID()); 371 } 372 // No CPU test. 373 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessIDs_Gpu, reporter, ctxInfo) { 374 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 375 for (auto& test_func : { &test_backend_handle_unique_id }) { 376 for (auto& handle_access_func : 377 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle}) { 378 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 379 test_func(reporter, surface.get(), handle_access_func); 380 } 381 } 382 } 383 } 384 #endif 385 386 // Verify that the right canvas commands trigger a copy on write. 387 static void test_copy_on_write(skiatest::Reporter* reporter, SkSurface* surface) { 388 SkCanvas* canvas = surface->getCanvas(); 389 390 const SkRect testRect = 391 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 392 SkIntToScalar(4), SkIntToScalar(5)); 393 SkPath testPath; 394 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 395 SkIntToScalar(2), SkIntToScalar(1))); 396 397 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1); 398 399 SkRegion testRegion; 400 testRegion.setRect(testIRect); 401 402 403 const SkColor testColor = 0x01020304; 404 const SkPaint testPaint; 405 const SkPoint testPoints[3] = { 406 {SkIntToScalar(0), SkIntToScalar(0)}, 407 {SkIntToScalar(2), SkIntToScalar(1)}, 408 {SkIntToScalar(0), SkIntToScalar(2)} 409 }; 410 const size_t testPointCount = 3; 411 412 SkBitmap testBitmap; 413 testBitmap.allocN32Pixels(10, 10); 414 testBitmap.eraseColor(0); 415 416 SkRRect testRRect; 417 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1); 418 419 SkString testText("Hello World"); 420 const SkPoint testPoints2[] = { 421 { SkIntToScalar(0), SkIntToScalar(1) }, 422 { SkIntToScalar(1), SkIntToScalar(1) }, 423 { SkIntToScalar(2), SkIntToScalar(1) }, 424 { SkIntToScalar(3), SkIntToScalar(1) }, 425 { SkIntToScalar(4), SkIntToScalar(1) }, 426 { SkIntToScalar(5), SkIntToScalar(1) }, 427 { SkIntToScalar(6), SkIntToScalar(1) }, 428 { SkIntToScalar(7), SkIntToScalar(1) }, 429 { SkIntToScalar(8), SkIntToScalar(1) }, 430 { SkIntToScalar(9), SkIntToScalar(1) }, 431 { SkIntToScalar(10), SkIntToScalar(1) }, 432 }; 433 434 #define EXPECT_COPY_ON_WRITE(command) \ 435 { \ 436 sk_sp<SkImage> imageBefore = surface->makeImageSnapshot(); \ 437 sk_sp<SkImage> aur_before(imageBefore); \ 438 canvas-> command ; \ 439 sk_sp<SkImage> imageAfter = surface->makeImageSnapshot(); \ 440 sk_sp<SkImage> aur_after(imageAfter); \ 441 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \ 442 } 443 444 EXPECT_COPY_ON_WRITE(clear(testColor)) 445 EXPECT_COPY_ON_WRITE(drawPaint(testPaint)) 446 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \ 447 testPaint)) 448 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint)) 449 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint)) 450 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint)) 451 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint)) 452 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0)) 453 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, testRect, nullptr)) 454 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, nullptr)) 455 EXPECT_COPY_ON_WRITE(drawString(testText, 0, 1, testPaint)) 456 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \ 457 testPaint)) 458 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, nullptr, \ 459 testPaint)) 460 } 461 DEF_TEST(SurfaceCopyOnWrite, reporter) { 462 test_copy_on_write(reporter, create_surface().get()); 463 } 464 #if SK_SUPPORT_GPU 465 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCopyOnWrite_Gpu, reporter, ctxInfo) { 466 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 467 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 468 test_copy_on_write(reporter, surface.get()); 469 } 470 } 471 #endif 472 473 static void test_writable_after_snapshot_release(skiatest::Reporter* reporter, 474 SkSurface* surface) { 475 // This test succeeds by not triggering an assertion. 476 // The test verifies that the surface remains writable (usable) after 477 // acquiring and releasing a snapshot without triggering a copy on write. 478 SkCanvas* canvas = surface->getCanvas(); 479 canvas->clear(1); 480 surface->makeImageSnapshot(); // Create and destroy SkImage 481 canvas->clear(2); // Must not assert internally 482 } 483 DEF_TEST(SurfaceWriteableAfterSnapshotRelease, reporter) { 484 test_writable_after_snapshot_release(reporter, create_surface().get()); 485 } 486 #if SK_SUPPORT_GPU 487 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceWriteableAfterSnapshotRelease_Gpu, reporter, ctxInfo) { 488 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 489 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 490 test_writable_after_snapshot_release(reporter, surface.get()); 491 } 492 } 493 #endif 494 495 #if SK_SUPPORT_GPU 496 static void test_crbug263329(skiatest::Reporter* reporter, 497 SkSurface* surface1, 498 SkSurface* surface2) { 499 // This is a regression test for crbug.com/263329 500 // Bug was caused by onCopyOnWrite releasing the old surface texture 501 // back to the scratch texture pool even though the texture is used 502 // by and active SkImage_Gpu. 503 SkCanvas* canvas1 = surface1->getCanvas(); 504 SkCanvas* canvas2 = surface2->getCanvas(); 505 canvas1->clear(1); 506 sk_sp<SkImage> image1(surface1->makeImageSnapshot()); 507 // Trigger copy on write, new backing is a scratch texture 508 canvas1->clear(2); 509 sk_sp<SkImage> image2(surface1->makeImageSnapshot()); 510 // Trigger copy on write, old backing should not be returned to scratch 511 // pool because it is held by image2 512 canvas1->clear(3); 513 514 canvas2->clear(4); 515 sk_sp<SkImage> image3(surface2->makeImageSnapshot()); 516 // Trigger copy on write on surface2. The new backing store should not 517 // be recycling a texture that is held by an existing image. 518 canvas2->clear(5); 519 sk_sp<SkImage> image4(surface2->makeImageSnapshot()); 520 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image3)->getTexture()); 521 // The following assertion checks crbug.com/263329 522 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image2)->getTexture()); 523 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image1)->getTexture()); 524 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image2)->getTexture()); 525 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image1)->getTexture()); 526 REPORTER_ASSERT(reporter, as_IB(image2)->getTexture() != as_IB(image1)->getTexture()); 527 } 528 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCRBug263329_Gpu, reporter, ctxInfo) { 529 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 530 auto surface1(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 531 auto surface2(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 532 test_crbug263329(reporter, surface1.get(), surface2.get()); 533 } 534 } 535 #endif 536 537 DEF_TEST(SurfaceGetTexture, reporter) { 538 auto surface(create_surface()); 539 sk_sp<SkImage> image(surface->makeImageSnapshot()); 540 REPORTER_ASSERT(reporter, !as_IB(image)->isTextureBacked()); 541 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 542 REPORTER_ASSERT(reporter, !as_IB(image)->isTextureBacked()); 543 } 544 #if SK_SUPPORT_GPU 545 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfacepeekTexture_Gpu, reporter, ctxInfo) { 546 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 547 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 548 sk_sp<SkImage> image(surface->makeImageSnapshot()); 549 550 REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked()); 551 GrBackendObject textureHandle = image->getTextureHandle(false); 552 REPORTER_ASSERT(reporter, 0 != textureHandle); 553 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 554 REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked()); 555 REPORTER_ASSERT(reporter, textureHandle == image->getTextureHandle(false)); 556 } 557 } 558 #endif 559 560 #if SK_SUPPORT_GPU 561 562 static SkBudgeted is_budgeted(const sk_sp<SkSurface>& surf) { 563 SkSurface_Gpu* gsurf = (SkSurface_Gpu*)surf.get(); 564 565 GrRenderTargetProxy* proxy = gsurf->getDevice()->accessRenderTargetContext() 566 ->asRenderTargetProxy(); 567 return proxy->isBudgeted(); 568 } 569 570 static SkBudgeted is_budgeted(SkImage* image) { 571 return ((SkImage_Gpu*)image)->peekProxy()->isBudgeted(); 572 } 573 574 static SkBudgeted is_budgeted(const sk_sp<SkImage> image) { 575 return is_budgeted(image.get()); 576 } 577 578 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBudget, reporter, ctxInfo) { 579 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8); 580 for (auto budgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) { 581 auto surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), budgeted, info)); 582 SkASSERT(surface); 583 REPORTER_ASSERT(reporter, budgeted == is_budgeted(surface)); 584 585 sk_sp<SkImage> image(surface->makeImageSnapshot()); 586 587 // Initially the image shares a texture with the surface, and the 588 // the budgets should always match. 589 REPORTER_ASSERT(reporter, budgeted == is_budgeted(surface)); 590 REPORTER_ASSERT(reporter, budgeted == is_budgeted(image)); 591 592 // Now trigger copy-on-write 593 surface->getCanvas()->clear(SK_ColorBLUE); 594 595 // They don't share a texture anymore but the budgets should still match. 596 REPORTER_ASSERT(reporter, budgeted == is_budgeted(surface)); 597 REPORTER_ASSERT(reporter, budgeted == is_budgeted(image)); 598 } 599 } 600 #endif 601 602 static void test_no_canvas1(skiatest::Reporter* reporter, 603 SkSurface* surface, 604 SkSurface::ContentChangeMode mode) { 605 // Test passes by not asserting 606 surface->notifyContentWillChange(mode); 607 SkDEBUGCODE(surface->validate();) 608 } 609 static void test_no_canvas2(skiatest::Reporter* reporter, 610 SkSurface* surface, 611 SkSurface::ContentChangeMode mode) { 612 // Verifies the robustness of SkSurface for handling use cases where calls 613 // are made before a canvas is created. 614 sk_sp<SkImage> image1 = surface->makeImageSnapshot(); 615 sk_sp<SkImage> aur_image1(image1); 616 SkDEBUGCODE(image1->validate();) 617 SkDEBUGCODE(surface->validate();) 618 surface->notifyContentWillChange(mode); 619 SkDEBUGCODE(image1->validate();) 620 SkDEBUGCODE(surface->validate();) 621 sk_sp<SkImage> image2 = surface->makeImageSnapshot(); 622 sk_sp<SkImage> aur_image2(image2); 623 SkDEBUGCODE(image2->validate();) 624 SkDEBUGCODE(surface->validate();) 625 REPORTER_ASSERT(reporter, image1 != image2); 626 } 627 DEF_TEST(SurfaceNoCanvas, reporter) { 628 SkSurface::ContentChangeMode modes[] = 629 { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode}; 630 for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) { 631 for (auto& mode : modes) { 632 test_func(reporter, create_surface().get(), mode); 633 } 634 } 635 } 636 #if SK_SUPPORT_GPU 637 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceNoCanvas_Gpu, reporter, ctxInfo) { 638 SkSurface::ContentChangeMode modes[] = 639 { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode}; 640 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) { 641 for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) { 642 for (auto& mode : modes) { 643 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr)); 644 test_func(reporter, surface.get(), mode); 645 } 646 } 647 } 648 } 649 #endif 650 651 static void check_rowbytes_remain_consistent(SkSurface* surface, skiatest::Reporter* reporter) { 652 SkPixmap surfacePM; 653 REPORTER_ASSERT(reporter, surface->peekPixels(&surfacePM)); 654 655 sk_sp<SkImage> image(surface->makeImageSnapshot()); 656 SkPixmap pm; 657 REPORTER_ASSERT(reporter, image->peekPixels(&pm)); 658 659 REPORTER_ASSERT(reporter, surfacePM.rowBytes() == pm.rowBytes()); 660 661 // trigger a copy-on-write 662 surface->getCanvas()->drawPaint(SkPaint()); 663 sk_sp<SkImage> image2(surface->makeImageSnapshot()); 664 REPORTER_ASSERT(reporter, image->uniqueID() != image2->uniqueID()); 665 666 SkPixmap pm2; 667 REPORTER_ASSERT(reporter, image2->peekPixels(&pm2)); 668 REPORTER_ASSERT(reporter, pm2.rowBytes() == pm.rowBytes()); 669 } 670 671 DEF_TEST(surface_rowbytes, reporter) { 672 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 673 674 auto surf0(SkSurface::MakeRaster(info)); 675 check_rowbytes_remain_consistent(surf0.get(), reporter); 676 677 // specify a larger rowbytes 678 auto surf1(SkSurface::MakeRaster(info, 500, nullptr)); 679 check_rowbytes_remain_consistent(surf1.get(), reporter); 680 681 // Try some illegal rowByte values 682 auto s = SkSurface::MakeRaster(info, 396, nullptr); // needs to be at least 400 683 REPORTER_ASSERT(reporter, nullptr == s); 684 s = SkSurface::MakeRaster(info, std::numeric_limits<size_t>::max(), nullptr); 685 REPORTER_ASSERT(reporter, nullptr == s); 686 } 687 688 DEF_TEST(surface_raster_zeroinitialized, reporter) { 689 sk_sp<SkSurface> s(SkSurface::MakeRasterN32Premul(100, 100)); 690 SkPixmap pixmap; 691 REPORTER_ASSERT(reporter, s->peekPixels(&pixmap)); 692 693 for (int i = 0; i < pixmap.info().width(); ++i) { 694 for (int j = 0; j < pixmap.info().height(); ++j) { 695 REPORTER_ASSERT(reporter, *pixmap.addr32(i, j) == 0); 696 } 697 } 698 } 699 700 #if SK_SUPPORT_GPU 701 static sk_sp<SkSurface> create_gpu_surface_backend_texture( 702 GrContext* context, int sampleCnt, uint32_t color, GrBackendTexture* outTexture) { 703 GrGpu* gpu = context->contextPriv().getGpu(); 704 705 const int kWidth = 10; 706 const int kHeight = 10; 707 std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]); 708 sk_memset32(pixels.get(), color, kWidth * kHeight); 709 710 *outTexture = gpu->createTestingOnlyBackendTexture( 711 pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo); 712 713 if (!outTexture->isValid() || !gpu->isTestingOnlyBackendTexture(*outTexture)) { 714 return nullptr; 715 } 716 717 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, *outTexture, 718 kTopLeft_GrSurfaceOrigin, sampleCnt, 719 kRGBA_8888_SkColorType, 720 nullptr, nullptr); 721 if (!surface) { 722 gpu->deleteTestingOnlyBackendTexture(outTexture); 723 return nullptr; 724 } 725 return surface; 726 } 727 728 static sk_sp<SkSurface> create_gpu_surface_backend_texture_as_render_target( 729 GrContext* context, int sampleCnt, uint32_t color, GrBackendTexture* outTexture) { 730 GrGpu* gpu = context->contextPriv().getGpu(); 731 732 const int kWidth = 10; 733 const int kHeight = 10; 734 std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]); 735 sk_memset32(pixels.get(), color, kWidth * kHeight); 736 737 *outTexture = gpu->createTestingOnlyBackendTexture( 738 pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo); 739 740 if (!outTexture->isValid() || !gpu->isTestingOnlyBackendTexture(*outTexture)) { 741 return nullptr; 742 } 743 744 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget( 745 context, *outTexture, kTopLeft_GrSurfaceOrigin, sampleCnt, kRGBA_8888_SkColorType, 746 nullptr, nullptr); 747 748 if (!surface) { 749 gpu->deleteTestingOnlyBackendTexture(outTexture); 750 return nullptr; 751 } 752 return surface; 753 } 754 755 static void test_surface_clear(skiatest::Reporter* reporter, sk_sp<SkSurface> surface, 756 std::function<sk_sp<GrSurfaceContext>(SkSurface*)> grSurfaceGetter, 757 uint32_t expectedValue) { 758 if (!surface) { 759 ERRORF(reporter, "Could not create GPU SkSurface."); 760 return; 761 } 762 int w = surface->width(); 763 int h = surface->height(); 764 std::unique_ptr<uint32_t[]> pixels(new uint32_t[w * h]); 765 sk_memset32(pixels.get(), ~expectedValue, w * h); 766 767 sk_sp<GrSurfaceContext> grSurfaceContext(grSurfaceGetter(surface.get())); 768 if (!grSurfaceContext) { 769 ERRORF(reporter, "Could access render target of GPU SkSurface."); 770 return; 771 } 772 surface.reset(); 773 774 SkImageInfo ii = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 775 grSurfaceContext->readPixels(ii, pixels.get(), 0, 0, 0); 776 for (int y = 0; y < h; ++y) { 777 for (int x = 0; x < w; ++x) { 778 uint32_t pixel = pixels.get()[y * w + x]; 779 if (pixel != expectedValue) { 780 SkString msg; 781 if (expectedValue) { 782 msg = "SkSurface should have left render target unmodified"; 783 } else { 784 msg = "SkSurface should have cleared the render target"; 785 } 786 ERRORF(reporter, 787 "%s but read 0x%08x (instead of 0x%08x) at %x,%d", msg.c_str(), pixel, 788 expectedValue, x, y); 789 return; 790 } 791 } 792 } 793 } 794 795 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceClear_Gpu, reporter, ctxInfo) { 796 GrContext* context = ctxInfo.grContext(); 797 GrGpu* gpu = context->contextPriv().getGpu(); 798 799 std::function<sk_sp<GrSurfaceContext>(SkSurface*)> grSurfaceContextGetters[] = { 800 [] (SkSurface* s){ 801 return sk_ref_sp(s->getCanvas()->internal_private_accessTopLayerRenderTargetContext()); 802 }, 803 [] (SkSurface* s){ 804 sk_sp<SkImage> i(s->makeImageSnapshot()); 805 SkImage_Gpu* gpuImage = (SkImage_Gpu *) as_IB(i); 806 sk_sp<GrTextureProxy> proxy = gpuImage->asTextureProxyRef(); 807 GrContext* context = gpuImage->context(); 808 return context->contextPriv().makeWrappedSurfaceContext(std::move(proxy), 809 gpuImage->refColorSpace()); 810 } 811 }; 812 813 for (auto grSurfaceGetter : grSurfaceContextGetters) { 814 // Test that non-wrapped RTs are created clear. 815 for (auto& surface_func : {&create_gpu_surface, &create_gpu_scratch_surface}) { 816 auto surface = surface_func(context, kPremul_SkAlphaType, nullptr); 817 test_surface_clear(reporter, surface, grSurfaceGetter, 0x0); 818 } 819 // Wrapped RTs are *not* supposed to clear (to allow client to partially update a surface). 820 const uint32_t kOrigColor = 0xABABABAB; 821 for (auto& surfaceFunc : {&create_gpu_surface_backend_texture, 822 &create_gpu_surface_backend_texture_as_render_target}) { 823 GrBackendTexture backendTex; 824 auto surface = surfaceFunc(context, 1, kOrigColor, &backendTex); 825 test_surface_clear(reporter, surface, grSurfaceGetter, kOrigColor); 826 surface.reset(); 827 gpu->deleteTestingOnlyBackendTexture(&backendTex); 828 } 829 } 830 } 831 832 static void test_surface_draw_partially( 833 skiatest::Reporter* reporter, sk_sp<SkSurface> surface, uint32_t origColor) { 834 const int kW = surface->width(); 835 const int kH = surface->height(); 836 SkPaint paint; 837 const SkColor kRectColor = ~origColor | 0xFF000000; 838 paint.setColor(kRectColor); 839 surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2), 840 paint); 841 std::unique_ptr<uint32_t[]> pixels(new uint32_t[kW * kH]); 842 sk_memset32(pixels.get(), ~origColor, kW * kH); 843 // Read back RGBA to avoid format conversions that may not be supported on all platforms. 844 SkImageInfo readInfo = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 845 SkAssertResult(surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0)); 846 bool stop = false; 847 SkPMColor origColorPM = SkPackARGB_as_RGBA((origColor >> 24 & 0xFF), 848 (origColor >> 0 & 0xFF), 849 (origColor >> 8 & 0xFF), 850 (origColor >> 16 & 0xFF)); 851 SkPMColor rectColorPM = SkPackARGB_as_RGBA((kRectColor >> 24 & 0xFF), 852 (kRectColor >> 16 & 0xFF), 853 (kRectColor >> 8 & 0xFF), 854 (kRectColor >> 0 & 0xFF)); 855 for (int y = 0; y < kH/2 && !stop; ++y) { 856 for (int x = 0; x < kW && !stop; ++x) { 857 REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]); 858 if (rectColorPM != pixels[x + y * kW]) { 859 stop = true; 860 } 861 } 862 } 863 stop = false; 864 for (int y = kH/2; y < kH && !stop; ++y) { 865 for (int x = 0; x < kW && !stop; ++x) { 866 REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]); 867 if (origColorPM != pixels[x + y * kW]) { 868 stop = true; 869 } 870 } 871 } 872 } 873 874 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfacePartialDraw_Gpu, reporter, ctxInfo) { 875 GrGpu* gpu = ctxInfo.grContext()->contextPriv().getGpu(); 876 if (!gpu) { 877 return; 878 } 879 static const uint32_t kOrigColor = 0xFFAABBCC; 880 881 for (auto& surfaceFunc : {&create_gpu_surface_backend_texture, 882 &create_gpu_surface_backend_texture_as_render_target}) { 883 // Validate that we can draw to the canvas and that the original texture color is 884 // preserved in pixels that aren't rendered to via the surface. 885 // This works only for non-multisampled case. 886 GrBackendTexture backendTex; 887 auto surface = surfaceFunc(ctxInfo.grContext(), 1, kOrigColor, &backendTex); 888 if (surface) { 889 test_surface_draw_partially(reporter, surface, kOrigColor); 890 surface.reset(); 891 gpu->deleteTestingOnlyBackendTexture(&backendTex); 892 } 893 } 894 } 895 896 897 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceAttachStencil_Gpu, reporter, ctxInfo) { 898 GrGpu* gpu = ctxInfo.grContext()->contextPriv().getGpu(); 899 if (!gpu) { 900 return; 901 } 902 if (gpu->caps()->avoidStencilBuffers()) { 903 return; 904 } 905 static const uint32_t kOrigColor = 0xFFAABBCC; 906 907 auto resourceProvider = ctxInfo.grContext()->contextPriv().resourceProvider(); 908 909 for (auto& surfaceFunc : {&create_gpu_surface_backend_texture, 910 &create_gpu_surface_backend_texture_as_render_target}) { 911 for (int sampleCnt : {1, 4, 8}) { 912 GrBackendTexture backendTex; 913 auto surface = surfaceFunc(ctxInfo.grContext(), sampleCnt, kOrigColor, &backendTex); 914 915 if (!surface && sampleCnt > 1) { 916 // Certain platforms don't support MSAA, skip these. 917 continue; 918 } 919 920 // Validate that we can attach a stencil buffer to an SkSurface created by either of 921 // our surface functions. 922 GrRenderTarget* rt = surface->getCanvas() 923 ->internal_private_accessTopLayerRenderTargetContext()->accessRenderTarget(); 924 REPORTER_ASSERT(reporter, resourceProvider->attachStencilAttachment(rt)); 925 gpu->deleteTestingOnlyBackendTexture(&backendTex); 926 } 927 } 928 } 929 #endif 930 931 static void test_surface_creation_and_snapshot_with_color_space( 932 skiatest::Reporter* reporter, 933 const char* prefix, 934 bool f16Support, 935 bool supports1010102, 936 std::function<sk_sp<SkSurface>(const SkImageInfo&)> surfaceMaker) { 937 938 auto srgbColorSpace = SkColorSpace::MakeSRGB(); 939 const SkMatrix44* srgbMatrix = srgbColorSpace->toXYZD50(); 940 SkASSERT(srgbMatrix); 941 SkColorSpaceTransferFn oddGamma; 942 oddGamma.fA = 1.0f; 943 oddGamma.fB = oddGamma.fC = oddGamma.fD = oddGamma.fE = oddGamma.fF = 0.0f; 944 oddGamma.fG = 4.0f; 945 auto oddColorSpace = SkColorSpace::MakeRGB(oddGamma, *srgbMatrix); 946 auto linearColorSpace = SkColorSpace::MakeSRGBLinear(); 947 948 const struct { 949 SkColorType fColorType; 950 sk_sp<SkColorSpace> fColorSpace; 951 bool fShouldWork; 952 const char* fDescription; 953 } testConfigs[] = { 954 { kN32_SkColorType, nullptr, true, "N32-nullptr" }, 955 { kN32_SkColorType, linearColorSpace, false, "N32-linear" }, 956 { kN32_SkColorType, srgbColorSpace, true, "N32-srgb" }, 957 { kN32_SkColorType, oddColorSpace, false, "N32-odd" }, 958 { kRGBA_F16_SkColorType, nullptr, true, "F16-nullptr" }, 959 { kRGBA_F16_SkColorType, linearColorSpace, true, "F16-linear" }, 960 { kRGBA_F16_SkColorType, srgbColorSpace, false, "F16-srgb" }, 961 { kRGBA_F16_SkColorType, oddColorSpace, false, "F16-odd" }, 962 { kRGB_565_SkColorType, srgbColorSpace, false, "565-srgb" }, 963 { kAlpha_8_SkColorType, srgbColorSpace, false, "A8-srgb" }, 964 { kRGBA_1010102_SkColorType, nullptr, true, "1010102-nullptr" }, 965 }; 966 967 for (auto& testConfig : testConfigs) { 968 SkString fullTestName = SkStringPrintf("%s-%s", prefix, testConfig.fDescription); 969 SkImageInfo info = SkImageInfo::Make(10, 10, testConfig.fColorType, kPremul_SkAlphaType, 970 testConfig.fColorSpace); 971 972 // For some GPU contexts (eg ANGLE), we don't have f16 support, so we should fail to create 973 // any surface of that type: 974 bool shouldWork = testConfig.fShouldWork && 975 (f16Support || kRGBA_F16_SkColorType != testConfig.fColorType) && 976 (supports1010102 || kRGBA_1010102_SkColorType != testConfig.fColorType); 977 978 auto surface(surfaceMaker(info)); 979 REPORTER_ASSERT(reporter, SkToBool(surface) == shouldWork, fullTestName.c_str()); 980 981 if (shouldWork && surface) { 982 sk_sp<SkImage> image(surface->makeImageSnapshot()); 983 REPORTER_ASSERT(reporter, image, testConfig.fDescription); 984 SkColorSpace* imageColorSpace = as_IB(image)->onImageInfo().colorSpace(); 985 REPORTER_ASSERT(reporter, imageColorSpace == testConfig.fColorSpace.get(), 986 fullTestName.c_str()); 987 } 988 } 989 } 990 991 DEF_TEST(SurfaceCreationWithColorSpace, reporter) { 992 auto surfaceMaker = [](const SkImageInfo& info) { 993 return SkSurface::MakeRaster(info); 994 }; 995 996 test_surface_creation_and_snapshot_with_color_space(reporter, "raster", true, true, 997 surfaceMaker); 998 } 999 1000 #if SK_SUPPORT_GPU 1001 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCreationWithColorSpace_Gpu, reporter, ctxInfo) { 1002 GrContext* context = ctxInfo.grContext(); 1003 1004 bool f16Support = context->caps()->isConfigRenderable(kRGBA_half_GrPixelConfig); 1005 bool supports1010102 = context->caps()->isConfigRenderable(kRGBA_1010102_GrPixelConfig); 1006 auto surfaceMaker = [context](const SkImageInfo& info) { 1007 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info); 1008 }; 1009 1010 test_surface_creation_and_snapshot_with_color_space(reporter, "gpu", f16Support, 1011 supports1010102, surfaceMaker); 1012 1013 std::vector<GrBackendTexture> backendTextures; 1014 auto wrappedSurfaceMaker = [ context, &backendTextures ](const SkImageInfo& info) { 1015 GrGpu* gpu = context->contextPriv().getGpu(); 1016 1017 static const int kSize = 10; 1018 GrPixelConfig config = SkImageInfo2GrPixelConfig(info, *context->caps()); 1019 SkASSERT(kUnknown_GrPixelConfig != config); 1020 1021 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 1022 nullptr, kSize, kSize, config, true, GrMipMapped::kNo); 1023 1024 if (!backendTex.isValid() || 1025 !gpu->isTestingOnlyBackendTexture(backendTex)) { 1026 return sk_sp<SkSurface>(nullptr); 1027 } 1028 backendTextures.push_back(backendTex); 1029 1030 return SkSurface::MakeFromBackendTexture(context, backendTex, 1031 kTopLeft_GrSurfaceOrigin, 0, 1032 info.colorType(), 1033 sk_ref_sp(info.colorSpace()), nullptr); 1034 }; 1035 1036 test_surface_creation_and_snapshot_with_color_space(reporter, "wrapped", f16Support, 1037 supports1010102, wrappedSurfaceMaker); 1038 1039 context->flush(); 1040 1041 GrGpu* gpu = context->contextPriv().getGpu(); 1042 for (auto backendTex : backendTextures) { 1043 gpu->deleteTestingOnlyBackendTexture(&backendTex); 1044 } 1045 } 1046 #endif 1047 1048 static void test_overdraw_surface(skiatest::Reporter* r, SkSurface* surface) { 1049 SkOverdrawCanvas canvas(surface->getCanvas()); 1050 canvas.drawPaint(SkPaint()); 1051 sk_sp<SkImage> image = surface->makeImageSnapshot(); 1052 1053 SkBitmap bitmap; 1054 image->asLegacyBitmap(&bitmap); 1055 for (int y = 0; y < 10; y++) { 1056 for (int x = 0; x < 10; x++) { 1057 REPORTER_ASSERT(r, 1 == SkGetPackedA32(*bitmap.getAddr32(x, y))); 1058 } 1059 } 1060 } 1061 1062 DEF_TEST(OverdrawSurface_Raster, r) { 1063 sk_sp<SkSurface> surface = create_surface(); 1064 test_overdraw_surface(r, surface.get()); 1065 } 1066 1067 #if SK_SUPPORT_GPU 1068 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(OverdrawSurface_Gpu, r, ctxInfo) { 1069 GrContext* context = ctxInfo.grContext(); 1070 sk_sp<SkSurface> surface = create_gpu_surface(context); 1071 test_overdraw_surface(r, surface.get()); 1072 } 1073 #endif 1074 1075 DEF_TEST(Surface_null, r) { 1076 REPORTER_ASSERT(r, SkSurface::MakeNull(0, 0) == nullptr); 1077 1078 const int w = 37; 1079 const int h = 1000; 1080 auto surf = SkSurface::MakeNull(w, h); 1081 auto canvas = surf->getCanvas(); 1082 1083 canvas->drawPaint(SkPaint()); // should not crash, but don't expect anything to draw 1084 REPORTER_ASSERT(r, surf->makeImageSnapshot() == nullptr); 1085 } 1086 1087 // assert: if a given imageinfo is valid for a surface, then it must be valid for an image 1088 // (so the snapshot can succeed) 1089 DEF_TEST(surface_image_unity, reporter) { 1090 auto do_test = [reporter](const SkImageInfo& info) { 1091 size_t rowBytes = info.minRowBytes(); 1092 auto surf = SkSurface::MakeRaster(info, rowBytes, nullptr); 1093 if (surf) { 1094 auto img = surf->makeImageSnapshot(); 1095 if (!img && false) { // change to true to document the differences 1096 SkDebugf("image failed: [%08X %08X] %14s %s\n", 1097 info.width(), info.height(), 1098 sk_tool_utils::colortype_name(info.colorType()), 1099 sk_tool_utils::alphatype_name(info.alphaType())); 1100 return; 1101 } 1102 REPORTER_ASSERT(reporter, img != nullptr); 1103 1104 char dummyPixel = 0; // just need a valid address (not a valid size) 1105 SkPixmap pmap = { info, &dummyPixel, rowBytes }; 1106 img = SkImage::MakeFromRaster(pmap, nullptr, nullptr); 1107 REPORTER_ASSERT(reporter, img != nullptr); 1108 } 1109 }; 1110 1111 const int32_t sizes[] = { 0, 1, 1 << 15, 1 << 16, 1 << 18, 1 << 28, 1 << 29, 1 << 30, -1 }; 1112 for (int cti = 0; cti <= kLastEnum_SkColorType; ++cti) { 1113 SkColorType ct = static_cast<SkColorType>(cti); 1114 for (int ati = 0; ati <= kLastEnum_SkAlphaType; ++ati) { 1115 SkAlphaType at = static_cast<SkAlphaType>(ati); 1116 for (int32_t size : sizes) { 1117 // Large allocations tend to make the 32-bit bots run out of virtual address space. 1118 if (sizeof(size_t) == 4 && size > (1<<20)) { 1119 continue; 1120 } 1121 do_test(SkImageInfo::Make(1, size, ct, at)); 1122 do_test(SkImageInfo::Make(size, 1, ct, at)); 1123 } 1124 } 1125 } 1126 } 1127