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