xref: /aosp_15_r20/external/skia/tests/ImageTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorPriv.h"
14 #include "include/core/SkColorSpace.h"
15 #include "include/core/SkColorType.h"
16 #include "include/core/SkData.h"
17 #include "include/core/SkDataTable.h"
18 #include "include/core/SkImage.h"
19 #include "include/core/SkImageGenerator.h"
20 #include "include/core/SkImageInfo.h"
21 #include "include/core/SkM44.h"
22 #include "include/core/SkPaint.h"
23 #include "include/core/SkPicture.h"
24 #include "include/core/SkPictureRecorder.h"
25 #include "include/core/SkPixmap.h"
26 #include "include/core/SkRect.h"
27 #include "include/core/SkRefCnt.h"
28 #include "include/core/SkSamplingOptions.h"
29 #include "include/core/SkScalar.h"
30 #include "include/core/SkSerialProcs.h"
31 #include "include/core/SkSize.h"
32 #include "include/core/SkStream.h"
33 #include "include/core/SkSurface.h"
34 #include "include/core/SkTypes.h"
35 #include "include/core/SkYUVAInfo.h"
36 #include "include/core/SkYUVAPixmaps.h"
37 #include "include/encode/SkPngEncoder.h"
38 #include "include/gpu/GpuTypes.h"
39 #include "include/gpu/ganesh/GrBackendSurface.h"
40 #include "include/gpu/ganesh/GrDirectContext.h"
41 #include "include/gpu/ganesh/GrTypes.h"
42 #include "include/gpu/ganesh/SkImageGanesh.h"
43 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
44 #include "include/private/SkColorData.h"
45 #include "include/private/base/SkCPUTypes.h"
46 #include "include/private/base/SkDebug.h"
47 #include "include/private/base/SkFloatingPoint.h"
48 #include "include/private/base/SkTemplates.h"
49 #include "include/private/base/SkTo.h"
50 #include "include/private/gpu/ganesh/GrImageContext.h"
51 #include "include/private/gpu/ganesh/GrTypesPriv.h"
52 #include "modules/skcms/skcms.h"
53 #include "src/core/SkAutoPixmapStorage.h"
54 #include "src/core/SkBitmapCache.h"
55 #include "src/core/SkColorSpacePriv.h"
56 #include "src/core/SkImagePriv.h"
57 #include "src/core/SkMemset.h"
58 #include "src/gpu/ResourceKey.h"
59 #include "src/gpu/ganesh/GrCaps.h"
60 #include "src/gpu/ganesh/GrDirectContextPriv.h"
61 #include "src/gpu/ganesh/GrGpu.h"
62 #include "src/gpu/ganesh/GrImageContextPriv.h"
63 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
64 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
65 #include "src/gpu/ganesh/GrTextureProxy.h"
66 #include "src/gpu/ganesh/image/GrImageUtils.h"
67 #include "src/gpu/ganesh/image/SkImage_GaneshYUVA.h"
68 #include "src/image/SkImageGeneratorPriv.h"
69 #include "src/image/SkImage_Base.h"
70 #include "src/shaders/SkImageShader.h"
71 #include "tests/CtsEnforcement.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"
77 #include "tools/gpu/ManagedBackendTexture.h"
78 #include "tools/gpu/ProxyUtils.h"
79 #include "tools/gpu/TestContext.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 
92 class GrContextThreadSafeProxy;
93 class GrRecordingContext;
94 struct GrContextOptions;
95 
96 using namespace sk_gpu_test;
97 
read_pixels_info(SkImage * image)98 SkImageInfo read_pixels_info(SkImage* image) {
99     if (image->colorSpace()) {
100         return SkImageInfo::MakeS32(image->width(), image->height(), image->alphaType());
101     }
102 
103     return SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType());
104 }
105 
106 // image `b` is assumed to be raster
assert_equal(skiatest::Reporter * reporter,GrDirectContext * dContextA,SkImage * a,const SkIRect * subsetA,SkImage * b)107 static void assert_equal(skiatest::Reporter* reporter, GrDirectContext* dContextA, SkImage* a,
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 }
draw_image_test_pattern(SkCanvas * canvas)133 static void draw_image_test_pattern(SkCanvas* canvas) {
134     canvas->clear(SK_ColorWHITE);
135     SkPaint paint;
136     paint.setColor(SK_ColorBLACK);
137     canvas->drawRect(SkRect::MakeXYWH(5, 5, 10, 10), paint);
138 }
create_image()139 static sk_sp<SkImage> create_image() {
140     const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
141     auto surface(SkSurfaces::Raster(info));
142     draw_image_test_pattern(surface->getCanvas());
143     return surface->makeImageSnapshot();
144 }
create_image_data(SkImageInfo * info)145 static sk_sp<SkData> create_image_data(SkImageInfo* info) {
146     *info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
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);
153         draw_image_test_pattern(&canvas);
154     }
155     return data;
156 }
create_data_image()157 static sk_sp<SkImage> create_data_image() {
158     SkImageInfo info;
159     sk_sp<SkData> data(create_image_data(&info));
160     return SkImages::RasterFromData(info, std::move(data), info.minRowBytes());
161 }
create_image_large(int maxTextureSize)162 static sk_sp<SkImage> create_image_large(int maxTextureSize) {
163     const SkImageInfo info = SkImageInfo::MakeN32(maxTextureSize + 1, 32, kOpaque_SkAlphaType);
164     auto surface(SkSurfaces::Raster(info));
165     surface->getCanvas()->clear(SK_ColorWHITE);
166     SkPaint paint;
167     paint.setColor(SK_ColorBLACK);
168     surface->getCanvas()->drawRect(SkRect::MakeXYWH(4000, 2, 28000, 30), paint);
169     return surface->makeImageSnapshot();
170 }
create_picture_image()171 static sk_sp<SkImage> create_picture_image() {
172     SkPictureRecorder recorder;
173     SkCanvas* canvas = recorder.beginRecording(10, 10);
174     canvas->clear(SK_ColorCYAN);
175     return SkImages::DeferredFromPicture(recorder.finishRecordingAsPicture(),
176                                          SkISize::Make(10, 10),
177                                          nullptr,
178                                          nullptr,
179                                          SkImages::BitDepth::kU8,
180                                          SkColorSpace::MakeSRGB());
181 }
182 // Want to ensure that our Release is called when the owning image is destroyed
183 struct RasterDataHolder {
RasterDataHolderRasterDataHolder184     RasterDataHolder() : fReleaseCount(0) {}
185     sk_sp<SkData> fData;
186     int fReleaseCount;
ReleaseRasterDataHolder187     static void Release(const void* pixels, void* context) {
188         RasterDataHolder* self = static_cast<RasterDataHolder*>(context);
189         self->fReleaseCount++;
190         self->fData.reset();
191     }
192 };
create_rasterproc_image(RasterDataHolder * dataHolder)193 static sk_sp<SkImage> create_rasterproc_image(RasterDataHolder* dataHolder) {
194     SkASSERT(dataHolder);
195     SkImageInfo info;
196     dataHolder->fData = create_image_data(&info);
197     return SkImages::RasterFromPixmap(SkPixmap(info, dataHolder->fData->data(), info.minRowBytes()),
198                                       RasterDataHolder::Release,
199                                       dataHolder);
200 }
create_codec_image()201 static sk_sp<SkImage> create_codec_image() {
202     SkImageInfo info;
203     sk_sp<SkData> data(create_image_data(&info));
204     SkBitmap bitmap;
205     bitmap.installPixels(info, data->writable_data(), info.minRowBytes());
206     SkDynamicMemoryWStream stream;
207     SkASSERT_RELEASE(SkPngEncoder::Encode(&stream, bitmap.pixmap(), {}));
208     return SkImages::DeferredFromEncodedData(stream.detachAsData());
209 }
create_gpu_image(GrRecordingContext * rContext,bool withMips=false,skgpu::Budgeted budgeted=skgpu::Budgeted::kYes)210 static sk_sp<SkImage> create_gpu_image(GrRecordingContext* rContext,
211                                        bool withMips = false,
212                                        skgpu::Budgeted budgeted = skgpu::Budgeted::kYes) {
213     const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
214     auto surface = SkSurfaces::RenderTarget(
215             rContext, budgeted, info, 0, kBottomLeft_GrSurfaceOrigin, nullptr, withMips);
216     draw_image_test_pattern(surface->getCanvas());
217     return surface->makeImageSnapshot();
218 }
219 
test_encode(skiatest::Reporter * reporter,GrDirectContext * dContext,SkImage * image)220 static void test_encode(skiatest::Reporter* reporter, GrDirectContext* dContext, SkImage* image) {
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 
226     sk_sp<SkImage> decoded(SkImages::DeferredFromEncodedData(origEncoded));
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 
DEF_TEST(ImageEncode,reporter)241 DEF_TEST(ImageEncode, reporter) {
242     test_encode(reporter, nullptr, create_image().get());
243 }
244 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageEncode_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)245 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageEncode_Gpu,
246                                        reporter,
247                                        ctxInfo,
248                                        CtsEnforcement::kApiLevel_T) {
249     auto dContext = ctxInfo.directContext();
250     test_encode(reporter, dContext, create_gpu_image(dContext).get());
251 }
252 
DEF_TEST(Image_MakeFromRasterBitmap,reporter)253 DEF_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.
DEF_TEST(Image_Serialize_Encoding_Failure,reporter)286 DEF_TEST(Image_Serialize_Encoding_Failure, reporter) {
287     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
288     surface->getCanvas()->clear(SK_ColorGREEN);
289     sk_sp<SkImage> image(surface->makeImageSnapshot());
290     REPORTER_ASSERT(reporter, image);
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);
297     REPORTER_ASSERT(reporter, picture->approximateOpCount() > 0);
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()).
DEF_TEST(Image_RetainSnapshot,reporter)320 DEF_TEST(Image_RetainSnapshot, reporter) {
321     const SkPMColor red   = SkPackARGB32(0xFF, 0xFF, 0, 0);
322     const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
323     SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2);
324     auto surface(SkSurfaces::Raster(info));
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 
338     SkPaint paint;
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 
make_bitmap_mutable(SkBitmap * bm)354 static void make_bitmap_mutable(SkBitmap* bm) {
355     bm->allocN32Pixels(10, 10);
356 }
357 
make_bitmap_immutable(SkBitmap * bm)358 static void make_bitmap_immutable(SkBitmap* bm) {
359     bm->allocN32Pixels(10, 10);
360     bm->setImmutable();
361 }
362 
DEF_TEST(image_newfrombitmap,reporter)363 DEF_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 
378         sk_sp<SkImage> image(bm.asImage());
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  */
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkImage_Ganesh2Cpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)402 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkImage_Ganesh2Cpu,
403                                        reporter,
404                                        ctxInfo,
405                                        CtsEnforcement::kApiLevel_T) {
406     SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
407     sk_sp<SkImage> image(create_gpu_image(ctxInfo.directContext()));
408     const auto desc = SkBitmapCacheDesc::Make(image.get());
409 
410     auto surface(SkSurfaces::Raster(info));
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 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkImage_makeTextureImage,reporter,contextInfo,CtsEnforcement::kApiLevel_T)439 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkImage_makeTextureImage,
440                                        reporter,
441                                        contextInfo,
442                                        CtsEnforcement::kApiLevel_T) {
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[] = {
449             create_image,
450             create_codec_image,
451             create_data_image,
452             // Create an image from a picture.
453             create_picture_image,
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))) {
475                 REPORTER_ASSERT(
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());
504                 REPORTER_ASSERT(
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);
517                     REPORTER_ASSERT(reporter, !texProxy->getUniqueKey().isValid());
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 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkImage_makeNonTextureImage,reporter,contextInfo,CtsEnforcement::kApiLevel_T)532 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkImage_makeNonTextureImage,
533                                        reporter,
534                                        contextInfo,
535                                        CtsEnforcement::kApiLevel_T) {
536     auto dContext = contextInfo.directContext();
537 
538     std::function<sk_sp<SkImage>()> imageFactories[] = {
539         create_image,
540         create_codec_image,
541         create_data_image,
542         create_picture_image,
543         [dContext] { return create_gpu_image(dContext); },
544     };
545     for (const auto& factory : imageFactories) {
546         sk_sp<SkImage> image = factory();
547         if (!image->isTextureBacked()) {
548             REPORTER_ASSERT(reporter, image->makeNonTextureImage().get() == image.get());
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 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsImage,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)562 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsImage,
563                                        reporter,
564                                        ctxInfo,
565                                        CtsEnforcement::kApiLevel_T) {
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(),
585                                               kTopLeft_GrSurfaceOrigin,
586                                               colorType,
587                                               kOpaque_SkAlphaType,
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 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(UnpremulTextureImage,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)596 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(UnpremulTextureImage,
597                                        reporter,
598                                        ctxInfo,
599                                        CtsEnforcement::kApiLevel_T) {
600     SkBitmap bmp;
601     bmp.allocPixels(
602             SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, nullptr));
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;
616     unpremul.allocPixels(SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType,
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     }
632     SkBitmap premul;
633     premul.allocPixels(
634             SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr));
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 
DEF_GANESH_TEST(AbandonedContextImage,reporter,options,CtsEnforcement::kApiLevel_T)667 DEF_GANESH_TEST(AbandonedContextImage, reporter, options, CtsEnforcement::kApiLevel_T) {
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),
679                 skgpu::Budgeted::kYes,
680                 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
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 
708 class EmptyGenerator : public SkImageGenerator {
709 public:
EmptyGenerator()710     EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {}
711 };
712 
DEF_TEST(ImageEmpty,reporter)713 DEF_TEST(ImageEmpty, reporter) {
714     const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
715     SkPixmap pmap(info, nullptr, 0);
716     REPORTER_ASSERT(reporter, nullptr == SkImages::RasterFromPixmapCopy(pmap));
717     REPORTER_ASSERT(reporter, nullptr == SkImages::RasterFromData(info, nullptr, 0));
718     REPORTER_ASSERT(reporter, nullptr == SkImages::RasterFromPixmap(pmap, nullptr, nullptr));
719     REPORTER_ASSERT(reporter,
720                     nullptr == SkImages::DeferredFromGenerator(std::make_unique<EmptyGenerator>()));
721 }
722 
DEF_TEST(ImageDataRef,reporter)723 DEF_TEST(ImageDataRef, reporter) {
724     SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
725     size_t rowBytes = info.minRowBytes();
726     size_t size = info.computeByteSize(rowBytes);
727     sk_sp<SkData> data = SkData::MakeUninitialized(size);
728     REPORTER_ASSERT(reporter, data->unique());
729     sk_sp<SkImage> image = SkImages::RasterFromData(info, data, rowBytes);
730     REPORTER_ASSERT(reporter, !data->unique());
731     image.reset();
732     REPORTER_ASSERT(reporter, data->unique());
733 }
734 
has_pixels(const SkPMColor pixels[],int count,SkPMColor expected)735 static 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 
image_test_read_pixels(GrDirectContext * dContext,skiatest::Reporter * reporter,SkImage * image)744 static void image_test_read_pixels(GrDirectContext* dContext, skiatest::Reporter* reporter,
745                                    SkImage* image) {
746     if (!image) {
747         ERRORF(reporter, "Failed to create image!");
748         return;
749     }
750     const SkPMColor expected = SkPreMultiplyColor(SK_ColorWHITE);
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 
757     SkImageInfo info;
758 
759     info = SkImageInfo::MakeUnknown(w, h);
760     REPORTER_ASSERT(reporter, !image->readPixels(dContext, info, pixels, rowBytes, 0, 0));
761 
762     // out-of-bounds should fail
763     info = SkImageInfo::MakeN32Premul(w, h);
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 }
DEF_TEST(ImageReadPixels,reporter)795 DEF_TEST(ImageReadPixels, reporter) {
796     sk_sp<SkImage> image(create_image());
797     image_test_read_pixels(nullptr, reporter, image.get());
798 
799     image = create_data_image();
800     image_test_read_pixels(nullptr, reporter, image.get());
801 
802     RasterDataHolder dataHolder;
803     image = create_rasterproc_image(&dataHolder);
804     image_test_read_pixels(nullptr, reporter, image.get());
805     image.reset();
806     REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
807 
808     image = create_codec_image();
809     image_test_read_pixels(nullptr, reporter, image.get());
810 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageReadPixels_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)811 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageReadPixels_Gpu,
812                                        reporter,
813                                        ctxInfo,
814                                        CtsEnforcement::kApiLevel_T) {
815     auto dContext = ctxInfo.directContext();
816     image_test_read_pixels(dContext, reporter, create_gpu_image(dContext).get());
817 }
818 
check_legacy_bitmap(skiatest::Reporter * reporter,GrDirectContext * dContext,const SkImage * image,const SkBitmap & bitmap)819 static void check_legacy_bitmap(skiatest::Reporter* reporter, GrDirectContext* dContext,
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 
test_legacy_bitmap(skiatest::Reporter * reporter,GrDirectContext * dContext,const SkImage * image)836 static void test_legacy_bitmap(skiatest::Reporter* reporter, GrDirectContext* dContext,
837                                const SkImage* image) {
838     if (!image) {
839         ERRORF(reporter, "Failed to create image.");
840         return;
841     }
842     SkBitmap bitmap;
843     REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap));
844     check_legacy_bitmap(reporter, dContext, image, bitmap);
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 }
DEF_TEST(ImageLegacyBitmap,reporter)857 DEF_TEST(ImageLegacyBitmap, reporter) {
858     sk_sp<SkImage> image(create_image());
859     test_legacy_bitmap(reporter, nullptr, image.get());
860 
861     image = create_data_image();
862     test_legacy_bitmap(reporter, nullptr, image.get());
863 
864     RasterDataHolder dataHolder;
865     image = create_rasterproc_image(&dataHolder);
866     test_legacy_bitmap(reporter, nullptr, image.get());
867     image.reset();
868     REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
869 
870     image = create_codec_image();
871     test_legacy_bitmap(reporter, nullptr, image.get());
872 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageLegacyBitmap_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)873 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageLegacyBitmap_Gpu,
874                                        reporter,
875                                        ctxInfo,
876                                        CtsEnforcement::kApiLevel_T) {
877     auto dContext = ctxInfo.directContext();
878     sk_sp<SkImage> image(create_gpu_image(dContext));
879     test_legacy_bitmap(reporter, dContext, image.get());
880 }
881 
test_peek(skiatest::Reporter * reporter,SkImage * image,bool expectPeekSuccess)882 static 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());
895         REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
896                         kOpaque_SkAlphaType == info.alphaType());
897         REPORTER_ASSERT(reporter, info.minRowBytes() <= pm.rowBytes());
898         REPORTER_ASSERT(reporter, SkPreMultiplyColor(SK_ColorWHITE) == *pm.addr32(0, 0));
899     }
900 }
DEF_TEST(ImagePeek,reporter)901 DEF_TEST(ImagePeek, reporter) {
902     sk_sp<SkImage> image(create_image());
903     test_peek(reporter, image.get(), true);
904 
905     image = create_data_image();
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 
914     image = create_codec_image();
915     test_peek(reporter, image.get(), false);
916 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImagePeek_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)917 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImagePeek_Gpu,
918                                        reporter,
919                                        ctxInfo,
920                                        CtsEnforcement::kApiLevel_T) {
921     sk_sp<SkImage> image(create_gpu_image(ctxInfo.directContext()));
922     test_peek(reporter, image.get(), false);
923 }
924 
925 struct TextureReleaseChecker {
TextureReleaseCheckerTextureReleaseChecker926     TextureReleaseChecker() : fReleaseCount(0) {}
927     int fReleaseCount;
ReleaseTextureReleaseChecker928     static void Release(void* self) {
929         static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
930     }
931 };
932 
DEF_GANESH_TEST_FOR_GL_CONTEXT(SkImage_NewFromTextureRelease,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)933 DEF_GANESH_TEST_FOR_GL_CONTEXT(SkImage_NewFromTextureRelease,
934                                reporter,
935                                ctxInfo,
936                                CtsEnforcement::kApiLevel_T) {
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,
945                                                                     kRGBA_8888_SkColorType,
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;
955     GrSurfaceOrigin texOrigin = kBottomLeft_GrSurfaceOrigin;
956     sk_sp<SkImage> refImg = SkImages::BorrowTextureFrom(
957             dContext,
958             mbet->texture(),
959             texOrigin,
960             kRGBA_8888_SkColorType,
961             kPremul_SkAlphaType,
962             /*color space*/ nullptr,
963             sk_gpu_test::ManagedBackendTexture::ReleaseProc,
964             mbet->releaseContext(TextureReleaseChecker::Release, &releaseChecker));
965 
966     GrSurfaceOrigin readBackOrigin;
967     GrBackendTexture readBackBackendTex;
968     REPORTER_ASSERT(reporter,
969                     SkImages::GetBackendTextureFromImage(
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     }
975     REPORTER_ASSERT(reporter,
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 
test_cross_context_image(skiatest::Reporter * reporter,const GrContextOptions & options,const char * testName,const std::function<sk_sp<SkImage> (GrDirectContext *)> & imageMaker)988 static void test_cross_context_image(
989         skiatest::Reporter* reporter,
990         const GrContextOptions& options,
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 
1023         SkImageInfo info = SkImageInfo::MakeN32Premul(128, 128);
1024         sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info);
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 
1064         surface = SkSurfaces::RenderTarget(otherCtx, skgpu::Budgeted::kNo, info);
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);
1110             REPORTER_ASSERT(reporter, view);
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 
DEF_GANESH_TEST(SkImage_MakeCrossContextFromPixmapRelease,reporter,options,CtsEnforcement::kApiLevel_T)1151 DEF_GANESH_TEST(SkImage_MakeCrossContextFromPixmapRelease,
1152                 reporter,
1153                 options,
1154                 CtsEnforcement::kApiLevel_T) {
1155     SkBitmap bitmap;
1156     SkPixmap pixmap;
1157     if (!ToolUtils::GetResourceAsBitmap("images/mandrill_128.png", &bitmap) ||
1158         !bitmap.peekPixels(&pixmap)) {
1159         ERRORF(reporter, "missing resource");
1160         return;
1161     }
1162     test_cross_context_image(reporter,
1163                              options,
1164                              "SkImage_MakeCrossContextFromPixmapRelease",
1165                              [&pixmap](GrDirectContext* dContext) {
1166                                  return SkImages::CrossContextTextureFromPixmap(
1167                                          dContext, pixmap, false);
1168                              });
1169 }
1170 
DEF_GANESH_TEST(SkImage_CrossContextGrayAlphaConfigs,reporter,options,CtsEnforcement::kApiLevel_T)1171 DEF_GANESH_TEST(SkImage_CrossContextGrayAlphaConfigs,
1172                 reporter,
1173                 options,
1174                 CtsEnforcement::kApiLevel_T) {
1175     for (SkColorType ct : { kGray_8_SkColorType, kAlpha_8_SkColorType }) {
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 
1188             sk_sp<SkImage> image = SkImages::CrossContextTextureFromPixmap(dContext, pixmap, false);
1189             REPORTER_ASSERT(reporter, image);
1190 
1191             auto [view, viewCT] = skgpu::ganesh::AsView(dContext, image, skgpu::Mipmapped::kNo);
1192             REPORTER_ASSERT(reporter, view);
1193             REPORTER_ASSERT(reporter, GrColorTypeToSkColorType(viewCT) == ct);
1194 
1195             bool expectAlpha = kAlpha_8_SkColorType == ct;
1196             GrColorType grCT = SkColorTypeToGrColorType(image->colorType());
1197             REPORTER_ASSERT(reporter, expectAlpha == GrColorTypeIsAlphaOnly(grCT));
1198         }
1199     }
1200 }
1201 
DEF_GANESH_TEST_FOR_GL_CONTEXT(makeBackendTexture,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1202 DEF_GANESH_TEST_FOR_GL_CONTEXT(makeBackendTexture, reporter, ctxInfo, CtsEnforcement::kApiLevel_T) {
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;
1251         SkImages::BackendTextureReleaseProc proc;
1252         bool result = SkImages::MakeBackendTextureFromImage(
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 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageBackendAccessAbandoned_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1275 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageBackendAccessAbandoned_Gpu,
1276                                        reporter,
1277                                        ctxInfo,
1278                                        CtsEnforcement::kApiLevel_T) {
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);
1287     REPORTER_ASSERT(reporter, ok);
1288     REPORTER_ASSERT(reporter, beTex.isValid());
1289 
1290     dContext->abandonContext();
1291 
1292     // After abandoning the context the backend texture should not be valid.
1293     ok = SkImages::GetBackendTextureFromImage(image, &beTex, true);
1294     REPORTER_ASSERT(reporter, !ok);
1295 }
1296 
1297 ///////////////////////////////////////////////////////////////////////////////////////////////////
1298 
create_picture_image(sk_sp<SkColorSpace> space)1299 static sk_sp<SkImage> create_picture_image(sk_sp<SkColorSpace> space) {
1300     SkPictureRecorder recorder;
1301     SkCanvas* canvas = recorder.beginRecording(10, 10);
1302     canvas->clear(SK_ColorCYAN);
1303     return SkImages::DeferredFromPicture(recorder.finishRecordingAsPicture(),
1304                                          SkISize::Make(10, 10),
1305                                          nullptr,
1306                                          nullptr,
1307                                          SkImages::BitDepth::kU8,
1308                                          std::move(space));
1309 }
1310 
DEF_TEST(Image_ColorSpace,r)1311 DEF_TEST(Image_ColorSpace, r) {
1312     sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
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");
1317     skcms_TransferFunction fn;
1318     bool success = image->colorSpace()->isNumericalTransferFn(&fn);
1319     REPORTER_ASSERT(r, success);
1320     REPORTER_ASSERT(r, color_space_almost_equal(1.8f, fn.g));
1321 
1322     sk_sp<SkColorSpace> rec2020 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
1323                                                         SkNamedGamut::kRec2020);
1324     image = create_picture_image(rec2020);
1325     REPORTER_ASSERT(r, SkColorSpace::Equals(rec2020.get(), image->colorSpace()));
1326 
1327     SkBitmap bitmap;
1328     SkImageInfo info = SkImageInfo::MakeN32(10, 10, kPremul_SkAlphaType, rec2020);
1329     bitmap.allocPixels(info);
1330     image = bitmap.asImage();
1331     REPORTER_ASSERT(r, SkColorSpace::Equals(rec2020.get(), image->colorSpace()));
1332 
1333     sk_sp<SkSurface> surface =
1334             SkSurfaces::Raster(SkImageInfo::MakeN32Premul(SkISize::Make(10, 10)));
1335     image = surface->makeImageSnapshot();
1336     REPORTER_ASSERT(r, nullptr == image->colorSpace());
1337 
1338     surface = SkSurfaces::Raster(info);
1339     image = surface->makeImageSnapshot();
1340     REPORTER_ASSERT(r, SkColorSpace::Equals(rec2020.get(), image->colorSpace()));
1341 }
1342 
DEF_TEST(Image_makeColorSpace,r)1343 DEF_TEST(Image_makeColorSpace, r) {
1344     sk_sp<SkColorSpace> p3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
1345     skcms_TransferFunction fn;
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;
1347     sk_sp<SkColorSpace> adobeGamut = SkColorSpace::MakeRGB(fn, SkNamedGamut::kAdobeRGB);
1348 
1349     SkBitmap srgbBitmap;
1350     srgbBitmap.allocPixels(SkImageInfo::MakeS32(1, 1, kOpaque_SkAlphaType));
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 
make_all_premul(SkBitmap * bm)1384 static void make_all_premul(SkBitmap* bm) {
1385     bm->allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType));
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 
equal(const SkBitmap & a,const SkBitmap & b)1395 static 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 
DEF_TEST(image_roundtrip_encode,reporter)1410 DEF_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;
1419     bm1.allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType));
1420     img1->readPixels(nullptr, bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0);
1421 
1422     REPORTER_ASSERT(reporter, equal(bm0, bm1));
1423 }
1424 
DEF_TEST(image_roundtrip_premul,reporter)1425 DEF_TEST(image_roundtrip_premul, reporter) {
1426     SkBitmap bm0;
1427     make_all_premul(&bm0);
1428 
1429     SkBitmap bm1;
1430     bm1.allocPixels(SkImageInfo::MakeN32(256, 256, kUnpremul_SkAlphaType));
1431     bm0.readPixels(bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0);
1432 
1433     SkBitmap bm2;
1434     bm2.allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType));
1435     bm1.readPixels(bm2.info(), bm2.getPixels(), bm2.rowBytes(), 0, 0);
1436 
1437     REPORTER_ASSERT(reporter, equal(bm0, bm2));
1438 }
1439 
DEF_TEST(image_from_encoded_alphatype_override,reporter)1440 DEF_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
1445     REPORTER_ASSERT(reporter, SkImages::DeferredFromEncodedData(data, kPremul_SkAlphaType));
1446     REPORTER_ASSERT(reporter, SkImages::DeferredFromEncodedData(data, kUnpremul_SkAlphaType));
1447     REPORTER_ASSERT(reporter, !SkImages::DeferredFromEncodedData(data, kOpaque_SkAlphaType));
1448 
1449     // Same tests as above, but using SkImageGenerators::MakeFromEncoded
1450     REPORTER_ASSERT(reporter, SkImageGenerators::MakeFromEncoded(data, kPremul_SkAlphaType));
1451     REPORTER_ASSERT(reporter, SkImageGenerators::MakeFromEncoded(data, kUnpremul_SkAlphaType));
1452     REPORTER_ASSERT(reporter, !SkImageGenerators::MakeFromEncoded(data, kOpaque_SkAlphaType));
1453 }
1454 
1455 ///////////////////////////////////////////////////////////////////////////////////////////////////
1456 
check_scaled_pixels(skiatest::Reporter * reporter,SkPixmap * pmap,uint32_t expected)1457 static 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 
test_scale_pixels(skiatest::Reporter * reporter,const SkImage * image,uint32_t expected)1471 static void test_scale_pixels(skiatest::Reporter* reporter, const SkImage* image,
1472                               uint32_t expected) {
1473     SkImageInfo info = SkImageInfo::MakeN32Premul(image->width() * 2, image->height() * 2);
1474 
1475     // Make sure to test kDisallow first, so we don't just get a cache hit in that case
1476     for (auto chint : { SkImage::kDisallow_CachingHint, SkImage::kAllow_CachingHint }) {
1477         SkAutoPixmapStorage scaled;
1478         scaled.alloc(info);
1479         if (!image->scalePixels(scaled, SkSamplingOptions(SkFilterMode::kLinear), chint)) {
1480             ERRORF(reporter, "Failed to scale image");
1481             continue;
1482         }
1483 
1484         check_scaled_pixels(reporter, &scaled, expected);
1485     }
1486 }
1487 
DEF_TEST(ImageScalePixels,reporter)1488 DEF_TEST(ImageScalePixels, reporter) {
1489     const SkPMColor pmRed = SkPackARGB32(0xFF, 0xFF, 0, 0);
1490     const SkColor red = SK_ColorRED;
1491 
1492     // Test raster image
1493     SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
1494     sk_sp<SkSurface> surface = SkSurfaces::Raster(info);
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(), {});
1501     sk_sp<SkImage> codecImage = SkImages::DeferredFromEncodedData(data);
1502     test_scale_pixels(reporter, codecImage.get(), pmRed);
1503 }
1504 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageScalePixels_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1505 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageScalePixels_Gpu,
1506                                        reporter,
1507                                        ctxInfo,
1508                                        CtsEnforcement::kApiLevel_T) {
1509     const SkPMColor pmRed = SkPackARGB32(0xFF, 0xFF, 0, 0);
1510     const SkColor red = SK_ColorRED;
1511 
1512     SkImageInfo info = SkImageInfo::MakeN32Premul(16, 16);
1513     sk_sp<SkSurface> surface =
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 
any_image_will_do()1520 static sk_sp<SkImage> any_image_will_do() {
1521     return ToolUtils::GetResourceAsImage("images/mandrill_32.png");
1522 }
1523 
DEF_TEST(Image_nonfinite_dst,reporter)1524 DEF_TEST(Image_nonfinite_dst, reporter) {
1525     auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10));
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 
make_yuva_image(GrDirectContext * dContext)1547 static sk_sp<SkImage> make_yuva_image(GrDirectContext* dContext) {
1548     SkAutoPixmapStorage pm;
1549     pm.alloc(SkImageInfo::Make(1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
1550     SkYUVAInfo yuvaInfo({1, 1},
1551                         SkYUVAInfo::PlaneConfig::kY_U_V,
1552                         SkYUVAInfo::Subsampling::k444,
1553                         kJPEG_Full_SkYUVColorSpace);
1554     const SkPixmap pmaps[] = {pm, pm, pm};
1555     auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, pmaps);
1556 
1557     return SkImages::TextureFromYUVAPixmaps(dContext, yuvaPixmaps);
1558 }
1559 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ImageFlush,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1560 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ImageFlush, reporter, ctxInfo, CtsEnforcement::kApiLevel_T) {
1561     auto dContext = ctxInfo.directContext();
1562     auto ii = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
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 
1638 constexpr SkM44 gCentripetalCatmulRom
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 
1644 constexpr SkM44 gMitchellNetravali
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 
DEF_TEST(image_cubicresampler,reporter)1650 DEF_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 
1661     diff(SkImageShader::CubicResamplerMatrix(1.0f/3, 1.0f/3), gMitchellNetravali);
1662 
1663     diff(SkImageShader::CubicResamplerMatrix(0, 1.0f/2), gCentripetalCatmulRom);
1664 }
1665 
DEF_TEST(image_subset_encode_skbug_7752,reporter)1666 DEF_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 }
1680