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