Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ImageTest.cpp
Go to the documentation of this file.
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
16#include "include/core/SkData.h"
21#include "include/core/SkM44.h"
26#include "include/core/SkRect.h"
31#include "include/core/SkSize.h"
41#include "include/gpu/GrTypes.h"
52#include "modules/skcms/skcms.h"
57#include "src/core/SkMemset.h"
58#include "src/gpu/ResourceKey.h"
72#include "tests/Test.h"
73#include "tools/DecodeUtils.h"
74#include "tools/Resources.h"
75#include "tools/ToolUtils.h"
76#include "tools/gpu/FenceSync.h"
80
81#include <algorithm>
82#include <cmath>
83#include <cstdint>
84#include <cstring>
85#include <functional>
86#include <initializer_list>
87#include <memory>
88#include <tuple>
89#include <utility>
90#include <vector>
91
94struct GrContextOptions;
95
96using namespace sk_gpu_test;
97
105
106// image `b` is assumed to be raster
108 const SkIRect* subsetA, SkImage* b) {
109 const int widthA = subsetA ? subsetA->width() : a->width();
110 const int heightA = subsetA ? subsetA->height() : a->height();
111
112 REPORTER_ASSERT(reporter, widthA == b->width());
113 REPORTER_ASSERT(reporter, heightA == b->height());
114
115 // see https://bug.skia.org/3965
116 //REPORTER_ASSERT(reporter, a->isOpaque() == b->isOpaque());
117
118 SkAutoPixmapStorage pmapA, pmapB;
119 pmapA.alloc(read_pixels_info(a));
120 pmapB.alloc(read_pixels_info(b));
121
122 const int srcX = subsetA ? subsetA->x() : 0;
123 const int srcY = subsetA ? subsetA->y() : 0;
124
125 REPORTER_ASSERT(reporter, a->readPixels(dContextA, pmapA, srcX, srcY));
126 REPORTER_ASSERT(reporter, b->readPixels(nullptr, pmapB, 0, 0));
127
128 const size_t widthBytes = widthA * 4;
129 for (int y = 0; y < heightA; ++y) {
130 REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes));
131 }
132}
133static void draw_image_test_pattern(SkCanvas* canvas) {
134 canvas->clear(SK_ColorWHITE);
136 paint.setColor(SK_ColorBLACK);
137 canvas->drawRect(SkRect::MakeXYWH(5, 5, 10, 10), paint);
138}
142 draw_image_test_pattern(surface->getCanvas());
143 return surface->makeImageSnapshot();
144}
147 const size_t rowBytes = info->minRowBytes();
148 sk_sp<SkData> data(SkData::MakeUninitialized(rowBytes * info->height()));
149 {
150 SkBitmap bm;
151 bm.installPixels(*info, data->writable_data(), rowBytes);
152 SkCanvas canvas(bm);
154 }
155 return data;
156}
160 return SkImages::RasterFromData(info, std::move(data), info.minRowBytes());
161}
162static sk_sp<SkImage> create_image_large(int maxTextureSize) {
163 const SkImageInfo info = SkImageInfo::MakeN32(maxTextureSize + 1, 32, kOpaque_SkAlphaType);
165 surface->getCanvas()->clear(SK_ColorWHITE);
167 paint.setColor(SK_ColorBLACK);
168 surface->getCanvas()->drawRect(SkRect::MakeXYWH(4000, 2, 28000, 30), paint);
169 return surface->makeImageSnapshot();
170}
172 SkPictureRecorder recorder;
173 SkCanvas* canvas = recorder.beginRecording(10, 10);
174 canvas->clear(SK_ColorCYAN);
176 SkISize::Make(10, 10),
177 nullptr,
178 nullptr,
181}
182// Want to ensure that our Release is called when the owning image is destroyed
187 static void Release(const void* pixels, void* context) {
188 RasterDataHolder* self = static_cast<RasterDataHolder*>(context);
190 self->fData.reset();
191 }
192};
194 SkASSERT(dataHolder);
196 dataHolder->fData = create_image_data(&info);
197 return SkImages::RasterFromPixmap(SkPixmap(info, dataHolder->fData->data(), info.minRowBytes()),
199 dataHolder);
200}
205 bitmap.installPixels(info, data->writable_data(), info.minRowBytes());
207 SkASSERT_RELEASE(SkPngEncoder::Encode(&stream, bitmap.pixmap(), {}));
208 return SkImages::DeferredFromEncodedData(stream.detachAsData());
209}
211 bool withMips = false,
215 rContext, budgeted, info, 0, kBottomLeft_GrSurfaceOrigin, nullptr, withMips);
216 draw_image_test_pattern(surface->getCanvas());
217 return surface->makeImageSnapshot();
218}
219
221 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10);
222 sk_sp<SkData> origEncoded = SkPngEncoder::Encode(dContext, image, {});
223 REPORTER_ASSERT(reporter, origEncoded);
224 REPORTER_ASSERT(reporter, origEncoded->size() > 0);
225
227 if (!decoded) {
228 ERRORF(reporter, "failed to decode image!");
229 return;
230 }
231 REPORTER_ASSERT(reporter, decoded);
232 assert_equal(reporter, dContext, image, nullptr, decoded.get());
233
234 // Now see if we can instantiate an image from a subset of the surface/origEncoded
235
236 decoded = SkImages::DeferredFromEncodedData(origEncoded)->makeSubset(nullptr, ir);
237 REPORTER_ASSERT(reporter, decoded);
238 assert_equal(reporter, dContext, image, &ir, decoded.get());
239}
240
241DEF_TEST(ImageEncode, reporter) {
242 test_encode(reporter, nullptr, create_image().get());
243}
244
246 reporter,
247 ctxInfo,
249 auto dContext = ctxInfo.directContext();
250 test_encode(reporter, dContext, create_gpu_image(dContext).get());
251}
252
253DEF_TEST(Image_MakeFromRasterBitmap, reporter) {
254 const struct {
255 SkCopyPixelsMode fCPM;
256 bool fExpectSameAsMutable;
257 bool fExpectSameAsImmutable;
258 } recs[] = {
259 { kIfMutable_SkCopyPixelsMode, false, true },
260 { kAlways_SkCopyPixelsMode, false, false },
261 { kNever_SkCopyPixelsMode, true, true },
262 };
263 for (auto rec : recs) {
264 SkPixmap pm;
265 SkBitmap bm;
266 bm.allocN32Pixels(100, 100);
267
268 auto img = SkMakeImageFromRasterBitmap(bm, rec.fCPM);
269 REPORTER_ASSERT(reporter, img->peekPixels(&pm));
270 const bool sameMutable = pm.addr32(0, 0) == bm.getAddr32(0, 0);
271 REPORTER_ASSERT(reporter, rec.fExpectSameAsMutable == sameMutable);
272 REPORTER_ASSERT(reporter, (bm.getGenerationID() == img->uniqueID()) == sameMutable);
273
274 bm.notifyPixelsChanged(); // force a new generation ID
275
276 bm.setImmutable();
277 img = SkMakeImageFromRasterBitmap(bm, rec.fCPM);
278 REPORTER_ASSERT(reporter, img->peekPixels(&pm));
279 const bool sameImmutable = pm.addr32(0, 0) == bm.getAddr32(0, 0);
280 REPORTER_ASSERT(reporter, rec.fExpectSameAsImmutable == sameImmutable);
281 REPORTER_ASSERT(reporter, (bm.getGenerationID() == img->uniqueID()) == sameImmutable);
282 }
283}
284
285// Test that image encoding failures do not break picture serialization/deserialization.
286DEF_TEST(Image_Serialize_Encoding_Failure, reporter) {
288 surface->getCanvas()->clear(SK_ColorGREEN);
289 sk_sp<SkImage> image(surface->makeImageSnapshot());
291
292 SkPictureRecorder recorder;
293 SkCanvas* canvas = recorder.beginRecording(100, 100);
294 canvas->drawImage(image.get(), 0, 0, SkSamplingOptions());
295 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
296 REPORTER_ASSERT(reporter, picture);
298
299 bool was_called = false;
300 SkSerialProcs procs;
301 procs.fImageProc = [](SkImage*, void* called) {
302 *(bool*)called = true;
303 return SkData::MakeEmpty();
304 };
305 procs.fImageCtx = &was_called;
306
307 REPORTER_ASSERT(reporter, !was_called);
308 auto data = picture->serialize(&procs);
309 REPORTER_ASSERT(reporter, was_called);
310 REPORTER_ASSERT(reporter, data && data->size() > 0);
311
312 auto deserialized = SkPicture::MakeFromData(data->data(), data->size());
313 REPORTER_ASSERT(reporter, deserialized);
314 REPORTER_ASSERT(reporter, deserialized->approximateOpCount() > 0);
315}
316
317// Test that a draw that only partially covers the drawing surface isn't
318// interpreted as covering the entire drawing surface (i.e., exercise one of the
319// conditions of SkCanvas::wouldOverwriteEntireSurface()).
320DEF_TEST(Image_RetainSnapshot, reporter) {
321 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0);
322 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
325 surface->getCanvas()->clear(0xFF00FF00);
326
327 SkPMColor pixels[4];
328 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect
329 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2);
330 const size_t dstRowBytes = 2 * sizeof(SkPMColor);
331
332 sk_sp<SkImage> image1(surface->makeImageSnapshot());
333 REPORTER_ASSERT(reporter, image1->readPixels(nullptr, dstInfo, pixels, dstRowBytes, 0, 0));
334 for (size_t i = 0; i < std::size(pixels); ++i) {
335 REPORTER_ASSERT(reporter, pixels[i] == green);
336 }
337
339 paint.setBlendMode(SkBlendMode::kSrc);
340 paint.setColor(SK_ColorRED);
341
342 surface->getCanvas()->drawRect(SkRect::MakeXYWH(1, 1, 1, 1), paint);
343
344 sk_sp<SkImage> image2(surface->makeImageSnapshot());
345 REPORTER_ASSERT(reporter, image2->readPixels(nullptr, dstInfo, pixels, dstRowBytes, 0, 0));
346 REPORTER_ASSERT(reporter, pixels[0] == green);
347 REPORTER_ASSERT(reporter, pixels[1] == green);
348 REPORTER_ASSERT(reporter, pixels[2] == green);
349 REPORTER_ASSERT(reporter, pixels[3] == red);
350}
351
352/////////////////////////////////////////////////////////////////////////////////////////////////
353
355 bm->allocN32Pixels(10, 10);
356}
357
359 bm->allocN32Pixels(10, 10);
360 bm->setImmutable();
361}
362
363DEF_TEST(image_newfrombitmap, reporter) {
364 const struct {
365 void (*fMakeProc)(SkBitmap*);
366 bool fExpectPeekSuccess;
367 bool fExpectSharedID;
368 bool fExpectLazy;
369 } rec[] = {
370 { make_bitmap_mutable, true, false, false },
371 { make_bitmap_immutable, true, true, false },
372 };
373
374 for (size_t i = 0; i < std::size(rec); ++i) {
375 SkBitmap bm;
376 rec[i].fMakeProc(&bm);
377
379 SkPixmap pmap;
380
381 const bool sharedID = (image->uniqueID() == bm.getGenerationID());
382 REPORTER_ASSERT(reporter, sharedID == rec[i].fExpectSharedID);
383
384 const bool peekSuccess = image->peekPixels(&pmap);
385 REPORTER_ASSERT(reporter, peekSuccess == rec[i].fExpectPeekSuccess);
386
387 const bool lazy = image->isLazyGenerated();
388 REPORTER_ASSERT(reporter, lazy == rec[i].fExpectLazy);
389 }
390}
391
392///////////////////////////////////////////////////////////////////////////////////////////////////
393
394/*
395 * This tests the caching (and preemptive purge) of the raster equivalent of a gpu-image.
396 * We cache it for performance when drawing into a raster surface.
397 *
398 * A cleaner test would know if each drawImage call triggered a read-back from the gpu,
399 * but we don't have that facility (at the moment) so we use a little internal knowledge
400 * of *how* the raster version is cached, and look for that.
401 */
403 reporter,
404 ctxInfo,
407 sk_sp<SkImage> image(create_gpu_image(ctxInfo.directContext()));
408 const auto desc = SkBitmapCacheDesc::Make(image.get());
409
411
412 // now we can test drawing a gpu-backed image into a cpu-backed surface
413
414 {
415 SkBitmap cachedBitmap;
416 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(desc, &cachedBitmap));
417 }
418
419 surface->getCanvas()->drawImage(image, 0, 0);
420 {
421 SkBitmap cachedBitmap;
422 if (SkBitmapCache::Find(desc, &cachedBitmap)) {
423 REPORTER_ASSERT(reporter, cachedBitmap.isImmutable());
424 REPORTER_ASSERT(reporter, cachedBitmap.getPixels());
425 } else {
426 // unexpected, but not really a bug, since the cache is global and this test may be
427 // run w/ other threads competing for its budget.
428 SkDebugf("SkImage_Ganesh2Cpu : cachedBitmap was already purged\n");
429 }
430 }
431
432 image.reset(nullptr);
433 {
434 SkBitmap cachedBitmap;
435 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(desc, &cachedBitmap));
436 }
437}
438
440 reporter,
441 contextInfo,
443 auto dContext = contextInfo.directContext();
444 sk_gpu_test::TestContext* testContext = contextInfo.testContext();
445 GrContextFactory otherFactory;
446 ContextInfo otherContextInfo = otherFactory.getContextInfo(contextInfo.type());
447 testContext->makeCurrent();
448 std::function<sk_sp<SkImage>()> imageFactories[] = {
452 // Create an image from a picture.
454 // Create a texture image.
455 [dContext] { return create_gpu_image(dContext, true, skgpu::Budgeted::kYes); },
456 [dContext] { return create_gpu_image(dContext, false, skgpu::Budgeted::kNo); },
457 // Create a texture image in a another context.
458 [otherContextInfo] {
459 auto restore = otherContextInfo.testContext()->makeCurrentAndAutoRestore();
460 auto otherContextImage = create_gpu_image(otherContextInfo.directContext());
461 otherContextInfo.directContext()->flushAndSubmit();
462 return otherContextImage;
463 }};
464 for (auto mipmapped : {skgpu::Mipmapped::kNo, skgpu::Mipmapped::kYes}) {
465 for (const auto& factory : imageFactories) {
466 sk_sp<SkImage> image(factory());
467 if (!image) {
468 ERRORF(reporter, "Error creating image.");
469 continue;
470 }
471 GrTextureProxy* origProxy = nullptr;
472 bool origIsMippedTexture = false;
473
474 if ((origProxy = sk_gpu_test::GetTextureImageProxy(image.get(), dContext))) {
476 reporter,
477 (origProxy->mipmapped() == skgpu::Mipmapped::kYes) == image->hasMipmaps());
478 origIsMippedTexture = image->hasMipmaps();
479 }
480 for (auto budgeted : {skgpu::Budgeted::kNo, skgpu::Budgeted::kYes}) {
481 auto texImage = SkImages::TextureFromImage(dContext, image, mipmapped, budgeted);
482 if (!texImage) {
483 auto imageContext = as_IB(image)->context();
484 // We expect to fail if image comes from a different context
485 if (!image->isTextureBacked() || imageContext->priv().matches(dContext)) {
486 ERRORF(reporter, "makeTextureImage failed.");
487 }
488 continue;
489 }
490 if (!texImage->isTextureBacked()) {
491 ERRORF(reporter, "makeTextureImage returned non-texture image.");
492 continue;
493 }
494
495 GrTextureProxy* copyProxy = sk_gpu_test::GetTextureImageProxy(texImage.get(),
496 dContext);
497 SkASSERT(copyProxy);
498 // Did we ask for MIPs on a context that supports them?
499 bool validRequestForMips = (mipmapped == skgpu::Mipmapped::kYes &&
500 dContext->priv().caps()->mipmapSupport());
501 // Do we expect the "copy" to have MIPs?
502 bool shouldBeMipped = origIsMippedTexture || validRequestForMips;
503 REPORTER_ASSERT(reporter, shouldBeMipped == texImage->hasMipmaps());
505 reporter,
506 shouldBeMipped == (copyProxy->mipmapped() == skgpu::Mipmapped::kYes));
507
508 // We should only make a copy of an already texture-backed image if it didn't
509 // already have MIPs but we asked for MIPs and the context supports it.
510 if (image->isTextureBacked() && (!validRequestForMips || origIsMippedTexture)) {
511 if (origProxy->underlyingUniqueID() != copyProxy->underlyingUniqueID()) {
512 ERRORF(reporter, "makeTextureImage made unnecessary texture copy.");
513 }
514 } else {
515 GrTextureProxy* texProxy = sk_gpu_test::GetTextureImageProxy(texImage.get(),
516 dContext);
518 REPORTER_ASSERT(reporter, texProxy->isBudgeted() == budgeted);
519 }
520 if (image->width() != texImage->width() || image->height() != texImage->height()) {
521 ERRORF(reporter, "makeTextureImage changed the image size.");
522 }
523 if (image->alphaType() != texImage->alphaType()) {
524 ERRORF(reporter, "makeTextureImage changed image alpha type.");
525 }
526 }
527 }
528 }
529 dContext->flushAndSubmit();
530}
531
532DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkImage_makeNonTextureImage,
533 reporter,
534 contextInfo,
536 auto dContext = contextInfo.directContext();
537
538 std::function<sk_sp<SkImage>()> imageFactories[] = {
543 [dContext] { return create_gpu_image(dContext); },
544 };
545 for (const auto& factory : imageFactories) {
546 sk_sp<SkImage> image = factory();
547 if (!image->isTextureBacked()) {
549 if (!(image = SkImages::TextureFromImage(dContext, image))) {
550 continue;
551 }
552 }
553 auto rasterImage = image->makeNonTextureImage();
554 if (!rasterImage) {
555 ERRORF(reporter, "makeNonTextureImage failed for texture-backed image.");
556 }
557 REPORTER_ASSERT(reporter, !rasterImage->isTextureBacked());
558 assert_equal(reporter, dContext, image.get(), nullptr, rasterImage.get());
559 }
560}
561
562DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsImage,
563 reporter,
564 ctxInfo,
566 using namespace skgpu;
567
568 auto dContext = ctxInfo.directContext();
569
570 Protected isProtected = Protected(dContext->priv().caps()->supportsProtectedContent());
571
572 static constexpr int kSize = 10;
573
574 for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) {
575 SkColorType colorType = static_cast<SkColorType>(ct);
576 bool can = dContext->colorTypeSupportedAsImage(colorType);
577
578 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
579 dContext, kSize, kSize, colorType, skgpu::Mipmapped::kNo, GrRenderable::kNo,
580 isProtected);
581 sk_sp<SkImage> img;
582 if (mbet) {
583 img = SkImages::BorrowTextureFrom(dContext,
584 mbet->texture(),
586 colorType,
588 nullptr);
589 }
590 REPORTER_ASSERT(reporter, can == SkToBool(img),
591 "colorTypeSupportedAsImage:%d, actual:%d, ct:%d", can, SkToBool(img),
592 colorType);
593 }
594}
595
597 reporter,
598 ctxInfo,
600 SkBitmap bmp;
601 bmp.allocPixels(
603 for (int y = 0; y < 256; ++y) {
604 for (int x = 0; x < 256; ++x) {
605 *bmp.getAddr32(x, y) =
606 SkColorSetARGB((U8CPU)y, 255 - (U8CPU)y, (U8CPU)x, 255 - (U8CPU)x);
607 }
608 }
609 auto dContext = ctxInfo.directContext();
610 auto texImage = SkImages::TextureFromImage(dContext, bmp.asImage());
611 if (!texImage || texImage->alphaType() != kUnpremul_SkAlphaType) {
612 ERRORF(reporter, "Failed to make unpremul texture image.");
613 return;
614 }
615 SkBitmap unpremul;
617 kUnpremul_SkAlphaType, nullptr));
618 if (!texImage->readPixels(dContext, unpremul.info(), unpremul.getPixels(), unpremul.rowBytes(),
619 0, 0)) {
620 ERRORF(reporter, "Unpremul readback failed.");
621 return;
622 }
623 for (int y = 0; y < 256; ++y) {
624 for (int x = 0; x < 256; ++x) {
625 if (*bmp.getAddr32(x, y) != *unpremul.getAddr32(x, y)) {
626 ERRORF(reporter, "unpremul(0x%08x)->unpremul(0x%08x) at %d, %d.",
627 *bmp.getAddr32(x, y), *unpremul.getAddr32(x, y), x, y);
628 return;
629 }
630 }
631 }
635 if (!texImage->readPixels(dContext, premul.info(), premul.getPixels(), premul.rowBytes(),
636 0, 0)) {
637 ERRORF(reporter, "Unpremul readback failed.");
638 return;
639 }
640 for (int y = 0; y < 256; ++y) {
641 for (int x = 0; x < 256; ++x) {
642 uint32_t origColor = *bmp.getAddr32(x, y);
643 int32_t origA = (origColor >> 24) & 0xff;
644 float a = origA / 255.f;
645 int32_t origB = sk_float_round2int(((origColor >> 16) & 0xff) * a);
646 int32_t origG = sk_float_round2int(((origColor >> 8) & 0xff) * a);
647 int32_t origR = sk_float_round2int(((origColor >> 0) & 0xff) * a);
648
649 uint32_t read = *premul.getAddr32(x, y);
650 int32_t readA = (read >> 24) & 0xff;
651 int32_t readB = (read >> 16) & 0xff;
652 int32_t readG = (read >> 8) & 0xff;
653 int32_t readR = (read >> 0) & 0xff;
654 // We expect that alpha=1 and alpha=0 should come out exact. Otherwise allow a little
655 // bit of tolerance for GPU vs CPU premul math.
656 int32_t tol = (origA == 0 || origA == 255) ? 0 : 1;
657 if (origA != readA || SkTAbs(readB - origB) > tol || SkTAbs(readG - origG) > tol ||
658 SkTAbs(readR - origR) > tol) {
659 ERRORF(reporter, "unpremul(0x%08x)->premul(0x%08x) expected(0x%08x) at %d, %d.",
660 *bmp.getAddr32(x, y), *premul.getAddr32(x, y), origColor, x, y);
661 return;
662 }
663 }
664 }
665}
666
668 using Factory = sk_gpu_test::GrContextFactory;
669 for (int ct = 0; ct < skgpu::kContextTypeCount; ++ct) {
670 auto type = static_cast<Factory::ContextType>(ct);
671 std::unique_ptr<Factory> factory(new Factory);
672 if (!factory->get(type)) {
673 continue;
674 }
675
676 sk_sp<SkImage> img;
677 auto gsurf = SkSurfaces::RenderTarget(
678 factory->get(type),
681 1,
682 nullptr);
683 if (!gsurf) {
684 continue;
685 }
686 img = gsurf->makeImageSnapshot();
687 gsurf.reset();
688
689 auto rsurf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100));
690
691 REPORTER_ASSERT(reporter, img->isValid(factory->get(type)));
692 REPORTER_ASSERT(reporter, img->isValid(rsurf->getCanvas()->recordingContext()));
693
694 factory->get(type)->abandonContext();
695 REPORTER_ASSERT(reporter, !img->isValid(factory->get(type)));
696 REPORTER_ASSERT(reporter, !img->isValid(rsurf->getCanvas()->recordingContext()));
697 // This shouldn't crash.
698 rsurf->getCanvas()->drawImage(img, 0, 0);
699
700 // Give up all other refs on the context.
701 factory.reset(nullptr);
702 REPORTER_ASSERT(reporter, !img->isValid(rsurf->getCanvas()->recordingContext()));
703 // This shouldn't crash.
704 rsurf->getCanvas()->drawImage(img, 0, 0);
705 }
706}
707
709public:
710 EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {}
711};
712
713DEF_TEST(ImageEmpty, reporter) {
714 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
715 SkPixmap pmap(info, nullptr, 0);
717 REPORTER_ASSERT(reporter, nullptr == SkImages::RasterFromData(info, nullptr, 0));
718 REPORTER_ASSERT(reporter, nullptr == SkImages::RasterFromPixmap(pmap, nullptr, nullptr));
720 nullptr == SkImages::DeferredFromGenerator(std::make_unique<EmptyGenerator>()));
721}
722
723DEF_TEST(ImageDataRef, reporter) {
725 size_t rowBytes = info.minRowBytes();
726 size_t size = info.computeByteSize(rowBytes);
728 REPORTER_ASSERT(reporter, data->unique());
730 REPORTER_ASSERT(reporter, !data->unique());
731 image.reset();
732 REPORTER_ASSERT(reporter, data->unique());
733}
734
735static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
736 for (int i = 0; i < count; ++i) {
737 if (pixels[i] != expected) {
738 return false;
739 }
740 }
741 return true;
742}
743
745 SkImage* image) {
746 if (!image) {
747 ERRORF(reporter, "Failed to create image!");
748 return;
749 }
751 const SkPMColor notExpected = ~expected;
752
753 const int w = 2, h = 2;
754 const size_t rowBytes = w * sizeof(SkPMColor);
755 SkPMColor pixels[w*h];
756
758
760 REPORTER_ASSERT(reporter, !image->readPixels(dContext, info, pixels, rowBytes, 0, 0));
761
762 // out-of-bounds should fail
764 REPORTER_ASSERT(reporter, !image->readPixels(dContext, info, pixels, rowBytes, -w, 0));
765 REPORTER_ASSERT(reporter, !image->readPixels(dContext, info, pixels, rowBytes, 0, -h));
766 REPORTER_ASSERT(reporter, !image->readPixels(dContext, info, pixels, rowBytes,
767 image->width(), 0));
768 REPORTER_ASSERT(reporter, !image->readPixels(dContext, info, pixels, rowBytes,
769 0, image->height()));
770
771 // top-left should succeed
772 SkOpts::memset32(pixels, notExpected, w*h);
773 REPORTER_ASSERT(reporter, image->readPixels(dContext, info, pixels, rowBytes, 0, 0));
774 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
775
776 // bottom-right should succeed
777 SkOpts::memset32(pixels, notExpected, w*h);
778 REPORTER_ASSERT(reporter, image->readPixels(dContext, info, pixels, rowBytes,
779 image->width() - w, image->height() - h));
780 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
781
782 // partial top-left should succeed
783 SkOpts::memset32(pixels, notExpected, w*h);
784 REPORTER_ASSERT(reporter, image->readPixels(dContext, info, pixels, rowBytes, -1, -1));
785 REPORTER_ASSERT(reporter, pixels[3] == expected);
786 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
787
788 // partial bottom-right should succeed
789 SkOpts::memset32(pixels, notExpected, w*h);
790 REPORTER_ASSERT(reporter, image->readPixels(dContext, info, pixels, rowBytes,
791 image->width() - 1, image->height() - 1));
792 REPORTER_ASSERT(reporter, pixels[0] == expected);
793 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
794}
795DEF_TEST(ImageReadPixels, reporter) {
798
801
802 RasterDataHolder dataHolder;
803 image = create_rasterproc_image(&dataHolder);
805 image.reset();
806 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
807
810}
812 reporter,
813 ctxInfo,
815 auto dContext = ctxInfo.directContext();
816 image_test_read_pixels(dContext, reporter, create_gpu_image(dContext).get());
817}
818
820 const SkImage* image, const SkBitmap& bitmap) {
821 REPORTER_ASSERT(reporter, image->width() == bitmap.width());
822 REPORTER_ASSERT(reporter, image->height() == bitmap.height());
823 REPORTER_ASSERT(reporter, image->alphaType() == bitmap.alphaType());
824
825 REPORTER_ASSERT(reporter, bitmap.isImmutable());
826
827 REPORTER_ASSERT(reporter, bitmap.getPixels());
828
829 const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType());
830 SkPMColor imageColor;
831 REPORTER_ASSERT(reporter, image->readPixels(dContext, info, &imageColor, sizeof(SkPMColor),
832 0, 0));
833 REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0));
834}
835
837 const SkImage* image) {
838 if (!image) {
839 ERRORF(reporter, "Failed to create image.");
840 return;
841 }
845
846 // Test subsetting to exercise the rowBytes logic.
847 SkBitmap tmp;
848 REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2,
849 image->height() / 2)));
850 sk_sp<SkImage> subsetImage(tmp.asImage());
851 REPORTER_ASSERT(reporter, subsetImage.get());
852
853 SkBitmap subsetBitmap;
854 REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap));
855 check_legacy_bitmap(reporter, nullptr, subsetImage.get(), subsetBitmap);
856}
857DEF_TEST(ImageLegacyBitmap, reporter) {
860
863
864 RasterDataHolder dataHolder;
865 image = create_rasterproc_image(&dataHolder);
867 image.reset();
868 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
869
872}
874 reporter,
875 ctxInfo,
877 auto dContext = ctxInfo.directContext();
879 test_legacy_bitmap(reporter, dContext, image.get());
880}
881
882static void test_peek(skiatest::Reporter* reporter, SkImage* image, bool expectPeekSuccess) {
883 if (!image) {
884 ERRORF(reporter, "Failed to create image!");
885 return;
886 }
887 SkPixmap pm;
888 bool success = image->peekPixels(&pm);
889 REPORTER_ASSERT(reporter, expectPeekSuccess == success);
890 if (success) {
891 const SkImageInfo& info = pm.info();
892 REPORTER_ASSERT(reporter, 20 == info.width());
893 REPORTER_ASSERT(reporter, 20 == info.height());
894 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
896 kOpaque_SkAlphaType == info.alphaType());
897 REPORTER_ASSERT(reporter, info.minRowBytes() <= pm.rowBytes());
899 }
900}
901DEF_TEST(ImagePeek, reporter) {
903 test_peek(reporter, image.get(), true);
904
906 test_peek(reporter, image.get(), true);
907
908 RasterDataHolder dataHolder;
909 image = create_rasterproc_image(&dataHolder);
910 test_peek(reporter, image.get(), true);
911 image.reset();
912 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
913
915 test_peek(reporter, image.get(), false);
916}
918 reporter,
919 ctxInfo,
921 sk_sp<SkImage> image(create_gpu_image(ctxInfo.directContext()));
922 test_peek(reporter, image.get(), false);
923}
924
927 int fReleaseCount;
928 static void Release(void* self) {
929 static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
930 }
931};
932
933DEF_GANESH_TEST_FOR_GL_CONTEXT(SkImage_NewFromTextureRelease,
934 reporter,
935 ctxInfo,
937 const int kWidth = 10;
938 const int kHeight = 10;
939
940 auto dContext = ctxInfo.directContext();
941
942 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(dContext,
943 kWidth,
944 kHeight,
946 skgpu::Mipmapped::kNo,
947 GrRenderable::kNo,
948 GrProtected::kNo);
949 if (!mbet) {
950 ERRORF(reporter, "couldn't create backend texture\n");
951 return;
952 }
953
954 TextureReleaseChecker releaseChecker;
957 dContext,
958 mbet->texture(),
959 texOrigin,
962 /*color space*/ nullptr,
963 sk_gpu_test::ManagedBackendTexture::ReleaseProc,
964 mbet->releaseContext(TextureReleaseChecker::Release, &releaseChecker));
965
966 GrSurfaceOrigin readBackOrigin;
967 GrBackendTexture readBackBackendTex;
970 refImg, &readBackBackendTex, false, &readBackOrigin),
971 "Did not get backend texture");
972 if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, mbet->texture())) {
973 ERRORF(reporter, "backend mismatch\n");
974 }
976 GrBackendTexture::TestingOnly_Equals(readBackBackendTex, mbet->texture()));
977 if (readBackOrigin != texOrigin) {
978 ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
979 }
980 REPORTER_ASSERT(reporter, readBackOrigin == texOrigin);
981
982 // Now exercise the release proc
983 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
984 refImg.reset(nullptr); // force a release of the image
985 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
986}
987
991 const char* testName,
992 const std::function<sk_sp<SkImage>(GrDirectContext*)>& imageMaker) {
993 for (int i = 0; i < skgpu::kContextTypeCount; ++i) {
994 GrContextFactory testFactory(options);
995 skgpu::ContextType ctxType = static_cast<skgpu::ContextType>(i);
996 ContextInfo ctxInfo = testFactory.getContextInfo(ctxType);
997 auto dContext = ctxInfo.directContext();
998 if (!dContext) {
999 continue;
1000 }
1001
1002 // If we don't have proper support for this feature, the factory will fallback to returning
1003 // codec-backed images. Those will "work", but some of our checks will fail because we
1004 // expect the cross-context images not to work on multiple contexts at once.
1005 if (!dContext->priv().caps()->crossContextTextureSupport()) {
1006 continue;
1007 }
1008
1009 // We test three lifetime patterns for a single context:
1010 // 1) Create image, free image
1011 // 2) Create image, draw, flush, free image
1012 // 3) Create image, draw, free image, flush
1013 // ... and then repeat the last two patterns with drawing on a second* context:
1014 // 4) Create image, draw*, flush*, free image
1015 // 5) Create image, draw*, free image, flush*
1016
1017 // Case #1: Create image, free image
1018 {
1019 sk_sp<SkImage> refImg(imageMaker(dContext));
1020 refImg.reset(nullptr); // force a release of the image
1021 }
1022
1025 if (!surface) {
1026 ERRORF(reporter, "SkSurfaces::RenderTarget failed for %s.", testName);
1027 continue;
1028 }
1029
1030 SkCanvas* canvas = surface->getCanvas();
1031
1032 // Case #2: Create image, draw, flush, free image
1033 {
1034 sk_sp<SkImage> refImg(imageMaker(dContext));
1035
1036 canvas->drawImage(refImg, 0, 0);
1037 dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
1038
1039 refImg.reset(nullptr); // force a release of the image
1040 }
1041
1042 // Case #3: Create image, draw, free image, flush
1043 {
1044 sk_sp<SkImage> refImg(imageMaker(dContext));
1045
1046 canvas->drawImage(refImg, 0, 0);
1047 refImg.reset(nullptr); // force a release of the image
1048
1049 dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
1050 }
1051
1052 // Configure second context
1053 sk_gpu_test::TestContext* testContext = ctxInfo.testContext();
1054
1055 ContextInfo otherContextInfo = testFactory.getSharedContextInfo(dContext);
1056 auto otherCtx = otherContextInfo.directContext();
1057 sk_gpu_test::TestContext* otherTestContext = otherContextInfo.testContext();
1058
1059 // Creating a context in a share group may fail
1060 if (!otherCtx) {
1061 continue;
1062 }
1063
1065 canvas = surface->getCanvas();
1066
1067 // Case #4: Create image, draw*, flush*, free image
1068 {
1069 testContext->makeCurrent();
1070 sk_sp<SkImage> refImg(imageMaker(dContext));
1071
1072 otherTestContext->makeCurrent();
1073 canvas->drawImage(refImg, 0, 0);
1074 otherCtx->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
1075
1076 testContext->makeCurrent();
1077 refImg.reset(nullptr); // force a release of the image
1078 }
1079
1080 // Case #5: Create image, draw*, free image, flush*
1081 {
1082 testContext->makeCurrent();
1083 sk_sp<SkImage> refImg(imageMaker(dContext));
1084
1085 otherTestContext->makeCurrent();
1086 canvas->drawImage(refImg, 0, 0);
1087
1088 testContext->makeCurrent();
1089 refImg.reset(nullptr); // force a release of the image
1090
1091 otherTestContext->makeCurrent();
1092 // Sync is specifically here for vulkan to guarantee the command buffer will finish
1093 // which is when we call the ReleaseProc.
1094 otherCtx->flushAndSubmit(surface.get(), GrSyncCpu::kYes);
1095 }
1096
1097 // Case #6: Verify that only one context can be using the image at a time
1098 {
1099 // Suppress warnings about trying to use a texture in two contexts.
1100 GrRecordingContextPriv::AutoSuppressWarningMessages aswm(otherCtx);
1101
1102 testContext->makeCurrent();
1103 sk_sp <SkImage> refImg(imageMaker(dContext));
1104 GrSurfaceProxyView view, otherView, viewSecondRef;
1105
1106 // Any context should be able to borrow the texture at this point
1107
1108 std::tie(view, std::ignore) =
1109 skgpu::ganesh::AsView(dContext, refImg, skgpu::Mipmapped::kNo);
1111
1112 // But once it's borrowed, no other context should be able to borrow
1113 otherTestContext->makeCurrent();
1114 std::tie(otherView, std::ignore) =
1115 skgpu::ganesh::AsView(otherCtx, refImg, skgpu::Mipmapped::kNo);
1116 REPORTER_ASSERT(reporter, !otherView);
1117
1118 // Original context (that's already borrowing) should be okay
1119 testContext->makeCurrent();
1120 std::tie(viewSecondRef, std::ignore) =
1121 skgpu::ganesh::AsView(dContext, refImg, skgpu::Mipmapped::kNo);
1122 REPORTER_ASSERT(reporter, viewSecondRef);
1123
1124 // Release first ref from the original context
1125 view.reset();
1126
1127 // We released one proxy but not the other from the current borrowing context. Make sure
1128 // a new context is still not able to borrow the texture.
1129 otherTestContext->makeCurrent();
1130 std::tie(otherView, std::ignore) =
1131 skgpu::ganesh::AsView(otherCtx, refImg, skgpu::Mipmapped::kNo);
1132 REPORTER_ASSERT(reporter, !otherView);
1133
1134 // Release second ref from the original context
1135 testContext->makeCurrent();
1136 viewSecondRef.reset();
1137
1138 // Now we should be able to borrow the texture from the other context
1139 otherTestContext->makeCurrent();
1140 std::tie(otherView, std::ignore) =
1141 skgpu::ganesh::AsView(otherCtx, refImg, skgpu::Mipmapped::kNo);
1142 REPORTER_ASSERT(reporter, otherView);
1143
1144 // Release everything
1145 otherView.reset();
1146 refImg.reset(nullptr);
1147 }
1148 }
1149}
1150
1151DEF_GANESH_TEST(SkImage_MakeCrossContextFromPixmapRelease,
1152 reporter,
1153 options,
1156 SkPixmap pixmap;
1157 if (!ToolUtils::GetResourceAsBitmap("images/mandrill_128.png", &bitmap) ||
1158 !bitmap.peekPixels(&pixmap)) {
1159 ERRORF(reporter, "missing resource");
1160 return;
1161 }
1163 options,
1164 "SkImage_MakeCrossContextFromPixmapRelease",
1165 [&pixmap](GrDirectContext* dContext) {
1167 dContext, pixmap, false);
1168 });
1169}
1170
1171DEF_GANESH_TEST(SkImage_CrossContextGrayAlphaConfigs,
1172 reporter,
1173 options,
1176 SkAutoPixmapStorage pixmap;
1177 pixmap.alloc(SkImageInfo::Make(4, 4, ct, kPremul_SkAlphaType));
1178
1179 for (int i = 0; i < skgpu::kContextTypeCount; ++i) {
1180 GrContextFactory testFactory(options);
1181 skgpu::ContextType ctxType = static_cast<skgpu::ContextType>(i);
1182 ContextInfo ctxInfo = testFactory.getContextInfo(ctxType);
1183 auto dContext = ctxInfo.directContext();
1184 if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
1185 continue;
1186 }
1187
1190
1191 auto [view, viewCT] = skgpu::ganesh::AsView(dContext, image, skgpu::Mipmapped::kNo);
1194
1195 bool expectAlpha = kAlpha_8_SkColorType == ct;
1197 REPORTER_ASSERT(reporter, expectAlpha == GrColorTypeIsAlphaOnly(grCT));
1198 }
1199 }
1200}
1201
1203 auto context = ctxInfo.directContext();
1204 sk_gpu_test::TestContext* testContext = ctxInfo.testContext();
1205 sk_sp<GrContextThreadSafeProxy> proxy = context->threadSafeProxy();
1206
1207 GrContextFactory otherFactory;
1208 ContextInfo otherContextInfo = otherFactory.getContextInfo(ctxInfo.type());
1209
1210 testContext->makeCurrent();
1211 REPORTER_ASSERT(reporter, proxy);
1212 auto createLarge = [context] {
1213 return create_image_large(context->priv().caps()->maxTextureSize());
1214 };
1215 struct TestCase {
1216 std::function<sk_sp<SkImage>()> fImageFactory;
1217 bool fExpectation;
1218 bool fCanTakeDirectly;
1219 };
1220 TestCase testCases[] = {
1221 { create_image, true, false },
1222 { create_codec_image, true, false },
1223 { create_data_image, true, false },
1224 { create_picture_image, true, false },
1225 { [context] { return create_gpu_image(context); }, true, true },
1226 // Create a texture image in a another context.
1227 { [otherContextInfo] {
1228 auto restore = otherContextInfo.testContext()->makeCurrentAndAutoRestore();
1229 sk_sp<SkImage> otherContextImage = create_gpu_image(otherContextInfo.directContext());
1230 otherContextInfo.directContext()->flushAndSubmit();
1231 return otherContextImage;
1232 }, false, false },
1233 // Create an image that is too large to be texture backed.
1234 { createLarge, false, false }
1235 };
1236
1237 for (const TestCase& testCase : testCases) {
1238 sk_sp<SkImage> image(testCase.fImageFactory());
1239 if (!image) {
1240 ERRORF(reporter, "Failed to create image!");
1241 continue;
1242 }
1243
1244 GrBackendTexture origBackend;
1245 SkImages::GetBackendTextureFromImage(image, &origBackend, true);
1246 if (testCase.fCanTakeDirectly) {
1247 SkASSERT(origBackend.isValid());
1248 }
1249
1250 GrBackendTexture newBackend;
1253 context, std::move(image), &newBackend, &proc);
1254 if (result != testCase.fExpectation) {
1255 static const char *const kFS[] = { "fail", "succeed" };
1256 ERRORF(reporter, "This image was expected to %s but did not.",
1257 kFS[testCase.fExpectation]);
1258 }
1259
1260 if (result) {
1261 SkASSERT(newBackend.isValid());
1262 }
1263
1264 bool tookDirectly = result && GrBackendTexture::TestingOnly_Equals(origBackend, newBackend);
1265 if (testCase.fCanTakeDirectly != tookDirectly) {
1266 static const char *const kExpectedState[] = { "not expected", "expected" };
1267 ERRORF(reporter, "This backend texture was %s to be taken directly.",
1268 kExpectedState[testCase.fCanTakeDirectly]);
1269 }
1270
1271 context->flushAndSubmit();
1272 }
1273}
1274
1275DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageBackendAccessAbandoned_Gpu,
1276 reporter,
1277 ctxInfo,
1279 auto dContext = ctxInfo.directContext();
1280 sk_sp<SkImage> image(create_gpu_image(ctxInfo.directContext()));
1281 if (!image) {
1282 return;
1283 }
1284
1285 GrBackendTexture beTex;
1286 bool ok = SkImages::GetBackendTextureFromImage(image, &beTex, true);
1289
1290 dContext->abandonContext();
1291
1292 // After abandoning the context the backend texture should not be valid.
1295}
1296
1297///////////////////////////////////////////////////////////////////////////////////////////////////
1298
1300 SkPictureRecorder recorder;
1301 SkCanvas* canvas = recorder.beginRecording(10, 10);
1302 canvas->clear(SK_ColorCYAN);
1304 SkISize::Make(10, 10),
1305 nullptr,
1306 nullptr,
1308 std::move(space));
1309}
1310
1311DEF_TEST(Image_ColorSpace, r) {
1313 sk_sp<SkImage> image = ToolUtils::GetResourceAsImage("images/mandrill_512_q075.jpg");
1314 REPORTER_ASSERT(r, srgb.get() == image->colorSpace());
1315
1316 image = ToolUtils::GetResourceAsImage("images/webp-color-profile-lossy.webp");
1318 bool success = image->colorSpace()->isNumericalTransferFn(&fn);
1319 REPORTER_ASSERT(r, success);
1321
1326
1329 bitmap.allocPixels(info);
1330 image = bitmap.asImage();
1332
1335 image = surface->makeImageSnapshot();
1336 REPORTER_ASSERT(r, nullptr == image->colorSpace());
1337
1339 image = surface->makeImageSnapshot();
1341}
1342
1343DEF_TEST(Image_makeColorSpace, r) {
1346 fn.a = 1.f; fn.b = 0.f; fn.c = 0.f; fn.d = 0.f; fn.e = 0.f; fn.f = 0.f; fn.g = 1.8f;
1348
1349 SkBitmap srgbBitmap;
1351 *srgbBitmap.getAddr32(0, 0) = SkSwizzle_RGBA_to_PMColor(0xFF604020);
1352 srgbBitmap.setImmutable();
1353 sk_sp<SkImage> srgbImage = srgbBitmap.asImage();
1354 sk_sp<SkImage> p3Image = srgbImage->makeColorSpace(nullptr, p3);
1355 SkBitmap p3Bitmap;
1356 bool success = p3Image->asLegacyBitmap(&p3Bitmap);
1357
1358 auto almost_equal = [](int a, int b) { return SkTAbs(a - b) <= 2; };
1359
1360 REPORTER_ASSERT(r, success);
1361 REPORTER_ASSERT(r, almost_equal(0x28, SkGetPackedR32(*p3Bitmap.getAddr32(0, 0))));
1362 REPORTER_ASSERT(r, almost_equal(0x40, SkGetPackedG32(*p3Bitmap.getAddr32(0, 0))));
1363 REPORTER_ASSERT(r, almost_equal(0x5E, SkGetPackedB32(*p3Bitmap.getAddr32(0, 0))));
1364
1365 sk_sp<SkImage> adobeImage = srgbImage->makeColorSpace(nullptr, adobeGamut);
1366 SkBitmap adobeBitmap;
1367 success = adobeImage->asLegacyBitmap(&adobeBitmap);
1368 REPORTER_ASSERT(r, success);
1369 REPORTER_ASSERT(r, almost_equal(0x21, SkGetPackedR32(*adobeBitmap.getAddr32(0, 0))));
1370 REPORTER_ASSERT(r, almost_equal(0x31, SkGetPackedG32(*adobeBitmap.getAddr32(0, 0))));
1371 REPORTER_ASSERT(r, almost_equal(0x4C, SkGetPackedB32(*adobeBitmap.getAddr32(0, 0))));
1372
1373 srgbImage = ToolUtils::GetResourceAsImage("images/1x1.png");
1374 p3Image = srgbImage->makeColorSpace(nullptr, p3);
1375 success = p3Image->asLegacyBitmap(&p3Bitmap);
1376 REPORTER_ASSERT(r, success);
1377 REPORTER_ASSERT(r, almost_equal(0x8B, SkGetPackedR32(*p3Bitmap.getAddr32(0, 0))));
1378 REPORTER_ASSERT(r, almost_equal(0x82, SkGetPackedG32(*p3Bitmap.getAddr32(0, 0))));
1379 REPORTER_ASSERT(r, almost_equal(0x77, SkGetPackedB32(*p3Bitmap.getAddr32(0, 0))));
1380}
1381
1382///////////////////////////////////////////////////////////////////////////////////////////////////
1383
1384static void make_all_premul(SkBitmap* bm) {
1386 for (int a = 0; a < 256; ++a) {
1387 for (int r = 0; r < 256; ++r) {
1388 // make all valid premul combinations
1389 int c = std::min(a, r);
1390 *bm->getAddr32(a, r) = SkPackARGB32(a, c, c, c);
1391 }
1392 }
1393}
1394
1395static bool equal(const SkBitmap& a, const SkBitmap& b) {
1396 SkASSERT(a.width() == b.width());
1397 SkASSERT(a.height() == b.height());
1398 for (int y = 0; y < a.height(); ++y) {
1399 for (int x = 0; x < a.width(); ++x) {
1400 SkPMColor pa = *a.getAddr32(x, y);
1401 SkPMColor pb = *b.getAddr32(x, y);
1402 if (pa != pb) {
1403 return false;
1404 }
1405 }
1406 }
1407 return true;
1408}
1409
1410DEF_TEST(image_roundtrip_encode, reporter) {
1411 SkBitmap bm0;
1412 make_all_premul(&bm0);
1413
1414 auto img0 = bm0.asImage();
1415 sk_sp<SkData> data = SkPngEncoder::Encode(nullptr, img0.get(), {});
1416 auto img1 = SkImages::DeferredFromEncodedData(data);
1417
1418 SkBitmap bm1;
1420 img1->readPixels(nullptr, bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0);
1421
1422 REPORTER_ASSERT(reporter, equal(bm0, bm1));
1423}
1424
1425DEF_TEST(image_roundtrip_premul, reporter) {
1426 SkBitmap bm0;
1427 make_all_premul(&bm0);
1428
1429 SkBitmap bm1;
1431 bm0.readPixels(bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0);
1432
1433 SkBitmap bm2;
1435 bm1.readPixels(bm2.info(), bm2.getPixels(), bm2.rowBytes(), 0, 0);
1436
1437 REPORTER_ASSERT(reporter, equal(bm0, bm2));
1438}
1439
1440DEF_TEST(image_from_encoded_alphatype_override, reporter) {
1441 sk_sp<SkData> data = GetResourceAsData("images/mandrill_32.png");
1442
1443 // Ensure that we can decode the image when we specifically request premul or unpremul, but
1444 // not when we request kOpaque
1448
1449 // Same tests as above, but using SkImageGenerators::MakeFromEncoded
1453}
1454
1455///////////////////////////////////////////////////////////////////////////////////////////////////
1456
1457static void check_scaled_pixels(skiatest::Reporter* reporter, SkPixmap* pmap, uint32_t expected) {
1458 // Verify that all pixels contain the original test color
1459 for (auto y = 0; y < pmap->height(); ++y) {
1460 for (auto x = 0; x < pmap->width(); ++x) {
1461 uint32_t pixel = *pmap->addr32(x, y);
1462 if (pixel != expected) {
1463 ERRORF(reporter, "Expected scaled pixels to be the same. At %d,%d 0x%08x != 0x%08x",
1464 x, y, pixel, expected);
1465 return;
1466 }
1467 }
1468 }
1469}
1470
1472 uint32_t expected) {
1474
1475 // Make sure to test kDisallow first, so we don't just get a cache hit in that case
1477 SkAutoPixmapStorage scaled;
1478 scaled.alloc(info);
1480 ERRORF(reporter, "Failed to scale image");
1481 continue;
1482 }
1483
1484 check_scaled_pixels(reporter, &scaled, expected);
1485 }
1486}
1487
1488DEF_TEST(ImageScalePixels, reporter) {
1489 const SkPMColor pmRed = SkPackARGB32(0xFF, 0xFF, 0, 0);
1490 const SkColor red = SK_ColorRED;
1491
1492 // Test raster image
1495 surface->getCanvas()->clear(red);
1496 sk_sp<SkImage> rasterImage = surface->makeImageSnapshot();
1497 test_scale_pixels(reporter, rasterImage.get(), pmRed);
1498
1499 // Test encoded image
1500 sk_sp<SkData> data = SkPngEncoder::Encode(nullptr, rasterImage.get(), {});
1502 test_scale_pixels(reporter, codecImage.get(), pmRed);
1503}
1504
1506 reporter,
1507 ctxInfo,
1509 const SkPMColor pmRed = SkPackARGB32(0xFF, 0xFF, 0, 0);
1510 const SkColor red = SK_ColorRED;
1511
1514 SkSurfaces::RenderTarget(ctxInfo.directContext(), skgpu::Budgeted::kNo, info);
1515 surface->getCanvas()->clear(red);
1516 sk_sp<SkImage> gpuImage = surface->makeImageSnapshot();
1517 test_scale_pixels(reporter, gpuImage.get(), pmRed);
1518}
1519
1521 return ToolUtils::GetResourceAsImage("images/mandrill_32.png");
1522}
1523
1524DEF_TEST(Image_nonfinite_dst, reporter) {
1526 auto img = any_image_will_do();
1527
1528 for (SkScalar bad : { SK_ScalarInfinity, SK_ScalarNaN}) {
1529 for (int bits = 1; bits <= 15; ++bits) {
1530 SkRect dst = { 0, 0, 10, 10 };
1531 if (bits & 1) dst.fLeft = bad;
1532 if (bits & 2) dst.fTop = bad;
1533 if (bits & 4) dst.fRight = bad;
1534 if (bits & 8) dst.fBottom = bad;
1535
1536 surf->getCanvas()->drawImageRect(img, dst, SkSamplingOptions());
1537
1538 // we should draw nothing
1539 ToolUtils::PixelIter iter(surf.get());
1540 while (void* addr = iter.next()) {
1541 REPORTER_ASSERT(reporter, *(SkPMColor*)addr == 0);
1542 }
1543 }
1544 }
1545}
1546
1550 SkYUVAInfo yuvaInfo({1, 1},
1554 const SkPixmap pmaps[] = {pm, pm, pm};
1555 auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, pmaps);
1556
1557 return SkImages::TextureFromYUVAPixmaps(dContext, yuvaPixmaps);
1558}
1559
1561 auto dContext = ctxInfo.directContext();
1563 auto s = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kYes, ii, 1, nullptr);
1564
1565 s->getCanvas()->clear(SK_ColorRED);
1566 auto i0 = s->makeImageSnapshot();
1567 s->getCanvas()->clear(SK_ColorBLUE);
1568 auto i1 = s->makeImageSnapshot();
1569 s->getCanvas()->clear(SK_ColorGREEN);
1570 // Make a YUVA image.
1571 auto i2 = make_yuva_image(dContext);
1572
1573 // Flush all the setup work we did above and then make little lambda that reports the flush
1574 // count delta since the last time it was called.
1575 dContext->flushAndSubmit();
1576 auto numSubmits =
1577 [dContext,
1578 submitCnt = dContext->priv().getGpu()->stats()->numSubmitToGpus()]() mutable {
1579 int curr = dContext->priv().getGpu()->stats()->numSubmitToGpus();
1580 int n = curr - submitCnt;
1581 submitCnt = curr;
1582 return n;
1583 };
1584
1585 // Images aren't used therefore flush is ignored, but submit is still called.
1586 dContext->flushAndSubmit(i0);
1587 dContext->flushAndSubmit(i1);
1588 dContext->flushAndSubmit(i2);
1589 REPORTER_ASSERT(reporter, numSubmits() == 3);
1590
1591 // Syncing forces the flush to happen even if the images aren't used.
1592 dContext->flush(i0);
1593 dContext->submit(GrSyncCpu::kYes);
1594 REPORTER_ASSERT(reporter, numSubmits() == 1);
1595 dContext->flush(i1);
1596 dContext->submit(GrSyncCpu::kYes);
1597 REPORTER_ASSERT(reporter, numSubmits() == 1);
1598 dContext->flush(i2);
1599 dContext->submit(GrSyncCpu::kYes);
1600 REPORTER_ASSERT(reporter, numSubmits() == 1);
1601
1602 // Use image 1
1603 s->getCanvas()->drawImage(i1, 0, 0);
1604 // Flushing image 0 should do nothing, but submit is still called.
1605 dContext->flushAndSubmit(i0);
1606 REPORTER_ASSERT(reporter, numSubmits() == 1);
1607 // Flushing image 1 should flush.
1608 dContext->flushAndSubmit(i1);
1609 REPORTER_ASSERT(reporter, numSubmits() == 1);
1610 // Flushing image 2 should do nothing, but submit is still called.
1611 dContext->flushAndSubmit(i2);
1612 REPORTER_ASSERT(reporter, numSubmits() == 1);
1613
1614 // Use image 2
1615 s->getCanvas()->drawImage(i2, 0, 0);
1616 // Flushing image 0 should do nothing, but submit is still called.
1617 dContext->flushAndSubmit(i0);
1618 REPORTER_ASSERT(reporter, numSubmits() == 1);
1619 // Flushing image 1 do nothing, but submit is still called.
1620 dContext->flushAndSubmit(i1);
1621 REPORTER_ASSERT(reporter, numSubmits() == 1);
1622 // Flushing image 2 should flush.
1623 dContext->flushAndSubmit(i2);
1624 REPORTER_ASSERT(reporter, numSubmits() == 1);
1625 REPORTER_ASSERT(reporter, static_cast<SkImage_GaneshYUVA*>(as_IB(i2.get()))->isTextureBacked());
1626 s->getCanvas()->drawImage(i2, 0, 0);
1627 // Flushing image 0 should do nothing, but submit is still called.
1628 dContext->flushAndSubmit(i0);
1629 REPORTER_ASSERT(reporter, numSubmits() == 1);
1630 // Flushing image 1 do nothing, but submit is still called.
1631 dContext->flushAndSubmit(i1);
1632 REPORTER_ASSERT(reporter, numSubmits() == 1);
1633 // Flushing image 2 should flush.
1634 dContext->flushAndSubmit(i2);
1635 REPORTER_ASSERT(reporter, numSubmits() == 1);
1636}
1637
1639 (0.0f/2, -1.0f/2, 2.0f/2, -1.0f/2,
1640 2.0f/2, 0.0f/2, -5.0f/2, 3.0f/2,
1641 0.0f/2, 1.0f/2, 4.0f/2, -3.0f/2,
1642 0.0f/2, 0.0f/2, -1.0f/2, 1.0f/2);
1643
1645 ( 1.0f/18, -9.0f/18, 15.0f/18, -7.0f/18,
1646 16.0f/18, 0.0f/18, -36.0f/18, 21.0f/18,
1647 1.0f/18, 9.0f/18, 27.0f/18, -21.0f/18,
1648 0.0f/18, 0.0f/18, -6.0f/18, 7.0f/18);
1649
1650DEF_TEST(image_cubicresampler, reporter) {
1651 auto diff = [reporter](const SkM44& a, const SkM44& b) {
1652 const float tolerance = 0.000001f;
1653 for (int r = 0; r < 4; ++r) {
1654 for (int c = 0; c < 4; ++c) {
1655 float d = std::abs(a.rc(r, c) - b.rc(r, c));
1656 REPORTER_ASSERT(reporter, d <= tolerance);
1657 }
1658 }
1659 };
1660
1662
1664}
1665
1666DEF_TEST(image_subset_encode_skbug_7752, reporter) {
1667 sk_sp<SkImage> image = ToolUtils::GetResourceAsImage("images/mandrill_128.png");
1668 const int W = image->width();
1669 const int H = image->height();
1670
1671 auto check_roundtrip = [&](const sk_sp<SkImage>& img) {
1672 auto img2 = SkImages::DeferredFromEncodedData(SkPngEncoder::Encode(nullptr, img.get(), {}));
1673 REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img.get(), img2.get()));
1674 };
1675 check_roundtrip(image); // should trivially pass
1676 check_roundtrip(image->makeSubset(nullptr, {0, 0, W/2, H/2}));
1677 check_roundtrip(image->makeSubset(nullptr, {W/2, H/2, W, H}));
1678 check_roundtrip(image->makeColorSpace(nullptr, SkColorSpace::MakeSRGBLinear()));
1679}
static bool almost_equal(float a, float b)
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
reporter
int count
static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct)
static constexpr bool GrColorTypeIsAlphaOnly(GrColorType ct)
GrColorType
static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct)
GrSurfaceOrigin
Definition GrTypes.h:147
@ kBottomLeft_GrSurfaceOrigin
Definition GrTypes.h:149
@ kTopLeft_GrSurfaceOrigin
Definition GrTypes.h:148
static sk_sp< SkColorSpace > rec2020()
static void make_bitmap_mutable(SkBitmap *bm)
static void check_legacy_bitmap(skiatest::Reporter *reporter, GrDirectContext *dContext, const SkImage *image, const SkBitmap &bitmap)
static sk_sp< SkImage > create_data_image()
static void draw_image_test_pattern(SkCanvas *canvas)
static void test_legacy_bitmap(skiatest::Reporter *reporter, GrDirectContext *dContext, const SkImage *image)
static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected)
SkImageInfo read_pixels_info(SkImage *image)
Definition ImageTest.cpp:98
constexpr SkM44 gCentripetalCatmulRom(0.0f/2, -1.0f/2, 2.0f/2, -1.0f/2, 2.0f/2, 0.0f/2, -5.0f/2, 3.0f/2, 0.0f/2, 1.0f/2, 4.0f/2, -3.0f/2, 0.0f/2, 0.0f/2, -1.0f/2, 1.0f/2)
static sk_sp< SkData > create_image_data(SkImageInfo *info)
static void test_scale_pixels(skiatest::Reporter *reporter, const SkImage *image, uint32_t expected)
static void test_cross_context_image(skiatest::Reporter *reporter, const GrContextOptions &options, const char *testName, const std::function< sk_sp< SkImage >(GrDirectContext *)> &imageMaker)
static sk_sp< SkImage > create_codec_image()
static sk_sp< SkImage > create_gpu_image(GrRecordingContext *rContext, bool withMips=false, skgpu::Budgeted budgeted=skgpu::Budgeted::kYes)
static sk_sp< SkImage > create_picture_image()
constexpr SkM44 gMitchellNetravali(1.0f/18, -9.0f/18, 15.0f/18, -7.0f/18, 16.0f/18, 0.0f/18, -36.0f/18, 21.0f/18, 1.0f/18, 9.0f/18, 27.0f/18, -21.0f/18, 0.0f/18, 0.0f/18, -6.0f/18, 7.0f/18)
static sk_sp< SkImage > any_image_will_do()
static void check_scaled_pixels(skiatest::Reporter *reporter, SkPixmap *pmap, uint32_t expected)
static sk_sp< SkImage > make_yuva_image(GrDirectContext *dContext)
static sk_sp< SkImage > create_image()
static void assert_equal(skiatest::Reporter *reporter, GrDirectContext *dContextA, SkImage *a, const SkIRect *subsetA, SkImage *b)
static void test_encode(skiatest::Reporter *reporter, GrDirectContext *dContext, SkImage *image)
static bool equal(const SkBitmap &a, const SkBitmap &b)
static sk_sp< SkImage > create_image_large(int maxTextureSize)
static sk_sp< SkImage > create_rasterproc_image(RasterDataHolder *dataHolder)
static void image_test_read_pixels(GrDirectContext *dContext, skiatest::Reporter *reporter, SkImage *image)
static void make_bitmap_immutable(SkBitmap *bm)
static void test_peek(skiatest::Reporter *reporter, SkImage *image, bool expectPeekSuccess)
static void make_all_premul(SkBitmap *bm)
kUnpremul_SkAlphaType
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition Resources.cpp:42
@ kOpaque_SkAlphaType
pixel is opaque
Definition SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT_RELEASE(cond)
Definition SkAssert.h:100
#define SkASSERT(cond)
Definition SkAssert.h:116
unsigned U8CPU
Definition SkCPUTypes.h:18
static SkPMColor SkSwizzle_RGBA_to_PMColor(uint32_t c)
Definition SkColorData.h:83
#define SkGetPackedB32(packed)
Definition SkColorPriv.h:95
#define SkGetPackedR32(packed)
Definition SkColorPriv.h:93
#define SkGetPackedG32(packed)
Definition SkColorPriv.h:94
static SkPMColor SkPackARGB32(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
static bool color_space_almost_equal(float a, float b)
SkColorType
Definition SkColorType.h:19
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition SkColorType.h:21
@ kLastEnum_SkColorType
last valid value
Definition SkColorType.h:56
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition SkColorType.h:35
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
SK_API SkPMColor SkPreMultiplyColor(SkColor c)
Definition SkColor.cpp:21
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition SkColor.h:143
uint32_t SkPMColor
Definition SkColor.h:205
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
static constexpr SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition SkColor.h:49
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define sk_float_round2int(x)
static bool read(SkStream *stream, void *buffer, size_t amount)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static bool ok(int result)
@ kJPEG_Full_SkYUVColorSpace
describes full range
Definition SkImageInfo.h:69
SK_SPI sk_sp< SkImage > SkMakeImageFromRasterBitmap(const SkBitmap &, SkCopyPixelsMode)
SkCopyPixelsMode
Definition SkImagePriv.h:17
@ kNever_SkCopyPixelsMode
never copy src pixels (even if they are marked mutable)
Definition SkImagePriv.h:20
@ kIfMutable_SkCopyPixelsMode
only copy src pixels if they are marked mutable
Definition SkImagePriv.h:18
@ kAlways_SkCopyPixelsMode
always copy src pixels (even if they are marked immutable)
Definition SkImagePriv.h:19
static SkImage_Base * as_IB(SkImage *image)
#define SK_ScalarNaN
Definition SkScalar.h:28
#define SK_ScalarInfinity
Definition SkScalar.h:26
static T SkTAbs(T value)
Definition SkTemplates.h:43
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
#define DEF_GANESH_TEST(name, reporter, options, ctsEnforcement)
Definition Test.h:393
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
#define DEF_GANESH_TEST_FOR_GL_CONTEXT(name, reporter, context_info, ctsEnforcement)
Definition Test.h:442
#define ERRORF(r,...)
Definition Test.h:293
#define DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info, ctsEnforcement)
Definition Test.h:434
#define DEF_GANESH_TEST_FOR_ALL_CONTEXTS(name, reporter, context_info, ctsEnforcement)
Definition Test.h:431
static uint32_t premul(uint32_t color)
#define W
Definition aaa.cpp:17
void flushAndSubmit(GrSyncCpu sync=GrSyncCpu::kNo)
UniqueID underlyingUniqueID() const
skgpu::Budgeted isBudgeted() const
const skgpu::UniqueKey & getUniqueKey() const override
skgpu::Mipmapped mipmapped() const
void alloc(const SkImageInfo &)
static bool Find(const SkBitmapCacheDesc &, SkBitmap *result)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
sk_sp< SkImage > asImage() const
Definition SkBitmap.cpp:645
void setImmutable()
Definition SkBitmap.cpp:400
bool installPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, void(*releaseProc)(void *addr, void *context), void *context)
Definition SkBitmap.cpp:323
void notifyPixelsChanged() const
Definition SkBitmap.cpp:365
bool isImmutable() const
Definition SkBitmap.cpp:396
size_t rowBytes() const
Definition SkBitmap.h:238
void * getPixels() const
Definition SkBitmap.h:283
const SkImageInfo & info() const
Definition SkBitmap.h:139
bool readPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY) const
Definition SkBitmap.cpp:488
uint32_t getGenerationID() const
Definition SkBitmap.cpp:361
void allocN32Pixels(int width, int height, bool isOpaque=false)
Definition SkBitmap.cpp:232
uint32_t * getAddr32(int x, int y) const
Definition SkBitmap.h:1260
void drawRect(const SkRect &rect, const SkPaint &paint)
void clear(SkColor color)
Definition SkCanvas.h:1199
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
bool isNumericalTransferFn(skcms_TransferFunction *fn) const
static bool Equals(const SkColorSpace *, const SkColorSpace *)
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkColorSpace > MakeSRGBLinear()
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition SkData.cpp:116
const void * data() const
Definition SkData.h:37
static sk_sp< SkData > MakeEmpty()
Definition SkData.cpp:94
static SkM44 CubicResamplerMatrix(float B, float C)
virtual GrImageContext * context() const
bool isTextureBacked() const override
virtual sk_sp< SkImage > makeColorSpace(GrDirectContext *direct, sk_sp< SkColorSpace > target) const =0
SkColorSpace * colorSpace() const
Definition SkImage.cpp:156
bool readPixels(GrDirectContext *context, const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint cachingHint=kAllow_CachingHint) const
Definition SkImage.cpp:42
uint32_t uniqueID() const
Definition SkImage.h:311
SkAlphaType alphaType() const
Definition SkImage.cpp:154
virtual bool isLazyGenerated() const =0
bool peekPixels(SkPixmap *pixmap) const
Definition SkImage.cpp:34
int width() const
Definition SkImage.h:285
SkColorType colorType() const
Definition SkImage.cpp:152
sk_sp< SkImage > makeNonTextureImage(GrDirectContext *=nullptr) const
Definition SkImage.cpp:260
virtual bool isTextureBacked() const =0
int height() const
Definition SkImage.h:291
@ kDisallow_CachingHint
disallows internally caching decoded and copied pixels
Definition SkImage.h:465
@ kAllow_CachingHint
allows internally caching decoded and copied pixels
Definition SkImage.h:464
bool hasMipmaps() const
Definition SkImage.cpp:292
bool scalePixels(const SkPixmap &dst, const SkSamplingOptions &, CachingHint cachingHint=kAllow_CachingHint) const
Definition SkImage.cpp:127
bool asLegacyBitmap(SkBitmap *bitmap, LegacyBitmapMode legacyBitmapMode=kRO_LegacyBitmapMode) const
Definition SkImage.cpp:233
virtual sk_sp< SkImage > makeSubset(GrDirectContext *direct, const SkIRect &subset) const =0
Definition SkM44.h:150
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkData > serialize(const SkSerialProcs *procs=nullptr) const
static sk_sp< SkPicture > MakeFromData(const SkData *data, const SkDeserialProcs *procs=nullptr)
virtual int approximateOpCount(bool nested=false) const =0
const uint32_t * addr32() const
Definition SkPixmap.h:352
size_t rowBytes() const
Definition SkPixmap.h:145
int width() const
Definition SkPixmap.h:160
const SkImageInfo & info() const
Definition SkPixmap.h:135
int height() const
Definition SkPixmap.h:166
@ kY_U_V
Plane 0: Y, Plane 1: U, Plane 2: V.
@ k444
No subsampling. UV values for each Y.
static SkYUVAPixmaps FromExternalPixmaps(const SkYUVAInfo &, const SkPixmap[kMaxPlanes])
void * next(SkIPoint *loc=nullptr)
Definition ToolUtils.h:286
GrDirectContext * directContext() const
TestContext * testContext() const
ContextInfo getContextInfo(ContextType type, ContextOverrides=ContextOverrides::kNone)
ContextInfo getSharedContextInfo(GrDirectContext *shareContext, uint32_t shareIndex=0)
SkScopeExit makeCurrentAndAutoRestore() const
T * get() const
Definition SkRefCnt.h:303
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
bool isValid() const
Definition ResourceKey.h:55
static constexpr int kSize
const Paint & paint
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct s
struct MyStruct a[10]
GAsyncResult * result
double y
double x
std::unique_ptr< SkImageGenerator > MakeFromEncoded(sk_sp< SkData > data, std::optional< SkAlphaType > at)
SK_API sk_sp< SkImage > TextureFromYUVAPixmaps(GrRecordingContext *context, const SkYUVAPixmaps &pixmaps, skgpu::Mipmapped buildMips, bool limitToMaxTextureSize, sk_sp< SkColorSpace > imageColorSpace)
SK_API sk_sp< SkImage > DeferredFromPicture(sk_sp< SkPicture > picture, const SkISize &dimensions, const SkMatrix *matrix, const SkPaint *paint, BitDepth bitDepth, sk_sp< SkColorSpace > colorSpace, SkSurfaceProps props)
SK_API sk_sp< SkImage > RasterFromData(const SkImageInfo &info, sk_sp< SkData > pixels, size_t rowBytes)
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
SK_API sk_sp< SkImage > RasterFromPixmap(const SkPixmap &pixmap, RasterReleaseProc rasterReleaseProc, ReleaseContext releaseContext)
SK_API sk_sp< SkImage > DeferredFromGenerator(std::unique_ptr< SkImageGenerator > imageGenerator)
SK_API sk_sp< SkImage > TextureFromImage(GrDirectContext *, const SkImage *, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Budgeted=skgpu::Budgeted::kYes)
SK_API sk_sp< SkImage > CrossContextTextureFromPixmap(GrDirectContext *context, const SkPixmap &pixmap, bool buildMips, bool limitToMaxTextureSize=false)
SK_API sk_sp< SkImage > RasterFromPixmapCopy(const SkPixmap &pixmap)
@ kU8
uses 8-bit unsigned int per color component
std::function< void(GrBackendTexture)> BackendTextureReleaseProc
SK_API bool GetBackendTextureFromImage(const SkImage *img, GrBackendTexture *outTexture, bool flushPendingGrContextIO, GrSurfaceOrigin *origin=nullptr)
SK_API sk_sp< SkImage > BorrowTextureFrom(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
SK_API bool MakeBackendTextureFromImage(GrDirectContext *context, sk_sp< SkImage > image, GrBackendTexture *backendTexture, BackendTextureReleaseProc *backendTextureReleaseProc)
static constexpr skcms_Matrix3x3 kAdobeRGB
static constexpr skcms_Matrix3x3 kRec2020
static constexpr skcms_Matrix3x3 kDisplayP3
static constexpr skcms_TransferFunction kSRGB
void(* memset32)(uint32_t[], uint32_t, int)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition DecodeUtils.h:25
bool GetResourceAsBitmap(const char *resource, SkBitmap *dst)
Definition DecodeUtils.h:21
bool equal_pixels(const SkPixmap &a, const SkPixmap &b)
GrTextureProxy * GetTextureImageProxy(SkImage *image, GrRecordingContext *rContext)
skgpu::Protected Protected
std::tuple< GrSurfaceProxyView, GrColorType > AsView(GrRecordingContext *rContext, const SkImage *img, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy)
static const int kContextTypeCount
Definition ContextType.h:42
Budgeted
Definition GpuTypes.h:35
Protected
Definition GpuTypes.h:61
SkScalar w
SkScalar h
Definition SkMD5.cpp:130
sk_sp< SkData > fData
static void Release(const void *pixels, void *context)
static SkBitmapCacheDesc Make(const SkImage *)
constexpr int32_t x() const
Definition SkRect.h:141
constexpr int32_t y() const
Definition SkRect.h:148
constexpr int32_t height() const
Definition SkRect.h:165
constexpr int32_t width() const
Definition SkRect.h:158
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo MakeS32(int width, int height, SkAlphaType at)
static SkImageInfo MakeUnknown()
static SkImageInfo MakeN32(int width, int height, SkAlphaType at)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
SkSerialImageProc fImageProc
static void Release(void *self)
constexpr size_t kHeight
constexpr size_t kWidth