blob: f335411c80c8f2ed2b5a91c299cc4f2c57f53efb [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() {
Robert Phillips40b05c32019-09-20 12:40:55 -040038 SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType,
39 kPremul_SkAlphaType);
40
robertphillipsb6c65e92016-02-04 10:52:42 -080041 SkBitmap bm;
Robert Phillips40b05c32019-09-20 12:40:55 -040042 bm.allocPixels(ii);
robertphillipsb6c65e92016-02-04 10:52:42 -080043
44 SkCanvas temp(bm);
45
46 temp.clear(SK_ColorGREEN);
47 SkPaint p;
48 p.setColor(SK_ColorRED);
49 p.setAntiAlias(false);
50
51 temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
halcanary9d524f22016-03-29 09:03:52 -070052 SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
robertphillipsb6c65e92016-02-04 10:52:42 -080053 p);
54
55 return bm;
56}
57
58// Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
robertphillips37bd7c32016-03-17 14:31:39 -070059static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
Michael Ludwigb4580352019-06-21 16:01:42 -040060 GrContext* context, bool isGPUBacked) {
robertphillips3e302272016-04-20 11:48:36 -070061 const SkIRect subset = img->subset();
Michael Ludwigb4580352019-06-21 16:01:42 -040062 REPORTER_ASSERT(reporter, kPad == subset.left());
63 REPORTER_ASSERT(reporter, kPad == subset.top());
robertphillipsb6c65e92016-02-04 10:52:42 -080064 REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
65 REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
66
67 //--------------
Robert Phillips2c6d2bf2017-02-21 10:19:29 -050068 // Test that isTextureBacked reports the correct backing type
Robert Phillips6de99042017-01-31 11:31:39 -050069 REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked());
robertphillips64612512016-04-08 12:10:42 -070070
robertphillips64612512016-04-08 12:10:42 -070071 //--------------
Robert Phillips8e1c4e62017-02-19 12:27:01 -050072 // Test asTextureProxyRef - as long as there is a context this should succeed
robertphillips64612512016-04-08 12:10:42 -070073 if (context) {
Robert Phillips8e1c4e62017-02-19 12:27:01 -050074 sk_sp<GrTextureProxy> proxy(img->asTextureProxyRef(context));
75 REPORTER_ASSERT(reporter, proxy);
robertphillips64612512016-04-08 12:10:42 -070076 }
robertphillipsb6c65e92016-02-04 10:52:42 -080077
78 //--------------
robertphillips64612512016-04-08 12:10:42 -070079 // Test getROPixels - this should always succeed regardless of backing store
80 SkBitmap bitmap;
81 REPORTER_ASSERT(reporter, img->getROPixels(&bitmap));
Michael Ludwigb4580352019-06-21 16:01:42 -040082 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
83 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
robertphillipsb6c65e92016-02-04 10:52:42 -080084
85 //--------------
robertphillipsb4bd11e2016-03-21 13:44:18 -070086 // Test that draw restricts itself to the subset
Michael Ludwig03f9ca32019-08-14 14:35:15 -040087 sk_sp<SkSpecialSurface> surf(img->makeSurface(kN32_SkColorType, img->getColorSpace(),
88 SkISize::Make(kFullSize, kFullSize),
Matt Sarettcb6266b2017-01-17 10:48:53 -050089 kPremul_SkAlphaType));
robertphillipsb6c65e92016-02-04 10:52:42 -080090
91 SkCanvas* canvas = surf->getCanvas();
92
93 canvas->clear(SK_ColorBLUE);
robertphillipse8c34972016-02-16 12:09:36 -080094 img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad), nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -080095
96 SkBitmap bm;
Matt Sarettcb6266b2017-01-17 10:48:53 -050097 bm.allocN32Pixels(kFullSize, kFullSize, false);
robertphillipsb6c65e92016-02-04 10:52:42 -080098
99 bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
100 SkASSERT_RELEASE(result);
101
102 // Only the center (red) portion should've been drawn into the canvas
103 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
104 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad));
105 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1,
106 kSmallerSize+kPad-1));
107 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
108 kSmallerSize+kPad));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700109
110 //--------------
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500111 // Test that asImage & makeTightSurface return appropriately sized objects
robertphillipsb4bd11e2016-03-21 13:44:18 -0700112 // of the correct backing type
113 SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height());
114 {
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500115 sk_sp<SkImage> tightImg(img->asImage(&newSubset));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700116
117 REPORTER_ASSERT(reporter, tightImg->width() == subset.width());
118 REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400119 REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked());
robertphillipsb4bd11e2016-03-21 13:44:18 -0700120 SkPixmap tmpPixmap;
Robert Phillips6de99042017-01-31 11:31:39 -0500121 REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700122 }
123 {
Michael Ludwig03f9ca32019-08-14 14:35:15 -0400124 sk_sp<SkSurface> tightSurf(img->makeTightSurface(kN32_SkColorType, img->getColorSpace(),
125 subset.size()));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700126
127 REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
128 REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
Robert Phillips8caf85f2018-04-05 09:30:38 -0400129 GrBackendTexture backendTex = tightSurf->getBackendTexture(
130 SkSurface::kDiscardWrite_BackendHandleAccess);
131 REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid());
robertphillipsb4bd11e2016-03-21 13:44:18 -0700132 SkPixmap tmpPixmap;
Robert Phillips6de99042017-01-31 11:31:39 -0500133 REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700134 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800135}
136
137DEF_TEST(SpecialImage_Raster, reporter) {
138 SkBitmap bm = create_bm();
139
robertphillips37bd7c32016-03-17 14:31:39 -0700140 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster(
robertphillipsc5035e72016-03-17 06:58:39 -0700141 SkIRect::MakeWH(kFullSize, kFullSize),
142 bm));
143
robertphillipsb6c65e92016-02-04 10:52:42 -0800144 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
145
robertphillipsc5035e72016-03-17 06:58:39 -0700146 {
robertphillips3e302272016-04-20 11:48:36 -0700147 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm));
Michael Ludwigb4580352019-06-21 16:01:42 -0400148 test_image(subSImg1, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700149 }
150
151 {
robertphillips37bd7c32016-03-17 14:31:39 -0700152 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400153 test_image(subSImg2, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700154 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800155}
156
Brian Osmanb9c49782018-10-12 12:01:22 -0400157static void test_specialimage_image(skiatest::Reporter* reporter) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800158 SkBitmap bm = create_bm();
159
reed9ce9d672016-03-17 10:51:11 -0700160 sk_sp<SkImage> fullImage(SkImage::MakeFromBitmap(bm));
robertphillipsb6c65e92016-02-04 10:52:42 -0800161
robertphillips37bd7c32016-03-17 14:31:39 -0700162 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage(
Robert Phillips27467652019-01-10 16:34:22 -0500163 nullptr,
robertphillipsc5035e72016-03-17 06:58:39 -0700164 SkIRect::MakeWH(kFullSize, kFullSize),
Brian Osmanb9c49782018-10-12 12:01:22 -0400165 fullImage));
robertphillipsc5035e72016-03-17 06:58:39 -0700166
robertphillipsb6c65e92016-02-04 10:52:42 -0800167 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
168
robertphillipsc5035e72016-03-17 06:58:39 -0700169 {
Robert Phillips27467652019-01-10 16:34:22 -0500170 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset, fullImage));
Michael Ludwigb4580352019-06-21 16:01:42 -0400171 test_image(subSImg1, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700172 }
173
174 {
robertphillips37bd7c32016-03-17 14:31:39 -0700175 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400176 test_image(subSImg2, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700177 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800178}
179
Brian Osman7992da32016-11-18 11:28:24 -0500180DEF_TEST(SpecialImage_Image_Legacy, reporter) {
Brian Osmanb9c49782018-10-12 12:01:22 -0400181 test_specialimage_image(reporter);
Brian Osman7992da32016-11-18 11:28:24 -0500182}
183
robertphillips83c17fa2016-03-18 08:14:27 -0700184static void test_texture_backed(skiatest::Reporter* reporter,
185 const sk_sp<SkSpecialImage>& orig,
186 const sk_sp<SkSpecialImage>& gpuBacked) {
187 REPORTER_ASSERT(reporter, gpuBacked);
robertphillips64612512016-04-08 12:10:42 -0700188 REPORTER_ASSERT(reporter, gpuBacked->isTextureBacked());
robertphillips83c17fa2016-03-18 08:14:27 -0700189 REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID());
190 REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() &&
191 gpuBacked->subset().height() == orig->subset().height());
brianosmanafbf71d2016-07-21 07:15:37 -0700192 REPORTER_ASSERT(reporter, gpuBacked->getColorSpace() == orig->getColorSpace());
robertphillips83c17fa2016-03-18 08:14:27 -0700193}
194
195// Test out the SkSpecialImage::makeTextureImage entry point
bsalomon68d91342016-04-12 09:59:58 -0700196DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700197 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500198 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
robertphillips83c17fa2016-03-18 08:14:27 -0700199 SkBitmap bm = create_bm();
200
201 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
202
203 {
204 // raster
205 sk_sp<SkSpecialImage> rasterImage(SkSpecialImage::MakeFromRaster(
robertphillips83c17fa2016-03-18 08:14:27 -0700206 SkIRect::MakeWH(kFullSize,
207 kFullSize),
208 bm));
209
210 {
robertphillips3e302272016-04-20 11:48:36 -0700211 sk_sp<SkSpecialImage> fromRaster(rasterImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700212 test_texture_backed(reporter, rasterImage, fromRaster);
213 }
214
215 {
216 sk_sp<SkSpecialImage> subRasterImage(rasterImage->makeSubset(subset));
217
robertphillips3e302272016-04-20 11:48:36 -0700218 sk_sp<SkSpecialImage> fromSubRaster(subRasterImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700219 test_texture_backed(reporter, subRasterImage, fromSubRaster);
220 }
221 }
222
223 {
224 // gpu
Brian Osman2700abc2018-09-12 10:19:41 -0400225 sk_sp<SkImage> rasterImage = SkImage::MakeFromBitmap(bm);
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400226 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
Brian Salomon96b383a2019-08-13 16:55:41 -0400227 rasterImage, 1, SkBudgeted::kNo, SkBackingFit::kExact);
Robert Phillips2f493142017-03-02 18:18:38 -0500228 if (!proxy) {
robertphillips83c17fa2016-03-18 08:14:27 -0700229 return;
230 }
231
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500232 sk_sp<SkSpecialImage> gpuImage(SkSpecialImage::MakeDeferredFromGpu(
Robert Phillips2f493142017-03-02 18:18:38 -0500233 context,
234 SkIRect::MakeWH(kFullSize, kFullSize),
235 kNeedNewImageUniqueID_SpecialImage,
Robert Phillips40b05c32019-09-20 12:40:55 -0400236 std::move(proxy),
237 GrColorType::kRGBA_8888,
238 nullptr));
robertphillips83c17fa2016-03-18 08:14:27 -0700239
240 {
robertphillips3e302272016-04-20 11:48:36 -0700241 sk_sp<SkSpecialImage> fromGPU(gpuImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700242 test_texture_backed(reporter, gpuImage, fromGPU);
243 }
244
245 {
246 sk_sp<SkSpecialImage> subGPUImage(gpuImage->makeSubset(subset));
247
robertphillips3e302272016-04-20 11:48:36 -0700248 sk_sp<SkSpecialImage> fromSubGPU(subGPUImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700249 test_texture_backed(reporter, subGPUImage, fromSubGPU);
250 }
251 }
252}
253
bsalomon68d91342016-04-12 09:59:58 -0700254DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700255 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500256 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
robertphillipsb6c65e92016-02-04 10:52:42 -0800257 SkBitmap bm = create_bm();
Brian Osman2700abc2018-09-12 10:19:41 -0400258 sk_sp<SkImage> rasterImage = SkImage::MakeFromBitmap(bm);
robertphillipsb6c65e92016-02-04 10:52:42 -0800259
Brian Salomon96b383a2019-08-13 16:55:41 -0400260 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(rasterImage, 1, SkBudgeted::kNo,
261 SkBackingFit::kExact);
Robert Phillips2f493142017-03-02 18:18:38 -0500262 if (!proxy) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800263 return;
264 }
265
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500266 sk_sp<SkSpecialImage> fullSImg(SkSpecialImage::MakeDeferredFromGpu(
267 context,
robertphillipsc5035e72016-03-17 06:58:39 -0700268 SkIRect::MakeWH(kFullSize, kFullSize),
269 kNeedNewImageUniqueID_SpecialImage,
Robert Phillips40b05c32019-09-20 12:40:55 -0400270 proxy,
271 GrColorType::kRGBA_8888,
272 nullptr));
robertphillipsc5035e72016-03-17 06:58:39 -0700273
robertphillipsb6c65e92016-02-04 10:52:42 -0800274 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
275
robertphillipsc5035e72016-03-17 06:58:39 -0700276 {
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500277 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeDeferredFromGpu(
Robert Phillips2f493142017-03-02 18:18:38 -0500278 context, subset,
robertphillipsc5035e72016-03-17 06:58:39 -0700279 kNeedNewImageUniqueID_SpecialImage,
Robert Phillips40b05c32019-09-20 12:40:55 -0400280 std::move(proxy),
281 GrColorType::kRGBA_8888,
282 nullptr));
Michael Ludwigb4580352019-06-21 16:01:42 -0400283 test_image(subSImg1, reporter, context, true);
robertphillipsc5035e72016-03-17 06:58:39 -0700284 }
285
286 {
robertphillips37bd7c32016-03-17 14:31:39 -0700287 sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400288 test_image(subSImg2, reporter, context, true);
robertphillipsc5035e72016-03-17 06:58:39 -0700289 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800290}
Brian Osmanba651682018-10-05 11:13:04 -0400291
292DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_ReadbackAndCachingSubsets_Gpu, reporter, ctxInfo) {
293 GrContext* context = ctxInfo.grContext();
294 SkImageInfo ii = SkImageInfo::Make(50, 50, kN32_SkColorType, kPremul_SkAlphaType);
295 auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
296
297 // Fill out our surface:
298 // Green | Blue
299 // Red | Green
300 {
301 surface->getCanvas()->clear(SK_ColorGREEN);
302 SkPaint p;
303 p.setColor(SK_ColorRED);
304 surface->getCanvas()->drawRect(SkRect::MakeXYWH(0, 25, 25, 25), p);
305 p.setColor(SK_ColorBLUE);
306 surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 0, 25, 25), p);
307 }
308
309 auto image = surface->makeImageSnapshot();
Robert Phillips27467652019-01-10 16:34:22 -0500310 auto redImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(10, 30, 10, 10), image);
311 auto blueImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(30, 10, 10, 10), image);
Brian Osmanba651682018-10-05 11:13:04 -0400312
313 // This isn't necessary, but if it ever becomes false, then the cache collision bug that we're
314 // checking below is irrelevant.
315 REPORTER_ASSERT(reporter, redImg->uniqueID() == blueImg->uniqueID());
316
317 SkBitmap redBM, blueBM;
318 SkAssertResult(redImg->getROPixels(&redBM));
319 SkAssertResult(blueImg->getROPixels(&blueBM));
320
321 // Each image should read from the correct sub-rect. Past bugs (skbug.com/8448) have included:
322 // - Always reading back from (0, 0), producing green
323 // - Incorrectly hitting the cache on the 2nd read-back, causing blueBM to be red
324 REPORTER_ASSERT(reporter, redBM.getColor(0, 0) == SK_ColorRED,
325 "0x%08x != 0x%08x", redBM.getColor(0, 0), SK_ColorRED);
326 REPORTER_ASSERT(reporter, blueBM.getColor(0, 0) == SK_ColorBLUE,
327 "0x%08x != 0x%08x", blueBM.getColor(0, 0), SK_ColorBLUE);
328}