blob: 1c6b36c16af8ab2daaeea6c45201e4942474f0ea [file] [log] [blame]
robertphillipsb6c65e92016-02-04 10:52:42 -08001/*
2 * Copyright 2016 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkBitmap.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkImage.h"
11#include "include/core/SkPixmap.h"
12#include "include/core/SkSurface.h"
13#include "src/core/SkAutoPixmapStorage.h"
14#include "src/core/SkSpecialImage.h"
15#include "src/core/SkSpecialSurface.h"
16#include "tests/Test.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080017
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "include/gpu/GrBackendSurface.h"
19#include "include/gpu/GrContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrContextPriv.h"
21#include "src/gpu/GrProxyProvider.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040022#include "src/gpu/GrSurfaceProxy.h"
23#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/SkGr.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080025
robertphillipsb6c65e92016-02-04 10:52:42 -080026
27// This test creates backing resources exactly sized to [kFullSize x kFullSize].
28// It then wraps them in an SkSpecialImage with only the center (red) region being active.
29// It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
30// of the inactive (green) region leaked out.
31
32static const int kSmallerSize = 10;
33static const int kPad = 3;
34static const int kFullSize = kSmallerSize + 2 * kPad;
35
36// Create a bitmap with red in the center and green around it
37static SkBitmap create_bm() {
38 SkBitmap bm;
39 bm.allocN32Pixels(kFullSize, kFullSize, true);
40
41 SkCanvas temp(bm);
42
43 temp.clear(SK_ColorGREEN);
44 SkPaint p;
45 p.setColor(SK_ColorRED);
46 p.setAntiAlias(false);
47
48 temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
halcanary9d524f22016-03-29 09:03:52 -070049 SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
robertphillipsb6c65e92016-02-04 10:52:42 -080050 p);
51
52 return bm;
53}
54
55// Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
robertphillips37bd7c32016-03-17 14:31:39 -070056static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
Michael Ludwigb4580352019-06-21 16:01:42 -040057 GrContext* context, bool isGPUBacked) {
robertphillips3e302272016-04-20 11:48:36 -070058 const SkIRect subset = img->subset();
Michael Ludwigb4580352019-06-21 16:01:42 -040059 REPORTER_ASSERT(reporter, kPad == subset.left());
60 REPORTER_ASSERT(reporter, kPad == subset.top());
robertphillipsb6c65e92016-02-04 10:52:42 -080061 REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
62 REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
63
64 //--------------
Robert Phillips2c6d2bf2017-02-21 10:19:29 -050065 // Test that isTextureBacked reports the correct backing type
Robert Phillips6de99042017-01-31 11:31:39 -050066 REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked());
robertphillips64612512016-04-08 12:10:42 -070067
robertphillips64612512016-04-08 12:10:42 -070068 //--------------
Robert Phillips8e1c4e62017-02-19 12:27:01 -050069 // Test asTextureProxyRef - as long as there is a context this should succeed
robertphillips64612512016-04-08 12:10:42 -070070 if (context) {
Robert Phillips8e1c4e62017-02-19 12:27:01 -050071 sk_sp<GrTextureProxy> proxy(img->asTextureProxyRef(context));
72 REPORTER_ASSERT(reporter, proxy);
robertphillips64612512016-04-08 12:10:42 -070073 }
robertphillipsb6c65e92016-02-04 10:52:42 -080074
75 //--------------
robertphillips64612512016-04-08 12:10:42 -070076 // Test getROPixels - this should always succeed regardless of backing store
77 SkBitmap bitmap;
78 REPORTER_ASSERT(reporter, img->getROPixels(&bitmap));
Michael Ludwigb4580352019-06-21 16:01:42 -040079 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
80 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
robertphillipsb6c65e92016-02-04 10:52:42 -080081
82 //--------------
robertphillipsb4bd11e2016-03-21 13:44:18 -070083 // Test that draw restricts itself to the subset
Brian Osmana50205f2018-07-06 13:57:01 -040084 SkImageFilter::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
brianosmaneed6b0e2016-09-23 13:04:05 -070085 sk_sp<SkSpecialSurface> surf(img->makeSurface(outProps, SkISize::Make(kFullSize, kFullSize),
Matt Sarettcb6266b2017-01-17 10:48:53 -050086 kPremul_SkAlphaType));
robertphillipsb6c65e92016-02-04 10:52:42 -080087
88 SkCanvas* canvas = surf->getCanvas();
89
90 canvas->clear(SK_ColorBLUE);
robertphillipse8c34972016-02-16 12:09:36 -080091 img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad), nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -080092
93 SkBitmap bm;
Matt Sarettcb6266b2017-01-17 10:48:53 -050094 bm.allocN32Pixels(kFullSize, kFullSize, false);
robertphillipsb6c65e92016-02-04 10:52:42 -080095
96 bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
97 SkASSERT_RELEASE(result);
98
99 // Only the center (red) portion should've been drawn into the canvas
100 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
101 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad));
102 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1,
103 kSmallerSize+kPad-1));
104 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
105 kSmallerSize+kPad));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700106
107 //--------------
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500108 // Test that asImage & makeTightSurface return appropriately sized objects
robertphillipsb4bd11e2016-03-21 13:44:18 -0700109 // of the correct backing type
110 SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height());
111 {
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500112 sk_sp<SkImage> tightImg(img->asImage(&newSubset));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700113
114 REPORTER_ASSERT(reporter, tightImg->width() == subset.width());
115 REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400116 REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked());
robertphillipsb4bd11e2016-03-21 13:44:18 -0700117 SkPixmap tmpPixmap;
Robert Phillips6de99042017-01-31 11:31:39 -0500118 REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700119 }
120 {
Brian Osmana50205f2018-07-06 13:57:01 -0400121 SkImageFilter::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
brianosmaneed6b0e2016-09-23 13:04:05 -0700122 sk_sp<SkSurface> tightSurf(img->makeTightSurface(outProps, subset.size()));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700123
124 REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
125 REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
Robert Phillips8caf85f2018-04-05 09:30:38 -0400126 GrBackendTexture backendTex = tightSurf->getBackendTexture(
127 SkSurface::kDiscardWrite_BackendHandleAccess);
128 REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid());
robertphillipsb4bd11e2016-03-21 13:44:18 -0700129 SkPixmap tmpPixmap;
Robert Phillips6de99042017-01-31 11:31:39 -0500130 REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700131 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800132}
133
134DEF_TEST(SpecialImage_Raster, reporter) {
135 SkBitmap bm = create_bm();
136
robertphillips37bd7c32016-03-17 14:31:39 -0700137 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster(
robertphillipsc5035e72016-03-17 06:58:39 -0700138 SkIRect::MakeWH(kFullSize, kFullSize),
139 bm));
140
robertphillipsb6c65e92016-02-04 10:52:42 -0800141 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
142
robertphillipsc5035e72016-03-17 06:58:39 -0700143 {
robertphillips3e302272016-04-20 11:48:36 -0700144 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm));
Michael Ludwigb4580352019-06-21 16:01:42 -0400145 test_image(subSImg1, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700146 }
147
148 {
robertphillips37bd7c32016-03-17 14:31:39 -0700149 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400150 test_image(subSImg2, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700151 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800152}
153
Brian Osmanb9c49782018-10-12 12:01:22 -0400154static void test_specialimage_image(skiatest::Reporter* reporter) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800155 SkBitmap bm = create_bm();
156
reed9ce9d672016-03-17 10:51:11 -0700157 sk_sp<SkImage> fullImage(SkImage::MakeFromBitmap(bm));
robertphillipsb6c65e92016-02-04 10:52:42 -0800158
robertphillips37bd7c32016-03-17 14:31:39 -0700159 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage(
Robert Phillips27467652019-01-10 16:34:22 -0500160 nullptr,
robertphillipsc5035e72016-03-17 06:58:39 -0700161 SkIRect::MakeWH(kFullSize, kFullSize),
Brian Osmanb9c49782018-10-12 12:01:22 -0400162 fullImage));
robertphillipsc5035e72016-03-17 06:58:39 -0700163
robertphillipsb6c65e92016-02-04 10:52:42 -0800164 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
165
robertphillipsc5035e72016-03-17 06:58:39 -0700166 {
Robert Phillips27467652019-01-10 16:34:22 -0500167 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset, fullImage));
Michael Ludwigb4580352019-06-21 16:01:42 -0400168 test_image(subSImg1, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700169 }
170
171 {
robertphillips37bd7c32016-03-17 14:31:39 -0700172 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400173 test_image(subSImg2, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700174 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800175}
176
Brian Osman7992da32016-11-18 11:28:24 -0500177DEF_TEST(SpecialImage_Image_Legacy, reporter) {
Brian Osmanb9c49782018-10-12 12:01:22 -0400178 test_specialimage_image(reporter);
Brian Osman7992da32016-11-18 11:28:24 -0500179}
180
robertphillips83c17fa2016-03-18 08:14:27 -0700181static void test_texture_backed(skiatest::Reporter* reporter,
182 const sk_sp<SkSpecialImage>& orig,
183 const sk_sp<SkSpecialImage>& gpuBacked) {
184 REPORTER_ASSERT(reporter, gpuBacked);
robertphillips64612512016-04-08 12:10:42 -0700185 REPORTER_ASSERT(reporter, gpuBacked->isTextureBacked());
robertphillips83c17fa2016-03-18 08:14:27 -0700186 REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID());
187 REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() &&
188 gpuBacked->subset().height() == orig->subset().height());
brianosmanafbf71d2016-07-21 07:15:37 -0700189 REPORTER_ASSERT(reporter, gpuBacked->getColorSpace() == orig->getColorSpace());
robertphillips83c17fa2016-03-18 08:14:27 -0700190}
191
192// Test out the SkSpecialImage::makeTextureImage entry point
bsalomon68d91342016-04-12 09:59:58 -0700193DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700194 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500195 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
robertphillips83c17fa2016-03-18 08:14:27 -0700196 SkBitmap bm = create_bm();
197
198 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
199
200 {
201 // raster
202 sk_sp<SkSpecialImage> rasterImage(SkSpecialImage::MakeFromRaster(
robertphillips83c17fa2016-03-18 08:14:27 -0700203 SkIRect::MakeWH(kFullSize,
204 kFullSize),
205 bm));
206
207 {
robertphillips3e302272016-04-20 11:48:36 -0700208 sk_sp<SkSpecialImage> fromRaster(rasterImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700209 test_texture_backed(reporter, rasterImage, fromRaster);
210 }
211
212 {
213 sk_sp<SkSpecialImage> subRasterImage(rasterImage->makeSubset(subset));
214
robertphillips3e302272016-04-20 11:48:36 -0700215 sk_sp<SkSpecialImage> fromSubRaster(subRasterImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700216 test_texture_backed(reporter, subRasterImage, fromSubRaster);
217 }
218 }
219
220 {
221 // gpu
Brian Osman2700abc2018-09-12 10:19:41 -0400222 sk_sp<SkImage> rasterImage = SkImage::MakeFromBitmap(bm);
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400223 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
224 rasterImage, GrRenderable::kNo, 1, SkBudgeted::kNo, SkBackingFit::kExact);
Robert Phillips2f493142017-03-02 18:18:38 -0500225 if (!proxy) {
robertphillips83c17fa2016-03-18 08:14:27 -0700226 return;
227 }
228
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500229 sk_sp<SkSpecialImage> gpuImage(SkSpecialImage::MakeDeferredFromGpu(
Robert Phillips2f493142017-03-02 18:18:38 -0500230 context,
231 SkIRect::MakeWH(kFullSize, kFullSize),
232 kNeedNewImageUniqueID_SpecialImage,
233 std::move(proxy), nullptr));
robertphillips83c17fa2016-03-18 08:14:27 -0700234
235 {
robertphillips3e302272016-04-20 11:48:36 -0700236 sk_sp<SkSpecialImage> fromGPU(gpuImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700237 test_texture_backed(reporter, gpuImage, fromGPU);
238 }
239
240 {
241 sk_sp<SkSpecialImage> subGPUImage(gpuImage->makeSubset(subset));
242
robertphillips3e302272016-04-20 11:48:36 -0700243 sk_sp<SkSpecialImage> fromSubGPU(subGPUImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700244 test_texture_backed(reporter, subGPUImage, fromSubGPU);
245 }
246 }
247}
248
bsalomon68d91342016-04-12 09:59:58 -0700249DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700250 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500251 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
robertphillipsb6c65e92016-02-04 10:52:42 -0800252 SkBitmap bm = create_bm();
Brian Osman2700abc2018-09-12 10:19:41 -0400253 sk_sp<SkImage> rasterImage = SkImage::MakeFromBitmap(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800254
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400255 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
256 rasterImage, GrRenderable::kNo, 1, SkBudgeted::kNo, SkBackingFit::kExact);
Robert Phillips2f493142017-03-02 18:18:38 -0500257 if (!proxy) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800258 return;
259 }
260
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500261 sk_sp<SkSpecialImage> fullSImg(SkSpecialImage::MakeDeferredFromGpu(
262 context,
robertphillipsc5035e72016-03-17 06:58:39 -0700263 SkIRect::MakeWH(kFullSize, kFullSize),
264 kNeedNewImageUniqueID_SpecialImage,
Robert Phillips2f493142017-03-02 18:18:38 -0500265 proxy, nullptr));
robertphillipsc5035e72016-03-17 06:58:39 -0700266
robertphillipsb6c65e92016-02-04 10:52:42 -0800267 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
268
robertphillipsc5035e72016-03-17 06:58:39 -0700269 {
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500270 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeDeferredFromGpu(
Robert Phillips2f493142017-03-02 18:18:38 -0500271 context, subset,
robertphillipsc5035e72016-03-17 06:58:39 -0700272 kNeedNewImageUniqueID_SpecialImage,
Robert Phillips2f493142017-03-02 18:18:38 -0500273 std::move(proxy), nullptr));
Michael Ludwigb4580352019-06-21 16:01:42 -0400274 test_image(subSImg1, reporter, context, true);
robertphillipsc5035e72016-03-17 06:58:39 -0700275 }
276
277 {
robertphillips37bd7c32016-03-17 14:31:39 -0700278 sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400279 test_image(subSImg2, reporter, context, true);
robertphillipsc5035e72016-03-17 06:58:39 -0700280 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800281}
Brian Osmanba651682018-10-05 11:13:04 -0400282
283DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_ReadbackAndCachingSubsets_Gpu, reporter, ctxInfo) {
284 GrContext* context = ctxInfo.grContext();
285 SkImageInfo ii = SkImageInfo::Make(50, 50, kN32_SkColorType, kPremul_SkAlphaType);
286 auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
287
288 // Fill out our surface:
289 // Green | Blue
290 // Red | Green
291 {
292 surface->getCanvas()->clear(SK_ColorGREEN);
293 SkPaint p;
294 p.setColor(SK_ColorRED);
295 surface->getCanvas()->drawRect(SkRect::MakeXYWH(0, 25, 25, 25), p);
296 p.setColor(SK_ColorBLUE);
297 surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 0, 25, 25), p);
298 }
299
300 auto image = surface->makeImageSnapshot();
Robert Phillips27467652019-01-10 16:34:22 -0500301 auto redImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(10, 30, 10, 10), image);
302 auto blueImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(30, 10, 10, 10), image);
Brian Osmanba651682018-10-05 11:13:04 -0400303
304 // This isn't necessary, but if it ever becomes false, then the cache collision bug that we're
305 // checking below is irrelevant.
306 REPORTER_ASSERT(reporter, redImg->uniqueID() == blueImg->uniqueID());
307
308 SkBitmap redBM, blueBM;
309 SkAssertResult(redImg->getROPixels(&redBM));
310 SkAssertResult(blueImg->getROPixels(&blueBM));
311
312 // Each image should read from the correct sub-rect. Past bugs (skbug.com/8448) have included:
313 // - Always reading back from (0, 0), producing green
314 // - Incorrectly hitting the cache on the 2nd read-back, causing blueBM to be red
315 REPORTER_ASSERT(reporter, redBM.getColor(0, 0) == SK_ColorRED,
316 "0x%08x != 0x%08x", redBM.getColor(0, 0), SK_ColorRED);
317 REPORTER_ASSERT(reporter, blueBM.getColor(0, 0) == SK_ColorBLUE,
318 "0x%08x != 0x%08x", blueBM.getColor(0, 0), SK_ColorBLUE);
319}