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