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 "DMGpuSupport.h" 10 11 #include "SkBitmap.h" 12 #include "SkCanvas.h" 13 #include "SkData.h" 14 #include "SkDevice.h" 15 #include "SkImageEncoder.h" 16 #include "SkImageGenerator.h" 17 #include "SkImage_Base.h" 18 #include "SkPicture.h" 19 #include "SkPictureRecorder.h" 20 #include "SkPixelSerializer.h" 21 #include "SkRRect.h" 22 #include "SkStream.h" 23 #include "SkSurface.h" 24 #include "SkUtils.h" 25 #include "Test.h" 26 27 static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA, 28 SkImage* b) { 29 const int widthA = subsetA ? subsetA->width() : a->width(); 30 const int heightA = subsetA ? subsetA->height() : a->height(); 31 32 REPORTER_ASSERT(reporter, widthA == b->width()); 33 REPORTER_ASSERT(reporter, heightA == b->height()); 34 #if 0 35 // see https://bug.skia.org/3965 36 bool AO = a->isOpaque(); 37 bool BO = b->isOpaque(); 38 REPORTER_ASSERT(reporter, AO == BO); 39 #endif 40 41 SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA, 42 a->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 43 SkAutoPixmapStorage pmapA, pmapB; 44 pmapA.alloc(info); 45 pmapB.alloc(info); 46 47 const int srcX = subsetA ? subsetA->x() : 0; 48 const int srcY = subsetA ? subsetA->y() : 0; 49 50 REPORTER_ASSERT(reporter, a->readPixels(pmapA, srcX, srcY)); 51 REPORTER_ASSERT(reporter, b->readPixels(pmapB, 0, 0)); 52 53 const size_t widthBytes = widthA * info.bytesPerPixel(); 54 for (int y = 0; y < heightA; ++y) { 55 REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes)); 56 } 57 } 58 static void draw_image_test_pattern(SkCanvas* canvas) { 59 canvas->clear(SK_ColorWHITE); 60 SkPaint paint; 61 paint.setColor(SK_ColorBLACK); 62 canvas->drawRect(SkRect::MakeXYWH(5, 5, 10, 10), paint); 63 } 64 static SkImage* create_image() { 65 const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 66 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info)); 67 draw_image_test_pattern(surface->getCanvas()); 68 return surface->newImageSnapshot(); 69 } 70 static SkData* create_image_data(SkImageInfo* info) { 71 *info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 72 const size_t rowBytes = info->minRowBytes(); 73 SkAutoTUnref<SkData> data(SkData::NewUninitialized(rowBytes * info->height())); 74 { 75 SkBitmap bm; 76 bm.installPixels(*info, data->writable_data(), rowBytes); 77 SkCanvas canvas(bm); 78 draw_image_test_pattern(&canvas); 79 } 80 return data.release(); 81 } 82 static SkImage* create_data_image() { 83 SkImageInfo info; 84 SkAutoTUnref<SkData> data(create_image_data(&info)); 85 return SkImage::NewRasterData(info, data, info.minRowBytes()); 86 } 87 #if SK_SUPPORT_GPU // not gpu-specific but currently only used in GPU tests 88 static SkImage* create_picture_image() { 89 SkPictureRecorder recorder; 90 SkCanvas* canvas = recorder.beginRecording(10, 10); 91 canvas->clear(SK_ColorCYAN); 92 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 93 return SkImage::NewFromPicture(picture, SkISize::Make(10, 10), nullptr, nullptr); 94 }; 95 #endif 96 // Want to ensure that our Release is called when the owning image is destroyed 97 struct RasterDataHolder { 98 RasterDataHolder() : fReleaseCount(0) {} 99 SkAutoTUnref<SkData> fData; 100 int fReleaseCount; 101 static void Release(const void* pixels, void* context) { 102 RasterDataHolder* self = static_cast<RasterDataHolder*>(context); 103 self->fReleaseCount++; 104 self->fData.reset(); 105 } 106 }; 107 static SkImage* create_rasterproc_image(RasterDataHolder* dataHolder) { 108 SkASSERT(dataHolder); 109 SkImageInfo info; 110 SkAutoTUnref<SkData> data(create_image_data(&info)); 111 dataHolder->fData.reset(SkRef(data.get())); 112 return SkImage::NewFromRaster(info, data->data(), info.minRowBytes(), 113 RasterDataHolder::Release, dataHolder); 114 } 115 static SkImage* create_codec_image() { 116 SkImageInfo info; 117 SkAutoTUnref<SkData> data(create_image_data(&info)); 118 SkBitmap bitmap; 119 bitmap.installPixels(info, data->writable_data(), info.minRowBytes()); 120 SkAutoTUnref<SkData> src( 121 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100)); 122 return SkImage::NewFromEncoded(src); 123 } 124 #if SK_SUPPORT_GPU 125 static SkImage* create_gpu_image(GrContext* context) { 126 const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 127 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context, SkBudgeted::kNo, 128 info)); 129 draw_image_test_pattern(surface->getCanvas()); 130 return surface->newImageSnapshot(); 131 } 132 #endif 133 134 static void test_encode(skiatest::Reporter* reporter, SkImage* image) { 135 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10); 136 SkAutoTUnref<SkData> origEncoded(image->encode()); 137 REPORTER_ASSERT(reporter, origEncoded); 138 REPORTER_ASSERT(reporter, origEncoded->size() > 0); 139 140 SkAutoTUnref<SkImage> decoded(SkImage::NewFromEncoded(origEncoded)); 141 REPORTER_ASSERT(reporter, decoded); 142 assert_equal(reporter, image, nullptr, decoded); 143 144 // Now see if we can instantiate an image from a subset of the surface/origEncoded 145 146 decoded.reset(SkImage::NewFromEncoded(origEncoded, &ir)); 147 REPORTER_ASSERT(reporter, decoded); 148 assert_equal(reporter, image, &ir, decoded); 149 } 150 151 DEF_TEST(ImageEncode, reporter) { 152 SkAutoTUnref<SkImage> image(create_image()); 153 test_encode(reporter, image); 154 } 155 156 #if SK_SUPPORT_GPU 157 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageEncode_Gpu, reporter, context) { 158 SkAutoTUnref<SkImage> image(create_gpu_image(context)); 159 test_encode(reporter, image); 160 } 161 #endif 162 163 namespace { 164 165 const char* kSerializedData = "serialized"; 166 167 class MockSerializer : public SkPixelSerializer { 168 public: 169 MockSerializer(SkData* (*func)()) : fFunc(func), fDidEncode(false) { } 170 171 bool didEncode() const { return fDidEncode; } 172 173 protected: 174 bool onUseEncodedData(const void*, size_t) override { 175 return false; 176 } 177 178 SkData* onEncode(const SkPixmap&) override { 179 fDidEncode = true; 180 return fFunc(); 181 } 182 183 private: 184 SkData* (*fFunc)(); 185 bool fDidEncode; 186 187 typedef SkPixelSerializer INHERITED; 188 }; 189 190 } // anonymous namespace 191 192 // Test that SkImage encoding observes custom pixel serializers. 193 DEF_TEST(Image_Encode_Serializer, reporter) { 194 MockSerializer serializer([]() -> SkData* { return SkData::NewWithCString(kSerializedData); }); 195 SkAutoTUnref<SkImage> image(create_image()); 196 SkAutoTUnref<SkData> encoded(image->encode(&serializer)); 197 SkAutoTUnref<SkData> reference(SkData::NewWithCString(kSerializedData)); 198 199 REPORTER_ASSERT(reporter, serializer.didEncode()); 200 REPORTER_ASSERT(reporter, encoded); 201 REPORTER_ASSERT(reporter, encoded->size() > 0); 202 REPORTER_ASSERT(reporter, encoded->equals(reference)); 203 } 204 205 // Test that image encoding failures do not break picture serialization/deserialization. 206 DEF_TEST(Image_Serialize_Encoding_Failure, reporter) { 207 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100)); 208 surface->getCanvas()->clear(SK_ColorGREEN); 209 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 210 REPORTER_ASSERT(reporter, image); 211 212 SkPictureRecorder recorder; 213 SkCanvas* canvas = recorder.beginRecording(100, 100); 214 canvas->drawImage(image, 0, 0); 215 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 216 REPORTER_ASSERT(reporter, picture); 217 REPORTER_ASSERT(reporter, picture->approximateOpCount() > 0); 218 219 MockSerializer emptySerializer([]() -> SkData* { return SkData::NewEmpty(); }); 220 MockSerializer nullSerializer([]() -> SkData* { return nullptr; }); 221 MockSerializer* serializers[] = { &emptySerializer, &nullSerializer }; 222 223 for (size_t i = 0; i < SK_ARRAY_COUNT(serializers); ++i) { 224 SkDynamicMemoryWStream wstream; 225 REPORTER_ASSERT(reporter, !serializers[i]->didEncode()); 226 picture->serialize(&wstream, serializers[i]); 227 REPORTER_ASSERT(reporter, serializers[i]->didEncode()); 228 229 SkAutoTDelete<SkStream> rstream(wstream.detachAsStream()); 230 SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rstream)); 231 REPORTER_ASSERT(reporter, deserialized); 232 REPORTER_ASSERT(reporter, deserialized->approximateOpCount() > 0); 233 } 234 } 235 236 DEF_TEST(Image_NewRasterCopy, reporter) { 237 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0); 238 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0); 239 const SkPMColor blue = SkPackARGB32(0xFF, 0, 0, 0xFF); 240 SkPMColor colors[] = { red, green, blue, 0 }; 241 SkAutoTUnref<SkColorTable> ctable(new SkColorTable(colors, SK_ARRAY_COUNT(colors))); 242 // The colortable made a copy, so we can trash the original colors 243 memset(colors, 0xFF, sizeof(colors)); 244 245 const SkImageInfo srcInfo = SkImageInfo::Make(2, 2, kIndex_8_SkColorType, kPremul_SkAlphaType); 246 const size_t srcRowBytes = 2 * sizeof(uint8_t); 247 uint8_t indices[] = { 0, 1, 2, 3 }; 248 SkAutoTUnref<SkImage> image(SkImage::NewRasterCopy(srcInfo, indices, srcRowBytes, ctable)); 249 // The image made a copy, so we can trash the original indices 250 memset(indices, 0xFF, sizeof(indices)); 251 252 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2); 253 const size_t dstRowBytes = 2 * sizeof(SkPMColor); 254 SkPMColor pixels[4]; 255 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect 256 image->readPixels(dstInfo, pixels, dstRowBytes, 0, 0); 257 REPORTER_ASSERT(reporter, red == pixels[0]); 258 REPORTER_ASSERT(reporter, green == pixels[1]); 259 REPORTER_ASSERT(reporter, blue == pixels[2]); 260 REPORTER_ASSERT(reporter, 0 == pixels[3]); 261 } 262 263 // Test that a draw that only partially covers the drawing surface isn't 264 // interpreted as covering the entire drawing surface (i.e., exercise one of the 265 // conditions of SkCanvas::wouldOverwriteEntireSurface()). 266 DEF_TEST(Image_RetainSnapshot, reporter) { 267 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0); 268 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0); 269 SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2); 270 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info)); 271 surface->getCanvas()->clear(0xFF00FF00); 272 273 SkPMColor pixels[4]; 274 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect 275 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2); 276 const size_t dstRowBytes = 2 * sizeof(SkPMColor); 277 278 SkAutoTUnref<SkImage> image1(surface->newImageSnapshot()); 279 REPORTER_ASSERT(reporter, image1->readPixels(dstInfo, pixels, dstRowBytes, 0, 0)); 280 for (size_t i = 0; i < SK_ARRAY_COUNT(pixels); ++i) { 281 REPORTER_ASSERT(reporter, pixels[i] == green); 282 } 283 284 SkPaint paint; 285 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 286 paint.setColor(SK_ColorRED); 287 288 surface->getCanvas()->drawRect(SkRect::MakeXYWH(1, 1, 1, 1), paint); 289 290 SkAutoTUnref<SkImage> image2(surface->newImageSnapshot()); 291 REPORTER_ASSERT(reporter, image2->readPixels(dstInfo, pixels, dstRowBytes, 0, 0)); 292 REPORTER_ASSERT(reporter, pixels[0] == green); 293 REPORTER_ASSERT(reporter, pixels[1] == green); 294 REPORTER_ASSERT(reporter, pixels[2] == green); 295 REPORTER_ASSERT(reporter, pixels[3] == red); 296 } 297 298 ///////////////////////////////////////////////////////////////////////////////////////////////// 299 300 static void make_bitmap_mutable(SkBitmap* bm) { 301 bm->allocN32Pixels(10, 10); 302 } 303 304 static void make_bitmap_immutable(SkBitmap* bm) { 305 bm->allocN32Pixels(10, 10); 306 bm->setImmutable(); 307 } 308 309 DEF_TEST(image_newfrombitmap, reporter) { 310 const struct { 311 void (*fMakeProc)(SkBitmap*); 312 bool fExpectPeekSuccess; 313 bool fExpectSharedID; 314 bool fExpectLazy; 315 } rec[] = { 316 { make_bitmap_mutable, true, false, false }, 317 { make_bitmap_immutable, true, true, false }, 318 }; 319 320 for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) { 321 SkBitmap bm; 322 rec[i].fMakeProc(&bm); 323 324 SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bm)); 325 SkPixmap pmap; 326 327 const bool sharedID = (image->uniqueID() == bm.getGenerationID()); 328 REPORTER_ASSERT(reporter, sharedID == rec[i].fExpectSharedID); 329 330 const bool peekSuccess = image->peekPixels(&pmap); 331 REPORTER_ASSERT(reporter, peekSuccess == rec[i].fExpectPeekSuccess); 332 333 const bool lazy = image->isLazyGenerated(); 334 REPORTER_ASSERT(reporter, lazy == rec[i].fExpectLazy); 335 } 336 } 337 338 /////////////////////////////////////////////////////////////////////////////////////////////////// 339 #if SK_SUPPORT_GPU 340 341 #include "SkBitmapCache.h" 342 343 /* 344 * This tests the caching (and preemptive purge) of the raster equivalent of a gpu-image. 345 * We cache it for performance when drawing into a raster surface. 346 * 347 * A cleaner test would know if each drawImage call triggered a read-back from the gpu, 348 * but we don't have that facility (at the moment) so we use a little internal knowledge 349 * of *how* the raster version is cached, and look for that. 350 */ 351 DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_Gpu2Cpu, reporter, context) { 352 SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); 353 SkAutoTUnref<SkImage> image(create_gpu_image(context)); 354 const uint32_t uniqueID = image->uniqueID(); 355 356 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info)); 357 358 // now we can test drawing a gpu-backed image into a cpu-backed surface 359 360 { 361 SkBitmap cachedBitmap; 362 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap)); 363 } 364 365 surface->getCanvas()->drawImage(image, 0, 0); 366 { 367 SkBitmap cachedBitmap; 368 if (SkBitmapCache::Find(uniqueID, &cachedBitmap)) { 369 REPORTER_ASSERT(reporter, cachedBitmap.getGenerationID() == uniqueID); 370 REPORTER_ASSERT(reporter, cachedBitmap.isImmutable()); 371 REPORTER_ASSERT(reporter, cachedBitmap.getPixels()); 372 } else { 373 // unexpected, but not really a bug, since the cache is global and this test may be 374 // run w/ other threads competing for its budget. 375 SkDebugf("SkImage_Gpu2Cpu : cachedBitmap was already purged\n"); 376 } 377 } 378 379 image.reset(nullptr); 380 { 381 SkBitmap cachedBitmap; 382 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap)); 383 } 384 } 385 386 DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_newTextureImage, reporter, context, glContext) { 387 GrContextFactory otherFactory; 388 GrContextFactory::ContextInfo otherContextInfo = 389 otherFactory.getContextInfo(GrContextFactory::kNative_GLContextType); 390 glContext->makeCurrent(); 391 392 std::function<SkImage*()> imageFactories[] = { 393 create_image, 394 create_codec_image, 395 create_data_image, 396 // Create an image from a picture. 397 create_picture_image, 398 // Create a texture image. 399 [context] { return create_gpu_image(context); }, 400 // Create a texture image in a another GrContext. 401 [glContext, otherContextInfo] { 402 otherContextInfo.fGLContext->makeCurrent(); 403 SkImage* otherContextImage = create_gpu_image(otherContextInfo.fGrContext); 404 glContext->makeCurrent(); 405 return otherContextImage; 406 } 407 }; 408 409 for (auto factory : imageFactories) { 410 SkAutoTUnref<SkImage> image(factory()); 411 if (!image) { 412 ERRORF(reporter, "Error creating image."); 413 continue; 414 } 415 GrTexture* origTexture = as_IB(image)->peekTexture(); 416 417 SkAutoTUnref<SkImage> texImage(image->newTextureImage(context)); 418 if (!texImage) { 419 // We execpt to fail if image comes from a different GrContext. 420 if (!origTexture || origTexture->getContext() == context) { 421 ERRORF(reporter, "newTextureImage failed."); 422 } 423 continue; 424 } 425 GrTexture* copyTexture = as_IB(texImage)->peekTexture(); 426 if (!copyTexture) { 427 ERRORF(reporter, "newTextureImage returned non-texture image."); 428 continue; 429 } 430 if (origTexture) { 431 if (origTexture != copyTexture) { 432 ERRORF(reporter, "newTextureImage made unnecessary texture copy."); 433 } 434 } 435 if (image->width() != texImage->width() || image->height() != texImage->height()) { 436 ERRORF(reporter, "newTextureImage changed the image size."); 437 } 438 if (image->isOpaque() != texImage->isOpaque()) { 439 ERRORF(reporter, "newTextureImage changed image opaqueness."); 440 } 441 } 442 } 443 #endif 444 445 // https://bug.skia.org/4390 446 DEF_TEST(ImageFromIndex8Bitmap, r) { 447 SkPMColor pmColors[1] = {SkPreMultiplyColor(SK_ColorWHITE)}; 448 SkBitmap bm; 449 SkAutoTUnref<SkColorTable> ctable( 450 new SkColorTable(pmColors, SK_ARRAY_COUNT(pmColors))); 451 SkImageInfo info = 452 SkImageInfo::Make(1, 1, kIndex_8_SkColorType, kPremul_SkAlphaType); 453 bm.allocPixels(info, nullptr, ctable); 454 SkAutoLockPixels autoLockPixels(bm); 455 *bm.getAddr8(0, 0) = 0; 456 SkAutoTUnref<SkImage> img(SkImage::NewFromBitmap(bm)); 457 REPORTER_ASSERT(r, img.get() != nullptr); 458 } 459 460 class EmptyGenerator : public SkImageGenerator { 461 public: 462 EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {} 463 }; 464 465 DEF_TEST(ImageEmpty, reporter) { 466 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 467 REPORTER_ASSERT(reporter, nullptr == SkImage::NewRasterCopy(info, nullptr, 0)); 468 REPORTER_ASSERT(reporter, nullptr == SkImage::NewRasterData(info, nullptr, 0)); 469 REPORTER_ASSERT(reporter, nullptr == SkImage::NewFromRaster(info, nullptr, 0, nullptr, nullptr)); 470 REPORTER_ASSERT(reporter, nullptr == SkImage::NewFromGenerator(new EmptyGenerator)); 471 } 472 473 DEF_TEST(ImageDataRef, reporter) { 474 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 475 size_t rowBytes = info.minRowBytes(); 476 size_t size = info.getSafeSize(rowBytes); 477 SkData* data = SkData::NewUninitialized(size); 478 REPORTER_ASSERT(reporter, data->unique()); 479 SkImage* image = SkImage::NewRasterData(info, data, rowBytes); 480 REPORTER_ASSERT(reporter, !data->unique()); 481 image->unref(); 482 REPORTER_ASSERT(reporter, data->unique()); 483 data->unref(); 484 } 485 486 static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) { 487 for (int i = 0; i < count; ++i) { 488 if (pixels[i] != expected) { 489 return false; 490 } 491 } 492 return true; 493 } 494 495 static void test_read_pixels(skiatest::Reporter* reporter, SkImage* image) { 496 const SkPMColor expected = SkPreMultiplyColor(SK_ColorWHITE); 497 const SkPMColor notExpected = ~expected; 498 499 const int w = 2, h = 2; 500 const size_t rowBytes = w * sizeof(SkPMColor); 501 SkPMColor pixels[w*h]; 502 503 SkImageInfo info; 504 505 info = SkImageInfo::MakeUnknown(w, h); 506 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0)); 507 508 // out-of-bounds should fail 509 info = SkImageInfo::MakeN32Premul(w, h); 510 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0)); 511 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h)); 512 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0)); 513 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height())); 514 515 // top-left should succeed 516 sk_memset32(pixels, notExpected, w*h); 517 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0)); 518 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); 519 520 // bottom-right should succeed 521 sk_memset32(pixels, notExpected, w*h); 522 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 523 image->width() - w, image->height() - h)); 524 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); 525 526 // partial top-left should succeed 527 sk_memset32(pixels, notExpected, w*h); 528 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1)); 529 REPORTER_ASSERT(reporter, pixels[3] == expected); 530 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected)); 531 532 // partial bottom-right should succeed 533 sk_memset32(pixels, notExpected, w*h); 534 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 535 image->width() - 1, image->height() - 1)); 536 REPORTER_ASSERT(reporter, pixels[0] == expected); 537 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected)); 538 } 539 DEF_TEST(ImageReadPixels, reporter) { 540 SkAutoTUnref<SkImage> image(create_image()); 541 test_read_pixels(reporter, image); 542 543 image.reset(create_data_image()); 544 test_read_pixels(reporter, image); 545 546 RasterDataHolder dataHolder; 547 image.reset(create_rasterproc_image(&dataHolder)); 548 test_read_pixels(reporter, image); 549 image.reset(); 550 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount); 551 552 image.reset(create_codec_image()); 553 test_read_pixels(reporter, image); 554 } 555 #if SK_SUPPORT_GPU 556 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageReadPixels_Gpu, reporter, context) { 557 SkAutoTUnref<SkImage> image(create_gpu_image(context)); 558 test_read_pixels(reporter, image); 559 } 560 #endif 561 562 static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image, 563 const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) { 564 REPORTER_ASSERT(reporter, image->width() == bitmap.width()); 565 REPORTER_ASSERT(reporter, image->height() == bitmap.height()); 566 REPORTER_ASSERT(reporter, image->isOpaque() == bitmap.isOpaque()); 567 568 if (SkImage::kRO_LegacyBitmapMode == mode) { 569 REPORTER_ASSERT(reporter, bitmap.isImmutable()); 570 } 571 572 SkAutoLockPixels alp(bitmap); 573 REPORTER_ASSERT(reporter, bitmap.getPixels()); 574 575 const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType()); 576 SkPMColor imageColor; 577 REPORTER_ASSERT(reporter, image->readPixels(info, &imageColor, sizeof(SkPMColor), 0, 0)); 578 REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0)); 579 } 580 581 static void test_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image, SkImage::LegacyBitmapMode mode) { 582 SkBitmap bitmap; 583 REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap, mode)); 584 check_legacy_bitmap(reporter, image, bitmap, mode); 585 586 // Test subsetting to exercise the rowBytes logic. 587 SkBitmap tmp; 588 REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2, 589 image->height() / 2))); 590 SkAutoTUnref<SkImage> subsetImage(SkImage::NewFromBitmap(tmp)); 591 REPORTER_ASSERT(reporter, subsetImage); 592 593 SkBitmap subsetBitmap; 594 REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap, mode)); 595 check_legacy_bitmap(reporter, subsetImage, subsetBitmap, mode); 596 } 597 DEF_TEST(ImageLegacyBitmap, reporter) { 598 const SkImage::LegacyBitmapMode modes[] = { 599 SkImage::kRO_LegacyBitmapMode, 600 SkImage::kRW_LegacyBitmapMode, 601 }; 602 for (auto& mode : modes) { 603 SkAutoTUnref<SkImage> image(create_image()); 604 test_legacy_bitmap(reporter, image, mode); 605 606 image.reset(create_data_image()); 607 test_legacy_bitmap(reporter, image, mode); 608 609 RasterDataHolder dataHolder; 610 image.reset(create_rasterproc_image(&dataHolder)); 611 test_legacy_bitmap(reporter, image, mode); 612 image.reset(); 613 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount); 614 615 image.reset(create_codec_image()); 616 test_legacy_bitmap(reporter, image, mode); 617 } 618 } 619 #if SK_SUPPORT_GPU 620 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageLegacyBitmap_Gpu, reporter, context) { 621 const SkImage::LegacyBitmapMode modes[] = { 622 SkImage::kRO_LegacyBitmapMode, 623 SkImage::kRW_LegacyBitmapMode, 624 }; 625 for (auto& mode : modes) { 626 SkAutoTUnref<SkImage> image(create_gpu_image(context)); 627 test_legacy_bitmap(reporter, image, mode); 628 } 629 } 630 #endif 631 632 static void test_peek(skiatest::Reporter* reporter, SkImage* image, bool expectPeekSuccess) { 633 SkImageInfo info; 634 size_t rowBytes; 635 const void* addr = image->peekPixels(&info, &rowBytes); 636 bool success = SkToBool(addr); 637 REPORTER_ASSERT(reporter, expectPeekSuccess == success); 638 if (success) { 639 REPORTER_ASSERT(reporter, 20 == info.width()); 640 REPORTER_ASSERT(reporter, 20 == info.height()); 641 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType()); 642 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() || 643 kOpaque_SkAlphaType == info.alphaType()); 644 REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes); 645 REPORTER_ASSERT(reporter, SkPreMultiplyColor(SK_ColorWHITE) == *(const SkPMColor*)addr); 646 } 647 } 648 DEF_TEST(ImagePeek, reporter) { 649 SkAutoTUnref<SkImage> image(create_image()); 650 test_peek(reporter, image, true); 651 652 image.reset(create_data_image()); 653 test_peek(reporter, image, true); 654 655 RasterDataHolder dataHolder; 656 image.reset(create_rasterproc_image(&dataHolder)); 657 test_peek(reporter, image, true); 658 image.reset(); 659 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount); 660 661 image.reset(create_codec_image()); 662 test_peek(reporter, image, false); 663 } 664 #if SK_SUPPORT_GPU 665 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImagePeek_Gpu, reporter, context) { 666 SkAutoTUnref<SkImage> image(create_gpu_image(context)); 667 test_peek(reporter, image, false); 668 } 669 #endif 670 671 #if SK_SUPPORT_GPU 672 struct TextureReleaseChecker { 673 TextureReleaseChecker() : fReleaseCount(0) {} 674 int fReleaseCount; 675 static void Release(void* self) { 676 static_cast<TextureReleaseChecker*>(self)->fReleaseCount++; 677 } 678 }; 679 static void check_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) { 680 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 681 SkPMColor pixel; 682 REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0)); 683 REPORTER_ASSERT(reporter, pixel == expected); 684 } 685 DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_NewFromTexture, reporter, context) { 686 GrTextureProvider* provider = context->textureProvider(); 687 const int w = 10; 688 const int h = 10; 689 SkPMColor storage[w * h]; 690 const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED); 691 sk_memset32(storage, expected0, w * h); 692 GrSurfaceDesc desc; 693 desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels(); 694 desc.fOrigin = kDefault_GrSurfaceOrigin; 695 desc.fWidth = w; 696 desc.fHeight = h; 697 desc.fConfig = kSkia8888_GrPixelConfig; 698 desc.fSampleCnt = 0; 699 SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, SkBudgeted::kNo, storage, w * 4)); 700 if (!tex) { 701 REPORTER_ASSERT(reporter, false); 702 return; 703 } 704 705 GrBackendTextureDesc backendDesc; 706 backendDesc.fConfig = kSkia8888_GrPixelConfig; 707 backendDesc.fFlags = kRenderTarget_GrBackendTextureFlag; 708 backendDesc.fWidth = w; 709 backendDesc.fHeight = h; 710 backendDesc.fSampleCnt = 0; 711 backendDesc.fTextureHandle = tex->getTextureHandle(); 712 TextureReleaseChecker releaseChecker; 713 SkAutoTUnref<SkImage> refImg( 714 SkImage::NewFromTexture(context, backendDesc, kPremul_SkAlphaType, 715 TextureReleaseChecker::Release, &releaseChecker)); 716 SkAutoTUnref<SkImage> cpyImg(SkImage::NewFromTextureCopy(context, backendDesc, 717 kPremul_SkAlphaType)); 718 719 check_image_color(reporter, refImg, expected0); 720 check_image_color(reporter, cpyImg, expected0); 721 722 // Now lets jam new colors into our "external" texture, and see if the images notice 723 const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE); 724 sk_memset32(storage, expected1, w * h); 725 tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp); 726 727 // The cpy'd one should still see the old color 728 #if 0 729 // There is no guarantee that refImg sees the new color. We are free to have made a copy. Our 730 // write pixels call violated the contract with refImg and refImg is now undefined. 731 check_image_color(reporter, refImg, expected1); 732 #endif 733 check_image_color(reporter, cpyImg, expected0); 734 735 // Now exercise the release proc 736 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 737 refImg.reset(nullptr); // force a release of the image 738 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 739 } 740 #endif 741