1 /* 2 * Copyright 2015 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 <initializer_list> 10 #include <vector> 11 12 #include "SkAutoPixmapStorage.h" 13 #include "SkBitmap.h" 14 #include "SkCanvas.h" 15 #include "SkColorSpacePriv.h" 16 #include "SkData.h" 17 #include "SkImageEncoder.h" 18 #include "SkImageGenerator.h" 19 #include "SkImage_Base.h" 20 #include "SkImagePriv.h" 21 #include "SkMakeUnique.h" 22 #include "SkPicture.h" 23 #include "SkPictureRecorder.h" 24 #include "SkRRect.h" 25 #include "SkSerialProcs.h" 26 #include "SkStream.h" 27 #include "SkSurface.h" 28 #include "SkUtils.h" 29 #include "Test.h" 30 31 #include "Resources.h" 32 #include "sk_pixel_iter.h" 33 #include "sk_tool_utils.h" 34 35 #if SK_SUPPORT_GPU 36 #include "GrContextPriv.h" 37 #include "GrGpu.h" 38 #include "GrResourceCache.h" 39 #include "GrTest.h" 40 #include "GrTexture.h" 41 #include "SkGr.h" 42 #endif 43 44 using namespace sk_gpu_test; 45 46 SkImageInfo read_pixels_info(SkImage* image) { 47 if (as_IB(image)->onImageInfo().colorSpace()) { 48 return SkImageInfo::MakeS32(image->width(), image->height(), image->alphaType()); 49 } 50 51 return SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); 52 } 53 54 static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA, 55 SkImage* b) { 56 const int widthA = subsetA ? subsetA->width() : a->width(); 57 const int heightA = subsetA ? subsetA->height() : a->height(); 58 59 REPORTER_ASSERT(reporter, widthA == b->width()); 60 REPORTER_ASSERT(reporter, heightA == b->height()); 61 62 // see https://bug.skia.org/3965 63 //REPORTER_ASSERT(reporter, a->isOpaque() == b->isOpaque()); 64 65 SkAutoPixmapStorage pmapA, pmapB; 66 pmapA.alloc(read_pixels_info(a)); 67 pmapB.alloc(read_pixels_info(b)); 68 69 const int srcX = subsetA ? subsetA->x() : 0; 70 const int srcY = subsetA ? subsetA->y() : 0; 71 72 REPORTER_ASSERT(reporter, a->readPixels(pmapA, srcX, srcY)); 73 REPORTER_ASSERT(reporter, b->readPixels(pmapB, 0, 0)); 74 75 const size_t widthBytes = widthA * 4; 76 for (int y = 0; y < heightA; ++y) { 77 REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes)); 78 } 79 } 80 static void draw_image_test_pattern(SkCanvas* canvas) { 81 canvas->clear(SK_ColorWHITE); 82 SkPaint paint; 83 paint.setColor(SK_ColorBLACK); 84 canvas->drawRect(SkRect::MakeXYWH(5, 5, 10, 10), paint); 85 } 86 static sk_sp<SkImage> create_image() { 87 const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 88 auto surface(SkSurface::MakeRaster(info)); 89 draw_image_test_pattern(surface->getCanvas()); 90 return surface->makeImageSnapshot(); 91 } 92 static sk_sp<SkData> create_image_data(SkImageInfo* info) { 93 *info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 94 const size_t rowBytes = info->minRowBytes(); 95 sk_sp<SkData> data(SkData::MakeUninitialized(rowBytes * info->height())); 96 { 97 SkBitmap bm; 98 bm.installPixels(*info, data->writable_data(), rowBytes); 99 SkCanvas canvas(bm); 100 draw_image_test_pattern(&canvas); 101 } 102 return data; 103 } 104 static sk_sp<SkImage> create_data_image() { 105 SkImageInfo info; 106 sk_sp<SkData> data(create_image_data(&info)); 107 return SkImage::MakeRasterData(info, std::move(data), info.minRowBytes()); 108 } 109 #if SK_SUPPORT_GPU // not gpu-specific but currently only used in GPU tests 110 static sk_sp<SkImage> create_image_large(int maxTextureSize) { 111 const SkImageInfo info = SkImageInfo::MakeN32(maxTextureSize + 1, 32, kOpaque_SkAlphaType); 112 auto surface(SkSurface::MakeRaster(info)); 113 surface->getCanvas()->clear(SK_ColorWHITE); 114 SkPaint paint; 115 paint.setColor(SK_ColorBLACK); 116 surface->getCanvas()->drawRect(SkRect::MakeXYWH(4000, 2, 28000, 30), paint); 117 return surface->makeImageSnapshot(); 118 } 119 static sk_sp<SkImage> create_picture_image() { 120 SkPictureRecorder recorder; 121 SkCanvas* canvas = recorder.beginRecording(10, 10); 122 canvas->clear(SK_ColorCYAN); 123 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(), SkISize::Make(10, 10), 124 nullptr, nullptr, SkImage::BitDepth::kU8, 125 SkColorSpace::MakeSRGB()); 126 }; 127 #endif 128 // Want to ensure that our Release is called when the owning image is destroyed 129 struct RasterDataHolder { 130 RasterDataHolder() : fReleaseCount(0) {} 131 sk_sp<SkData> fData; 132 int fReleaseCount; 133 static void Release(const void* pixels, void* context) { 134 RasterDataHolder* self = static_cast<RasterDataHolder*>(context); 135 self->fReleaseCount++; 136 self->fData.reset(); 137 } 138 }; 139 static sk_sp<SkImage> create_rasterproc_image(RasterDataHolder* dataHolder) { 140 SkASSERT(dataHolder); 141 SkImageInfo info; 142 dataHolder->fData = create_image_data(&info); 143 return SkImage::MakeFromRaster(SkPixmap(info, dataHolder->fData->data(), info.minRowBytes()), 144 RasterDataHolder::Release, dataHolder); 145 } 146 static sk_sp<SkImage> create_codec_image() { 147 SkImageInfo info; 148 sk_sp<SkData> data(create_image_data(&info)); 149 SkBitmap bitmap; 150 bitmap.installPixels(info, data->writable_data(), info.minRowBytes()); 151 sk_sp<SkData> src(sk_tool_utils::EncodeImageToData(bitmap, SkEncodedImageFormat::kPNG, 100)); 152 return SkImage::MakeFromEncoded(std::move(src)); 153 } 154 #if SK_SUPPORT_GPU 155 static sk_sp<SkImage> create_gpu_image(GrContext* context) { 156 const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 157 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info)); 158 draw_image_test_pattern(surface->getCanvas()); 159 return surface->makeImageSnapshot(); 160 } 161 #endif 162 163 static void test_encode(skiatest::Reporter* reporter, SkImage* image) { 164 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10); 165 sk_sp<SkData> origEncoded = image->encodeToData(); 166 REPORTER_ASSERT(reporter, origEncoded); 167 REPORTER_ASSERT(reporter, origEncoded->size() > 0); 168 169 sk_sp<SkImage> decoded(SkImage::MakeFromEncoded(origEncoded)); 170 if (!decoded) { 171 ERRORF(reporter, "failed to decode image!"); 172 return; 173 } 174 REPORTER_ASSERT(reporter, decoded); 175 assert_equal(reporter, image, nullptr, decoded.get()); 176 177 // Now see if we can instantiate an image from a subset of the surface/origEncoded 178 179 decoded = SkImage::MakeFromEncoded(origEncoded, &ir); 180 REPORTER_ASSERT(reporter, decoded); 181 assert_equal(reporter, image, &ir, decoded.get()); 182 } 183 184 DEF_TEST(ImageEncode, reporter) { 185 test_encode(reporter, create_image().get()); 186 } 187 188 #if SK_SUPPORT_GPU 189 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageEncode_Gpu, reporter, ctxInfo) { 190 test_encode(reporter, create_gpu_image(ctxInfo.grContext()).get()); 191 } 192 #endif 193 194 DEF_TEST(Image_MakeFromRasterBitmap, reporter) { 195 const struct { 196 SkCopyPixelsMode fCPM; 197 bool fExpectSameAsMutable; 198 bool fExpectSameAsImmutable; 199 } recs[] = { 200 { kIfMutable_SkCopyPixelsMode, false, true }, 201 { kAlways_SkCopyPixelsMode, false, false }, 202 { kNever_SkCopyPixelsMode, true, true }, 203 }; 204 for (auto rec : recs) { 205 SkPixmap pm; 206 SkBitmap bm; 207 bm.allocN32Pixels(100, 100); 208 209 auto img = SkMakeImageFromRasterBitmap(bm, rec.fCPM); 210 REPORTER_ASSERT(reporter, img->peekPixels(&pm)); 211 const bool sameMutable = pm.addr32(0, 0) == bm.getAddr32(0, 0); 212 REPORTER_ASSERT(reporter, rec.fExpectSameAsMutable == sameMutable); 213 REPORTER_ASSERT(reporter, (bm.getGenerationID() == img->uniqueID()) == sameMutable); 214 215 bm.notifyPixelsChanged(); // force a new generation ID 216 217 bm.setImmutable(); 218 img = SkMakeImageFromRasterBitmap(bm, rec.fCPM); 219 REPORTER_ASSERT(reporter, img->peekPixels(&pm)); 220 const bool sameImmutable = pm.addr32(0, 0) == bm.getAddr32(0, 0); 221 REPORTER_ASSERT(reporter, rec.fExpectSameAsImmutable == sameImmutable); 222 REPORTER_ASSERT(reporter, (bm.getGenerationID() == img->uniqueID()) == sameImmutable); 223 } 224 } 225 226 // Test that image encoding failures do not break picture serialization/deserialization. 227 DEF_TEST(Image_Serialize_Encoding_Failure, reporter) { 228 auto surface(SkSurface::MakeRasterN32Premul(100, 100)); 229 surface->getCanvas()->clear(SK_ColorGREEN); 230 sk_sp<SkImage> image(surface->makeImageSnapshot()); 231 REPORTER_ASSERT(reporter, image); 232 233 SkPictureRecorder recorder; 234 SkCanvas* canvas = recorder.beginRecording(100, 100); 235 canvas->drawImage(image, 0, 0); 236 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 237 REPORTER_ASSERT(reporter, picture); 238 REPORTER_ASSERT(reporter, picture->approximateOpCount() > 0); 239 240 bool was_called = false; 241 SkSerialProcs procs; 242 procs.fImageProc = [](SkImage*, void* called) { 243 *(bool*)called = true; 244 return SkData::MakeEmpty(); 245 }; 246 procs.fImageCtx = &was_called; 247 248 REPORTER_ASSERT(reporter, !was_called); 249 auto data = picture->serialize(&procs); 250 REPORTER_ASSERT(reporter, was_called); 251 REPORTER_ASSERT(reporter, data && data->size() > 0); 252 253 auto deserialized = SkPicture::MakeFromData(data->data(), data->size()); 254 REPORTER_ASSERT(reporter, deserialized); 255 REPORTER_ASSERT(reporter, deserialized->approximateOpCount() > 0); 256 } 257 258 // Test that a draw that only partially covers the drawing surface isn't 259 // interpreted as covering the entire drawing surface (i.e., exercise one of the 260 // conditions of SkCanvas::wouldOverwriteEntireSurface()). 261 DEF_TEST(Image_RetainSnapshot, reporter) { 262 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0); 263 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0); 264 SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2); 265 auto surface(SkSurface::MakeRaster(info)); 266 surface->getCanvas()->clear(0xFF00FF00); 267 268 SkPMColor pixels[4]; 269 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect 270 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2); 271 const size_t dstRowBytes = 2 * sizeof(SkPMColor); 272 273 sk_sp<SkImage> image1(surface->makeImageSnapshot()); 274 REPORTER_ASSERT(reporter, image1->readPixels(dstInfo, pixels, dstRowBytes, 0, 0)); 275 for (size_t i = 0; i < SK_ARRAY_COUNT(pixels); ++i) { 276 REPORTER_ASSERT(reporter, pixels[i] == green); 277 } 278 279 SkPaint paint; 280 paint.setBlendMode(SkBlendMode::kSrc); 281 paint.setColor(SK_ColorRED); 282 283 surface->getCanvas()->drawRect(SkRect::MakeXYWH(1, 1, 1, 1), paint); 284 285 sk_sp<SkImage> image2(surface->makeImageSnapshot()); 286 REPORTER_ASSERT(reporter, image2->readPixels(dstInfo, pixels, dstRowBytes, 0, 0)); 287 REPORTER_ASSERT(reporter, pixels[0] == green); 288 REPORTER_ASSERT(reporter, pixels[1] == green); 289 REPORTER_ASSERT(reporter, pixels[2] == green); 290 REPORTER_ASSERT(reporter, pixels[3] == red); 291 } 292 293 ///////////////////////////////////////////////////////////////////////////////////////////////// 294 295 static void make_bitmap_mutable(SkBitmap* bm) { 296 bm->allocN32Pixels(10, 10); 297 } 298 299 static void make_bitmap_immutable(SkBitmap* bm) { 300 bm->allocN32Pixels(10, 10); 301 bm->setImmutable(); 302 } 303 304 DEF_TEST(image_newfrombitmap, reporter) { 305 const struct { 306 void (*fMakeProc)(SkBitmap*); 307 bool fExpectPeekSuccess; 308 bool fExpectSharedID; 309 bool fExpectLazy; 310 } rec[] = { 311 { make_bitmap_mutable, true, false, false }, 312 { make_bitmap_immutable, true, true, false }, 313 }; 314 315 for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) { 316 SkBitmap bm; 317 rec[i].fMakeProc(&bm); 318 319 sk_sp<SkImage> image(SkImage::MakeFromBitmap(bm)); 320 SkPixmap pmap; 321 322 const bool sharedID = (image->uniqueID() == bm.getGenerationID()); 323 REPORTER_ASSERT(reporter, sharedID == rec[i].fExpectSharedID); 324 325 const bool peekSuccess = image->peekPixels(&pmap); 326 REPORTER_ASSERT(reporter, peekSuccess == rec[i].fExpectPeekSuccess); 327 328 const bool lazy = image->isLazyGenerated(); 329 REPORTER_ASSERT(reporter, lazy == rec[i].fExpectLazy); 330 } 331 } 332 333 /////////////////////////////////////////////////////////////////////////////////////////////////// 334 #if SK_SUPPORT_GPU 335 336 #include "SkBitmapCache.h" 337 338 /* 339 * This tests the caching (and preemptive purge) of the raster equivalent of a gpu-image. 340 * We cache it for performance when drawing into a raster surface. 341 * 342 * A cleaner test would know if each drawImage call triggered a read-back from the gpu, 343 * but we don't have that facility (at the moment) so we use a little internal knowledge 344 * of *how* the raster version is cached, and look for that. 345 */ 346 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(c, reporter, ctxInfo) { 347 SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 348 sk_sp<SkImage> image(create_gpu_image(ctxInfo.grContext())); 349 const uint32_t uniqueID = image->uniqueID(); 350 const auto desc = SkBitmapCacheDesc::Make(image.get()); 351 352 auto surface(SkSurface::MakeRaster(info)); 353 354 // now we can test drawing a gpu-backed image into a cpu-backed surface 355 356 { 357 SkBitmap cachedBitmap; 358 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(desc, &cachedBitmap)); 359 } 360 361 surface->getCanvas()->drawImage(image, 0, 0); 362 { 363 SkBitmap cachedBitmap; 364 if (SkBitmapCache::Find(desc, &cachedBitmap)) { 365 REPORTER_ASSERT(reporter, cachedBitmap.getGenerationID() == uniqueID); 366 REPORTER_ASSERT(reporter, cachedBitmap.isImmutable()); 367 REPORTER_ASSERT(reporter, cachedBitmap.getPixels()); 368 } else { 369 // unexpected, but not really a bug, since the cache is global and this test may be 370 // run w/ other threads competing for its budget. 371 SkDebugf("SkImage_Gpu2Cpu : cachedBitmap was already purged\n"); 372 } 373 } 374 375 image.reset(nullptr); 376 { 377 SkBitmap cachedBitmap; 378 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(desc, &cachedBitmap)); 379 } 380 } 381 382 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeTextureImage, reporter, contextInfo) { 383 GrContext* context = contextInfo.grContext(); 384 sk_gpu_test::TestContext* testContext = contextInfo.testContext(); 385 GrContextFactory otherFactory; 386 ContextInfo otherContextInfo = otherFactory.getContextInfo(contextInfo.type()); 387 testContext->makeCurrent(); 388 389 std::function<sk_sp<SkImage>()> imageFactories[] = { 390 create_image, 391 create_codec_image, 392 create_data_image, 393 // Create an image from a picture. 394 create_picture_image, 395 // Create a texture image. 396 [context] { return create_gpu_image(context); }, 397 // Create a texture image in a another GrContext. 398 [otherContextInfo] { 399 auto restore = otherContextInfo.testContext()->makeCurrentAndAutoRestore(); 400 sk_sp<SkImage> otherContextImage = create_gpu_image(otherContextInfo.grContext()); 401 otherContextInfo.grContext()->flush(); 402 return otherContextImage; 403 } 404 }; 405 406 sk_sp<SkColorSpace> dstColorSpaces[] ={ 407 nullptr, 408 SkColorSpace::MakeSRGB(), 409 }; 410 411 for (auto& dstColorSpace : dstColorSpaces) { 412 for (auto factory : imageFactories) { 413 sk_sp<SkImage> image(factory()); 414 if (!image) { 415 ERRORF(reporter, "Error creating image."); 416 continue; 417 } 418 419 sk_sp<SkImage> texImage(image->makeTextureImage(context, dstColorSpace.get())); 420 if (!texImage) { 421 GrContext* imageContext = as_IB(image)->context(); 422 423 // We expect to fail if image comes from a different GrContext. 424 if (!image->isTextureBacked() || imageContext == context) { 425 ERRORF(reporter, "makeTextureImage failed."); 426 } 427 continue; 428 } 429 if (!texImage->isTextureBacked()) { 430 ERRORF(reporter, "makeTextureImage returned non-texture image."); 431 continue; 432 } 433 if (image->isTextureBacked()) { 434 GrSurfaceProxy* origProxy = as_IB(image)->peekProxy(); 435 GrSurfaceProxy* copyProxy = as_IB(texImage)->peekProxy(); 436 437 if (origProxy->underlyingUniqueID() != copyProxy->underlyingUniqueID()) { 438 ERRORF(reporter, "makeTextureImage made unnecessary texture copy."); 439 } 440 } 441 if (image->width() != texImage->width() || image->height() != texImage->height()) { 442 ERRORF(reporter, "makeTextureImage changed the image size."); 443 } 444 if (image->alphaType() != texImage->alphaType()) { 445 ERRORF(reporter, "makeTextureImage changed image alpha type."); 446 } 447 } 448 449 context->flush(); 450 } 451 } 452 453 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeNonTextureImage, reporter, contextInfo) { 454 GrContext* context = contextInfo.grContext(); 455 456 std::function<sk_sp<SkImage>()> imageFactories[] = { 457 create_image, 458 create_codec_image, 459 create_data_image, 460 create_picture_image, 461 [context] { return create_gpu_image(context); }, 462 }; 463 SkColorSpace* legacyColorSpace = nullptr; 464 for (auto factory : imageFactories) { 465 sk_sp<SkImage> image = factory(); 466 if (!image->isTextureBacked()) { 467 REPORTER_ASSERT(reporter, image->makeNonTextureImage().get() == image.get()); 468 if (!(image = image->makeTextureImage(context, legacyColorSpace))) { 469 continue; 470 } 471 } 472 auto rasterImage = image->makeNonTextureImage(); 473 if (!rasterImage) { 474 ERRORF(reporter, "makeNonTextureImage failed for texture-backed image."); 475 } 476 REPORTER_ASSERT(reporter, !rasterImage->isTextureBacked()); 477 assert_equal(reporter, image.get(), nullptr, rasterImage.get()); 478 } 479 } 480 481 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SkImage_drawAbandonedGpuImage, reporter, contextInfo) { 482 auto context = contextInfo.grContext(); 483 auto image = create_gpu_image(context); 484 auto info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 485 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info)); 486 image->getTexture()->abandon(); 487 surface->getCanvas()->drawImage(image, 0, 0); 488 } 489 490 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsImage, reporter, ctxInfo) { 491 for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) { 492 static constexpr int kSize = 10; 493 SkColorType colorType = static_cast<SkColorType>(ct); 494 bool can = ctxInfo.grContext()->colorTypeSupportedAsImage(colorType); 495 auto* gpu = ctxInfo.grContext()->contextPriv().getGpu(); 496 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 497 nullptr, kSize, kSize, colorType, false, GrMipMapped::kNo); 498 auto img = 499 SkImage::MakeFromTexture(ctxInfo.grContext(), backendTex, kTopLeft_GrSurfaceOrigin, 500 colorType, kOpaque_SkAlphaType, nullptr); 501 REPORTER_ASSERT(reporter, can == SkToBool(img), 502 "colorTypeSupportedAsImage:%d, actual:%d, ct:%d", can, SkToBool(img), 503 colorType); 504 505 img.reset(); 506 ctxInfo.grContext()->flush(); 507 if (backendTex.isValid()) { 508 gpu->deleteTestingOnlyBackendTexture(&backendTex); 509 } 510 } 511 } 512 513 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(UnpremulTextureImage, reporter, ctxInfo) { 514 SkBitmap bmp; 515 bmp.allocPixels( 516 SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, nullptr)); 517 for (int y = 0; y < 256; ++y) { 518 for (int x = 0; x < 256; ++x) { 519 *bmp.getAddr32(x, y) = 520 SkColorSetARGB((U8CPU)y, 255 - (U8CPU)y, (U8CPU)x, 255 - (U8CPU)x); 521 } 522 } 523 auto texImage = SkImage::MakeFromBitmap(bmp)->makeTextureImage(ctxInfo.grContext(), nullptr); 524 if (!texImage || texImage->alphaType() != kUnpremul_SkAlphaType) { 525 ERRORF(reporter, "Failed to make unpremul texture image."); 526 return; 527 } 528 // The GPU backend always unpremuls the values stored in the texture because it assumes they 529 // are premul values. (skbug.com/7580). 530 if (false) { 531 SkBitmap unpremul; 532 unpremul.allocPixels(SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, 533 kUnpremul_SkAlphaType, nullptr)); 534 if (!texImage->readPixels(unpremul.info(), unpremul.getPixels(), unpremul.rowBytes(), 0, 535 0)) { 536 ERRORF(reporter, "Unpremul readback failed."); 537 return; 538 } 539 for (int y = 0; y < 256; ++y) { 540 for (int x = 0; x < 256; ++x) { 541 if (*bmp.getAddr32(x, y) != *unpremul.getAddr32(x, y)) { 542 ERRORF(reporter, "unpremul(0x%08x)->unpremul(0x%08x) at %d, %d.", 543 *bmp.getAddr32(x, y), *unpremul.getAddr32(x, y), x, y); 544 return; 545 } 546 } 547 } 548 } 549 SkBitmap premul; 550 premul.allocPixels( 551 SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr)); 552 if (!texImage->readPixels(premul.info(), premul.getPixels(), premul.rowBytes(), 0, 0)) { 553 ERRORF(reporter, "Unpremul readback failed."); 554 return; 555 } 556 for (int y = 0; y < 256; ++y) { 557 for (int x = 0; x < 256; ++x) { 558 // Treat bmp's color as a pm color even though it may be the r/b swap of a PM color. 559 // SkPremultiplyColor acts the same on both channels. 560 uint32_t origColor = SkPreMultiplyColor(*bmp.getAddr32(x, y)); 561 int32_t origA = (origColor >> 24) & 0xff; 562 int32_t origB = (origColor >> 16) & 0xff; 563 int32_t origG = (origColor >> 8) & 0xff; 564 int32_t origR = (origColor >> 0) & 0xff; 565 uint32_t read = *premul.getAddr32(x, y); 566 int32_t readA = (read >> 24) & 0xff; 567 int32_t readB = (read >> 16) & 0xff; 568 int32_t readG = (read >> 8) & 0xff; 569 int32_t readR = (read >> 0) & 0xff; 570 // We expect that alpha=1 and alpha=0 should come out exact. Otherwise allow a little 571 // bit of tolerance for GPU vs CPU premul math. 572 int32_t tol = (origA == 0 || origA == 255) ? 0 : 1; 573 if (origA != readA || SkTAbs(readB - origB) > tol || SkTAbs(readG - origG) > tol || 574 SkTAbs(readR - origR) > tol) { 575 ERRORF(reporter, "unpremul(0x%08x)->premul(0x%08x) at %d, %d.", 576 *bmp.getAddr32(x, y), *premul.getAddr32(x, y), x, y); 577 return; 578 } 579 } 580 } 581 } 582 583 #endif 584 585 class EmptyGenerator : public SkImageGenerator { 586 public: 587 EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {} 588 }; 589 590 DEF_TEST(ImageEmpty, reporter) { 591 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 592 SkPixmap pmap(info, nullptr, 0); 593 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeRasterCopy(pmap)); 594 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeRasterData(info, nullptr, 0)); 595 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeFromRaster(pmap, nullptr, nullptr)); 596 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeFromGenerator( 597 skstd::make_unique<EmptyGenerator>())); 598 } 599 600 DEF_TEST(ImageDataRef, reporter) { 601 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 602 size_t rowBytes = info.minRowBytes(); 603 size_t size = info.computeByteSize(rowBytes); 604 sk_sp<SkData> data = SkData::MakeUninitialized(size); 605 REPORTER_ASSERT(reporter, data->unique()); 606 sk_sp<SkImage> image = SkImage::MakeRasterData(info, data, rowBytes); 607 REPORTER_ASSERT(reporter, !data->unique()); 608 image.reset(); 609 REPORTER_ASSERT(reporter, data->unique()); 610 } 611 612 static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) { 613 for (int i = 0; i < count; ++i) { 614 if (pixels[i] != expected) { 615 return false; 616 } 617 } 618 return true; 619 } 620 621 static void image_test_read_pixels(skiatest::Reporter* reporter, SkImage* image) { 622 if (!image) { 623 ERRORF(reporter, "Failed to create image!"); 624 return; 625 } 626 const SkPMColor expected = SkPreMultiplyColor(SK_ColorWHITE); 627 const SkPMColor notExpected = ~expected; 628 629 const int w = 2, h = 2; 630 const size_t rowBytes = w * sizeof(SkPMColor); 631 SkPMColor pixels[w*h]; 632 633 SkImageInfo info; 634 635 info = SkImageInfo::MakeUnknown(w, h); 636 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0)); 637 638 // out-of-bounds should fail 639 info = SkImageInfo::MakeN32Premul(w, h); 640 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0)); 641 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h)); 642 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0)); 643 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height())); 644 645 // top-left should succeed 646 sk_memset32(pixels, notExpected, w*h); 647 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0)); 648 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); 649 650 // bottom-right should succeed 651 sk_memset32(pixels, notExpected, w*h); 652 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 653 image->width() - w, image->height() - h)); 654 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); 655 656 // partial top-left should succeed 657 sk_memset32(pixels, notExpected, w*h); 658 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1)); 659 REPORTER_ASSERT(reporter, pixels[3] == expected); 660 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected)); 661 662 // partial bottom-right should succeed 663 sk_memset32(pixels, notExpected, w*h); 664 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 665 image->width() - 1, image->height() - 1)); 666 REPORTER_ASSERT(reporter, pixels[0] == expected); 667 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected)); 668 } 669 DEF_TEST(ImageReadPixels, reporter) { 670 sk_sp<SkImage> image(create_image()); 671 image_test_read_pixels(reporter, image.get()); 672 673 image = create_data_image(); 674 image_test_read_pixels(reporter, image.get()); 675 676 RasterDataHolder dataHolder; 677 image = create_rasterproc_image(&dataHolder); 678 image_test_read_pixels(reporter, image.get()); 679 image.reset(); 680 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount); 681 682 image = create_codec_image(); 683 image_test_read_pixels(reporter, image.get()); 684 } 685 #if SK_SUPPORT_GPU 686 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageReadPixels_Gpu, reporter, ctxInfo) { 687 image_test_read_pixels(reporter, create_gpu_image(ctxInfo.grContext()).get()); 688 } 689 #endif 690 691 static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image, 692 const SkBitmap& bitmap) { 693 REPORTER_ASSERT(reporter, image->width() == bitmap.width()); 694 REPORTER_ASSERT(reporter, image->height() == bitmap.height()); 695 REPORTER_ASSERT(reporter, image->alphaType() == bitmap.alphaType()); 696 697 REPORTER_ASSERT(reporter, bitmap.isImmutable()); 698 699 REPORTER_ASSERT(reporter, bitmap.getPixels()); 700 701 const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType()); 702 SkPMColor imageColor; 703 REPORTER_ASSERT(reporter, image->readPixels(info, &imageColor, sizeof(SkPMColor), 0, 0)); 704 REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0)); 705 } 706 707 static void test_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image) { 708 if (!image) { 709 ERRORF(reporter, "Failed to create image."); 710 return; 711 } 712 SkBitmap bitmap; 713 REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap)); 714 check_legacy_bitmap(reporter, image, bitmap); 715 716 // Test subsetting to exercise the rowBytes logic. 717 SkBitmap tmp; 718 REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2, 719 image->height() / 2))); 720 sk_sp<SkImage> subsetImage(SkImage::MakeFromBitmap(tmp)); 721 REPORTER_ASSERT(reporter, subsetImage.get()); 722 723 SkBitmap subsetBitmap; 724 REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap)); 725 check_legacy_bitmap(reporter, subsetImage.get(), subsetBitmap); 726 } 727 DEF_TEST(ImageLegacyBitmap, reporter) { 728 sk_sp<SkImage> image(create_image()); 729 test_legacy_bitmap(reporter, image.get()); 730 731 image = create_data_image(); 732 test_legacy_bitmap(reporter, image.get()); 733 734 RasterDataHolder dataHolder; 735 image = create_rasterproc_image(&dataHolder); 736 test_legacy_bitmap(reporter, image.get()); 737 image.reset(); 738 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount); 739 740 image = create_codec_image(); 741 test_legacy_bitmap(reporter, image.get()); 742 } 743 #if SK_SUPPORT_GPU 744 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageLegacyBitmap_Gpu, reporter, ctxInfo) { 745 sk_sp<SkImage> image(create_gpu_image(ctxInfo.grContext())); 746 test_legacy_bitmap(reporter, image.get()); 747 } 748 #endif 749 750 static void test_peek(skiatest::Reporter* reporter, SkImage* image, bool expectPeekSuccess) { 751 if (!image) { 752 ERRORF(reporter, "Failed to create image!"); 753 return; 754 } 755 SkPixmap pm; 756 bool success = image->peekPixels(&pm); 757 REPORTER_ASSERT(reporter, expectPeekSuccess == success); 758 if (success) { 759 const SkImageInfo& info = pm.info(); 760 REPORTER_ASSERT(reporter, 20 == info.width()); 761 REPORTER_ASSERT(reporter, 20 == info.height()); 762 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType()); 763 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() || 764 kOpaque_SkAlphaType == info.alphaType()); 765 REPORTER_ASSERT(reporter, info.minRowBytes() <= pm.rowBytes()); 766 REPORTER_ASSERT(reporter, SkPreMultiplyColor(SK_ColorWHITE) == *pm.addr32(0, 0)); 767 } 768 } 769 DEF_TEST(ImagePeek, reporter) { 770 sk_sp<SkImage> image(create_image()); 771 test_peek(reporter, image.get(), true); 772 773 image = create_data_image(); 774 test_peek(reporter, image.get(), true); 775 776 RasterDataHolder dataHolder; 777 image = create_rasterproc_image(&dataHolder); 778 test_peek(reporter, image.get(), true); 779 image.reset(); 780 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount); 781 782 image = create_codec_image(); 783 test_peek(reporter, image.get(), false); 784 } 785 #if SK_SUPPORT_GPU 786 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImagePeek_Gpu, reporter, ctxInfo) { 787 sk_sp<SkImage> image(create_gpu_image(ctxInfo.grContext())); 788 test_peek(reporter, image.get(), false); 789 } 790 #endif 791 792 #if SK_SUPPORT_GPU 793 struct TextureReleaseChecker { 794 TextureReleaseChecker() : fReleaseCount(0) {} 795 int fReleaseCount; 796 static void Release(void* self) { 797 static_cast<TextureReleaseChecker*>(self)->fReleaseCount++; 798 } 799 }; 800 801 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SkImage_NewFromTextureRelease, reporter, ctxInfo) { 802 const int kWidth = 10; 803 const int kHeight = 10; 804 std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]); 805 806 GrContext* ctx = ctxInfo.grContext(); 807 GrGpu* gpu = ctx->contextPriv().getGpu(); 808 809 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 810 pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo); 811 812 TextureReleaseChecker releaseChecker; 813 GrSurfaceOrigin texOrigin = kBottomLeft_GrSurfaceOrigin; 814 sk_sp<SkImage> refImg( 815 SkImage::MakeFromTexture(ctx, backendTex, texOrigin, kRGBA_8888_SkColorType, 816 kPremul_SkAlphaType, nullptr, 817 TextureReleaseChecker::Release, &releaseChecker)); 818 819 GrSurfaceOrigin readBackOrigin; 820 GrBackendObject readBackHandle = refImg->getTextureHandle(false, &readBackOrigin); 821 // TODO: Make it so we can check this (see skbug.com/5019) 822 #if 0 823 if (*readBackHandle != *(backendTexHandle)) { 824 ERRORF(reporter, "backend mismatch %d %d\n", 825 (int)readBackHandle, (int)backendTexHandle); 826 } 827 REPORTER_ASSERT(reporter, readBackHandle == backendTexHandle); 828 #else 829 REPORTER_ASSERT(reporter, SkToBool(readBackHandle)); 830 #endif 831 if (readBackOrigin != texOrigin) { 832 ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin); 833 } 834 REPORTER_ASSERT(reporter, readBackOrigin == texOrigin); 835 836 // Now exercise the release proc 837 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 838 refImg.reset(nullptr); // force a release of the image 839 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 840 841 gpu->deleteTestingOnlyBackendTexture(&backendTex); 842 } 843 844 static void test_cross_context_image(skiatest::Reporter* reporter, const GrContextOptions& options, 845 std::function<sk_sp<SkImage>(GrContext*)> imageMaker) { 846 for (int i = 0; i < GrContextFactory::kContextTypeCnt; ++i) { 847 GrContextFactory testFactory(options); 848 GrContextFactory::ContextType ctxType = static_cast<GrContextFactory::ContextType>(i); 849 ContextInfo ctxInfo = testFactory.getContextInfo(ctxType); 850 GrContext* ctx = ctxInfo.grContext(); 851 if (!ctx) { 852 continue; 853 } 854 855 // If we don't have proper support for this feature, the factory will fallback to returning 856 // codec-backed images. Those will "work", but some of our checks will fail because we 857 // expect the cross-context images not to work on multiple contexts at once. 858 if (!ctx->caps()->crossContextTextureSupport()) { 859 continue; 860 } 861 862 // We test three lifetime patterns for a single context: 863 // 1) Create image, free image 864 // 2) Create image, draw, flush, free image 865 // 3) Create image, draw, free image, flush 866 // ... and then repeat the last two patterns with drawing on a second* context: 867 // 4) Create image, draw*, flush*, free image 868 // 5) Create image, draw*, free iamge, flush* 869 870 // Case #1: Create image, free image 871 { 872 sk_sp<SkImage> refImg(imageMaker(ctx)); 873 refImg.reset(nullptr); // force a release of the image 874 } 875 876 SkImageInfo info = SkImageInfo::MakeN32Premul(128, 128); 877 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); 878 SkCanvas* canvas = surface->getCanvas(); 879 880 // Case #2: Create image, draw, flush, free image 881 { 882 sk_sp<SkImage> refImg(imageMaker(ctx)); 883 884 canvas->drawImage(refImg, 0, 0); 885 canvas->flush(); 886 887 refImg.reset(nullptr); // force a release of the image 888 } 889 890 // Case #3: Create image, draw, free image, flush 891 { 892 sk_sp<SkImage> refImg(imageMaker(ctx)); 893 894 canvas->drawImage(refImg, 0, 0); 895 refImg.reset(nullptr); // force a release of the image 896 897 canvas->flush(); 898 } 899 900 // Configure second context 901 sk_gpu_test::TestContext* testContext = ctxInfo.testContext(); 902 903 ContextInfo otherContextInfo = testFactory.getSharedContextInfo(ctx); 904 GrContext* otherCtx = otherContextInfo.grContext(); 905 sk_gpu_test::TestContext* otherTestContext = otherContextInfo.testContext(); 906 907 // Creating a context in a share group may fail 908 if (!otherCtx) { 909 continue; 910 } 911 912 surface = SkSurface::MakeRenderTarget(otherCtx, SkBudgeted::kNo, info); 913 canvas = surface->getCanvas(); 914 915 // Case #4: Create image, draw*, flush*, free image 916 { 917 testContext->makeCurrent(); 918 sk_sp<SkImage> refImg(imageMaker(ctx)); 919 920 otherTestContext->makeCurrent(); 921 canvas->drawImage(refImg, 0, 0); 922 canvas->flush(); 923 924 testContext->makeCurrent(); 925 refImg.reset(nullptr); // force a release of the image 926 } 927 928 // Case #5: Create image, draw*, free image, flush* 929 { 930 testContext->makeCurrent(); 931 sk_sp<SkImage> refImg(imageMaker(ctx)); 932 933 otherTestContext->makeCurrent(); 934 canvas->drawImage(refImg, 0, 0); 935 936 testContext->makeCurrent(); 937 refImg.reset(nullptr); // force a release of the image 938 939 otherTestContext->makeCurrent(); 940 canvas->flush(); 941 942 // This readPixels call is needed for Vulkan to make sure the ReleaseProc is called. 943 // Even though we flushed above, this does not guarantee the command buffer will finish 944 // which is when we call the ReleaseProc. The readPixels forces a CPU sync so we know 945 // that the command buffer has finished and we've called the ReleaseProc. 946 SkBitmap bitmap; 947 bitmap.allocPixels(info); 948 canvas->readPixels(bitmap, 0, 0); 949 } 950 951 // Case #6: Verify that only one context can be using the image at a time 952 { 953 testContext->makeCurrent(); 954 sk_sp<SkImage> refImg(imageMaker(ctx)); 955 956 // Any context should be able to borrow the texture at this point 957 sk_sp<SkColorSpace> texColorSpace; 958 sk_sp<GrTextureProxy> proxy = as_IB(refImg)->asTextureProxyRef( 959 ctx, GrSamplerState::ClampNearest(), nullptr, &texColorSpace, nullptr); 960 REPORTER_ASSERT(reporter, proxy); 961 962 // But once it's borrowed, no other context should be able to borrow 963 otherTestContext->makeCurrent(); 964 sk_sp<GrTextureProxy> otherProxy = as_IB(refImg)->asTextureProxyRef( 965 otherCtx, GrSamplerState::ClampNearest(), nullptr, &texColorSpace, nullptr); 966 REPORTER_ASSERT(reporter, !otherProxy); 967 968 // Original context (that's already borrowing) should be okay 969 testContext->makeCurrent(); 970 sk_sp<GrTextureProxy> proxySecondRef = as_IB(refImg)->asTextureProxyRef( 971 ctx, GrSamplerState::ClampNearest(), nullptr, &texColorSpace, nullptr); 972 REPORTER_ASSERT(reporter, proxySecondRef); 973 974 // Release first ref from the original context 975 proxy.reset(nullptr); 976 977 // We released one proxy but not the other from the current borrowing context. Make sure 978 // a new context is still not able to borrow the texture. 979 otherTestContext->makeCurrent(); 980 otherProxy = as_IB(refImg)->asTextureProxyRef(otherCtx, GrSamplerState::ClampNearest(), 981 nullptr, &texColorSpace, nullptr); 982 REPORTER_ASSERT(reporter, !otherProxy); 983 984 // Release second ref from the original context 985 testContext->makeCurrent(); 986 proxySecondRef.reset(nullptr); 987 988 // Now we should be able to borrow the texture from the other context 989 otherTestContext->makeCurrent(); 990 otherProxy = as_IB(refImg)->asTextureProxyRef(otherCtx, GrSamplerState::ClampNearest(), 991 nullptr, &texColorSpace, nullptr); 992 REPORTER_ASSERT(reporter, otherProxy); 993 994 // Release everything 995 otherProxy.reset(nullptr); 996 refImg.reset(nullptr); 997 } 998 } 999 } 1000 1001 DEF_GPUTEST(SkImage_MakeCrossContextFromEncodedRelease, reporter, options) { 1002 sk_sp<SkData> data = GetResourceAsData("images/mandrill_128.png"); 1003 SkASSERT(data.get()); 1004 1005 test_cross_context_image(reporter, options, [&data](GrContext* ctx) { 1006 return SkImage::MakeCrossContextFromEncoded(ctx, data, false, nullptr); 1007 }); 1008 } 1009 1010 DEF_GPUTEST(SkImage_MakeCrossContextFromPixmapRelease, reporter, options) { 1011 SkBitmap bitmap; 1012 SkPixmap pixmap; 1013 SkAssertResult(GetResourceAsBitmap("images/mandrill_128.png", &bitmap) && bitmap.peekPixels(&pixmap)); 1014 1015 test_cross_context_image(reporter, options, [&pixmap](GrContext* ctx) { 1016 return SkImage::MakeCrossContextFromPixmap(ctx, pixmap, false, nullptr); 1017 }); 1018 } 1019 1020 static uint32_t GetIdForBackendObject(GrContext* ctx, GrBackendObject object) { 1021 if (!object) { 1022 return 0; 1023 } 1024 1025 if (ctx->contextPriv().getBackend() != kOpenGL_GrBackend) { 1026 return 0; 1027 } 1028 1029 return reinterpret_cast<const GrGLTextureInfo*>(object)->fID; 1030 } 1031 1032 static uint32_t GetIdForBackendTexture(GrBackendTexture texture) { 1033 if (!texture.isValid()) { 1034 return 0; 1035 } 1036 1037 if (texture.backend() != kOpenGL_GrBackend) { 1038 return 0; 1039 } 1040 1041 return texture.getGLTextureInfo()->fID; 1042 } 1043 1044 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(makeBackendTexture, reporter, ctxInfo) { 1045 GrContext* context = ctxInfo.grContext(); 1046 sk_gpu_test::TestContext* testContext = ctxInfo.testContext(); 1047 sk_sp<GrContextThreadSafeProxy> proxy = context->threadSafeProxy(); 1048 1049 GrContextFactory otherFactory; 1050 ContextInfo otherContextInfo = otherFactory.getContextInfo(ctxInfo.type()); 1051 1052 testContext->makeCurrent(); 1053 REPORTER_ASSERT(reporter, proxy); 1054 auto createLarge = [context] { 1055 return create_image_large(context->caps()->maxTextureSize()); 1056 }; 1057 struct { 1058 std::function<sk_sp<SkImage> ()> fImageFactory; 1059 bool fExpectation; 1060 bool fCanTakeDirectly; 1061 } testCases[] = { 1062 { create_image, true, false }, 1063 { create_codec_image, true, false }, 1064 { create_data_image, true, false }, 1065 { create_picture_image, true, false }, 1066 { [context] { return create_gpu_image(context); }, true, true }, 1067 // Create a texture image in a another GrContext. 1068 { [otherContextInfo] { 1069 auto restore = otherContextInfo.testContext()->makeCurrentAndAutoRestore(); 1070 sk_sp<SkImage> otherContextImage = create_gpu_image(otherContextInfo.grContext()); 1071 otherContextInfo.grContext()->flush(); 1072 return otherContextImage; 1073 }, false, false }, 1074 // Create an image that is too large to be texture backed. 1075 { createLarge, false, false } 1076 }; 1077 1078 for (auto testCase : testCases) { 1079 sk_sp<SkImage> image(testCase.fImageFactory()); 1080 if (!image) { 1081 ERRORF(reporter, "Failed to create image!"); 1082 continue; 1083 } 1084 1085 uint32_t originalID = GetIdForBackendObject(context, image->getTextureHandle(true, nullptr)); 1086 GrBackendTexture texture; 1087 SkImage::BackendTextureReleaseProc proc; 1088 bool result = 1089 SkImage::MakeBackendTextureFromSkImage(context, std::move(image), &texture, &proc); 1090 if (result != testCase.fExpectation) { 1091 static const char *const kFS[] = { "fail", "succeed" }; 1092 ERRORF(reporter, "This image was expected to %s but did not.", 1093 kFS[testCase.fExpectation]); 1094 } 1095 1096 bool tookDirectly = result && originalID == GetIdForBackendTexture(texture); 1097 if (testCase.fCanTakeDirectly != tookDirectly) { 1098 static const char *const kExpectedState[] = { "not expected", "expected" }; 1099 ERRORF(reporter, "This backend texture was %s to be taken directly.", 1100 kExpectedState[testCase.fCanTakeDirectly]); 1101 } 1102 1103 context->flush(); 1104 } 1105 } 1106 #endif 1107 1108 /////////////////////////////////////////////////////////////////////////////////////////////////// 1109 1110 static sk_sp<SkImage> create_picture_image(sk_sp<SkColorSpace> space) { 1111 SkPictureRecorder recorder; 1112 SkCanvas* canvas = recorder.beginRecording(10, 10); 1113 canvas->clear(SK_ColorCYAN); 1114 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(), SkISize::Make(10, 10), 1115 nullptr, nullptr, SkImage::BitDepth::kU8, std::move(space)); 1116 }; 1117 1118 static inline bool almost_equal(int a, int b) { 1119 return SkTAbs(a - b) <= 1; 1120 } 1121 1122 DEF_TEST(Image_ColorSpace, r) { 1123 sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB(); 1124 sk_sp<SkImage> image = GetResourceAsImage("images/mandrill_512_q075.jpg"); 1125 REPORTER_ASSERT(r, srgb.get() == image->colorSpace()); 1126 1127 image = GetResourceAsImage("images/webp-color-profile-lossy.webp"); 1128 SkColorSpaceTransferFn fn; 1129 bool success = image->colorSpace()->isNumericalTransferFn(&fn); 1130 REPORTER_ASSERT(r, success); 1131 REPORTER_ASSERT(r, color_space_almost_equal(1.8f, fn.fG)); 1132 1133 sk_sp<SkColorSpace> rec2020 = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, 1134 SkColorSpace::kRec2020_Gamut); 1135 image = create_picture_image(rec2020); 1136 REPORTER_ASSERT(r, SkColorSpace::Equals(rec2020.get(), image->colorSpace())); 1137 1138 SkBitmap bitmap; 1139 SkImageInfo info = SkImageInfo::MakeN32(10, 10, kPremul_SkAlphaType, rec2020); 1140 bitmap.allocPixels(info); 1141 image = SkImage::MakeFromBitmap(bitmap); 1142 REPORTER_ASSERT(r, SkColorSpace::Equals(rec2020.get(), image->colorSpace())); 1143 1144 sk_sp<SkSurface> surface = SkSurface::MakeRaster( 1145 SkImageInfo::MakeN32Premul(SkISize::Make(10, 10))); 1146 image = surface->makeImageSnapshot(); 1147 REPORTER_ASSERT(r, nullptr == image->colorSpace()); 1148 1149 surface = SkSurface::MakeRaster(info); 1150 image = surface->makeImageSnapshot(); 1151 REPORTER_ASSERT(r, SkColorSpace::Equals(rec2020.get(), image->colorSpace())); 1152 } 1153 1154 DEF_TEST(Image_makeColorSpace, r) { 1155 sk_sp<SkColorSpace> p3 = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, 1156 SkColorSpace::kDCIP3_D65_Gamut); 1157 SkColorSpaceTransferFn fn; 1158 fn.fA = 1.f; fn.fB = 0.f; fn.fC = 0.f; fn.fD = 0.f; fn.fE = 0.f; fn.fF = 0.f; fn.fG = 1.8f; 1159 sk_sp<SkColorSpace> adobeGamut = SkColorSpace::MakeRGB(fn, SkColorSpace::kAdobeRGB_Gamut); 1160 1161 SkBitmap srgbBitmap; 1162 srgbBitmap.allocPixels(SkImageInfo::MakeS32(1, 1, kOpaque_SkAlphaType)); 1163 *srgbBitmap.getAddr32(0, 0) = SkSwizzle_RGBA_to_PMColor(0xFF604020); 1164 srgbBitmap.setImmutable(); 1165 sk_sp<SkImage> srgbImage = SkImage::MakeFromBitmap(srgbBitmap); 1166 sk_sp<SkImage> p3Image = srgbImage->makeColorSpace(p3, SkTransferFunctionBehavior::kIgnore); 1167 SkBitmap p3Bitmap; 1168 bool success = p3Image->asLegacyBitmap(&p3Bitmap); 1169 REPORTER_ASSERT(r, success); 1170 REPORTER_ASSERT(r, almost_equal(0x28, SkGetPackedR32(*p3Bitmap.getAddr32(0, 0)))); 1171 REPORTER_ASSERT(r, almost_equal(0x40, SkGetPackedG32(*p3Bitmap.getAddr32(0, 0)))); 1172 REPORTER_ASSERT(r, almost_equal(0x5E, SkGetPackedB32(*p3Bitmap.getAddr32(0, 0)))); 1173 1174 sk_sp<SkImage> adobeImage = srgbImage->makeColorSpace(adobeGamut, 1175 SkTransferFunctionBehavior::kIgnore); 1176 SkBitmap adobeBitmap; 1177 success = adobeImage->asLegacyBitmap(&adobeBitmap); 1178 REPORTER_ASSERT(r, success); 1179 REPORTER_ASSERT(r, almost_equal(0x21, SkGetPackedR32(*adobeBitmap.getAddr32(0, 0)))); 1180 REPORTER_ASSERT(r, almost_equal(0x31, SkGetPackedG32(*adobeBitmap.getAddr32(0, 0)))); 1181 REPORTER_ASSERT(r, almost_equal(0x4C, SkGetPackedB32(*adobeBitmap.getAddr32(0, 0)))); 1182 1183 srgbImage = GetResourceAsImage("images/1x1.png"); 1184 p3Image = srgbImage->makeColorSpace(p3, SkTransferFunctionBehavior::kIgnore); 1185 success = p3Image->asLegacyBitmap(&p3Bitmap); 1186 REPORTER_ASSERT(r, success); 1187 REPORTER_ASSERT(r, almost_equal(0x8B, SkGetPackedR32(*p3Bitmap.getAddr32(0, 0)))); 1188 REPORTER_ASSERT(r, almost_equal(0x82, SkGetPackedG32(*p3Bitmap.getAddr32(0, 0)))); 1189 REPORTER_ASSERT(r, almost_equal(0x77, SkGetPackedB32(*p3Bitmap.getAddr32(0, 0)))); 1190 } 1191 1192 /////////////////////////////////////////////////////////////////////////////////////////////////// 1193 1194 static void make_all_premul(SkBitmap* bm) { 1195 bm->allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType)); 1196 for (int a = 0; a < 256; ++a) { 1197 for (int r = 0; r < 256; ++r) { 1198 // make all valid premul combinations 1199 int c = SkTMin(a, r); 1200 *bm->getAddr32(a, r) = SkPackARGB32(a, c, c, c); 1201 } 1202 } 1203 } 1204 1205 static bool equal(const SkBitmap& a, const SkBitmap& b) { 1206 SkASSERT(a.width() == b.width()); 1207 SkASSERT(a.height() == b.height()); 1208 for (int y = 0; y < a.height(); ++y) { 1209 for (int x = 0; x < a.width(); ++x) { 1210 SkPMColor pa = *a.getAddr32(x, y); 1211 SkPMColor pb = *b.getAddr32(x, y); 1212 if (pa != pb) { 1213 return false; 1214 } 1215 } 1216 } 1217 return true; 1218 } 1219 1220 DEF_TEST(image_roundtrip_encode, reporter) { 1221 SkBitmap bm0; 1222 make_all_premul(&bm0); 1223 1224 auto img0 = SkImage::MakeFromBitmap(bm0); 1225 sk_sp<SkData> data = img0->encodeToData(SkEncodedImageFormat::kPNG, 100); 1226 auto img1 = SkImage::MakeFromEncoded(data); 1227 1228 SkBitmap bm1; 1229 bm1.allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType)); 1230 img1->readPixels(bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0); 1231 1232 REPORTER_ASSERT(reporter, equal(bm0, bm1)); 1233 } 1234 1235 DEF_TEST(image_roundtrip_premul, reporter) { 1236 SkBitmap bm0; 1237 make_all_premul(&bm0); 1238 1239 SkBitmap bm1; 1240 bm1.allocPixels(SkImageInfo::MakeN32(256, 256, kUnpremul_SkAlphaType)); 1241 bm0.readPixels(bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0); 1242 1243 SkBitmap bm2; 1244 bm2.allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType)); 1245 bm1.readPixels(bm2.info(), bm2.getPixels(), bm2.rowBytes(), 0, 0); 1246 1247 REPORTER_ASSERT(reporter, equal(bm0, bm2)); 1248 } 1249 1250 /////////////////////////////////////////////////////////////////////////////////////////////////// 1251 1252 static void check_scaled_pixels(skiatest::Reporter* reporter, SkPixmap* pmap, uint32_t expected) { 1253 // Verify that all pixels contain the original test color 1254 for (auto y = 0; y < pmap->height(); ++y) { 1255 for (auto x = 0; x < pmap->width(); ++x) { 1256 uint32_t pixel = *pmap->addr32(x, y); 1257 if (pixel != expected) { 1258 ERRORF(reporter, "Expected scaled pixels to be the same. At %d,%d 0x%08x != 0x%08x", 1259 x, y, pixel, expected); 1260 return; 1261 } 1262 } 1263 } 1264 } 1265 1266 static void test_scale_pixels(skiatest::Reporter* reporter, const SkImage* image, 1267 uint32_t expected) { 1268 SkImageInfo info = SkImageInfo::MakeN32Premul(image->width() * 2, image->height() * 2); 1269 1270 // Make sure to test kDisallow first, so we don't just get a cache hit in that case 1271 for (auto chint : { SkImage::kDisallow_CachingHint, SkImage::kAllow_CachingHint }) { 1272 SkAutoPixmapStorage scaled; 1273 scaled.alloc(info); 1274 if (!image->scalePixels(scaled, kLow_SkFilterQuality, chint)) { 1275 ERRORF(reporter, "Failed to scale image"); 1276 continue; 1277 } 1278 1279 check_scaled_pixels(reporter, &scaled, expected); 1280 } 1281 } 1282 1283 DEF_TEST(ImageScalePixels, reporter) { 1284 const SkPMColor pmRed = SkPackARGB32(0xFF, 0xFF, 0, 0); 1285 const SkColor red = SK_ColorRED; 1286 1287 // Test raster image 1288 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 1289 sk_sp<SkSurface> surface = SkSurface::MakeRaster(info); 1290 surface->getCanvas()->clear(red); 1291 sk_sp<SkImage> rasterImage = surface->makeImageSnapshot(); 1292 test_scale_pixels(reporter, rasterImage.get(), pmRed); 1293 1294 // Test encoded image 1295 sk_sp<SkData> data = rasterImage->encodeToData(); 1296 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(data); 1297 test_scale_pixels(reporter, codecImage.get(), pmRed); 1298 } 1299 1300 #if SK_SUPPORT_GPU 1301 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageScalePixels_Gpu, reporter, ctxInfo) { 1302 const SkPMColor pmRed = SkPackARGB32(0xFF, 0xFF, 0, 0); 1303 const SkColor red = SK_ColorRED; 1304 1305 SkImageInfo info = SkImageInfo::MakeN32Premul(16, 16); 1306 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo, 1307 info); 1308 surface->getCanvas()->clear(red); 1309 sk_sp<SkImage> gpuImage = surface->makeImageSnapshot(); 1310 test_scale_pixels(reporter, gpuImage.get(), pmRed); 1311 } 1312 #endif 1313 1314 static sk_sp<SkImage> any_image_will_do() { 1315 return GetResourceAsImage("images/mandrill_32.png"); 1316 } 1317 1318 DEF_TEST(Image_nonfinite_dst, reporter) { 1319 auto surf = SkSurface::MakeRasterN32Premul(10, 10); 1320 auto img = any_image_will_do(); 1321 SkPaint paint; 1322 1323 for (SkScalar bad : { SK_ScalarInfinity, SK_ScalarNaN}) { 1324 for (int bits = 1; bits <= 15; ++bits) { 1325 SkRect dst = { 0, 0, 10, 10 }; 1326 if (bits & 1) dst.fLeft = bad; 1327 if (bits & 2) dst.fTop = bad; 1328 if (bits & 4) dst.fRight = bad; 1329 if (bits & 8) dst.fBottom = bad; 1330 1331 surf->getCanvas()->drawImageRect(img, dst, &paint); 1332 1333 // we should draw nothing 1334 sk_tool_utils::PixelIter iter(surf.get()); 1335 while (void* addr = iter.next()) { 1336 REPORTER_ASSERT(reporter, *(SkPMColor*)addr == 0); 1337 } 1338 } 1339 } 1340 } 1341 1342