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