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