blob: 026d0fd0f403ffc3cc087d6a23ea45176ffea9df [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"
Greg Daniel6f5441a2020-01-28 17:02:49 -050020#include "src/gpu/GrBitmapTextureMaker.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrContextPriv.h"
22#include "src/gpu/GrProxyProvider.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040023#include "src/gpu/GrSurfaceProxy.h"
24#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/SkGr.h"
robertphillipsb6c65e92016-02-04 10:52:42 -080026
robertphillipsb6c65e92016-02-04 10:52:42 -080027
28// This test creates backing resources exactly sized to [kFullSize x kFullSize].
29// It then wraps them in an SkSpecialImage with only the center (red) region being active.
30// It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
31// of the inactive (green) region leaked out.
32
33static const int kSmallerSize = 10;
34static const int kPad = 3;
35static const int kFullSize = kSmallerSize + 2 * kPad;
36
37// Create a bitmap with red in the center and green around it
38static SkBitmap create_bm() {
Robert Phillips40b05c32019-09-20 12:40:55 -040039 SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType,
40 kPremul_SkAlphaType);
41
robertphillipsb6c65e92016-02-04 10:52:42 -080042 SkBitmap bm;
Robert Phillips40b05c32019-09-20 12:40:55 -040043 bm.allocPixels(ii);
robertphillipsb6c65e92016-02-04 10:52:42 -080044
45 SkCanvas temp(bm);
46
47 temp.clear(SK_ColorGREEN);
48 SkPaint p;
49 p.setColor(SK_ColorRED);
50 p.setAntiAlias(false);
51
52 temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
halcanary9d524f22016-03-29 09:03:52 -070053 SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
robertphillipsb6c65e92016-02-04 10:52:42 -080054 p);
55
Greg Daniel6f5441a2020-01-28 17:02:49 -050056 bm.setImmutable();
robertphillipsb6c65e92016-02-04 10:52:42 -080057 return bm;
58}
59
60// Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
robertphillips37bd7c32016-03-17 14:31:39 -070061static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
Michael Ludwigb4580352019-06-21 16:01:42 -040062 GrContext* context, bool isGPUBacked) {
robertphillips3e302272016-04-20 11:48:36 -070063 const SkIRect subset = img->subset();
Michael Ludwigb4580352019-06-21 16:01:42 -040064 REPORTER_ASSERT(reporter, kPad == subset.left());
65 REPORTER_ASSERT(reporter, kPad == subset.top());
robertphillipsb6c65e92016-02-04 10:52:42 -080066 REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
67 REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
68
69 //--------------
Robert Phillips2c6d2bf2017-02-21 10:19:29 -050070 // Test that isTextureBacked reports the correct backing type
Robert Phillips6de99042017-01-31 11:31:39 -050071 REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked());
robertphillips64612512016-04-08 12:10:42 -070072
robertphillips64612512016-04-08 12:10:42 -070073 //--------------
Greg Daniel37c127f2020-02-05 10:37:27 -050074 // Test view - as long as there is a context this should succeed
robertphillips64612512016-04-08 12:10:42 -070075 if (context) {
Greg Daniel37c127f2020-02-05 10:37:27 -050076 GrSurfaceProxyView view = img->view(context);
Greg Daniel83547172020-01-29 11:11:03 -050077 REPORTER_ASSERT(reporter, view.asTextureProxy());
robertphillips64612512016-04-08 12:10:42 -070078 }
robertphillipsb6c65e92016-02-04 10:52:42 -080079
80 //--------------
robertphillips64612512016-04-08 12:10:42 -070081 // Test getROPixels - this should always succeed regardless of backing store
82 SkBitmap bitmap;
83 REPORTER_ASSERT(reporter, img->getROPixels(&bitmap));
Michael Ludwigb4580352019-06-21 16:01:42 -040084 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
85 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
robertphillipsb6c65e92016-02-04 10:52:42 -080086
87 //--------------
robertphillipsb4bd11e2016-03-21 13:44:18 -070088 // Test that draw restricts itself to the subset
Michael Ludwig03f9ca32019-08-14 14:35:15 -040089 sk_sp<SkSpecialSurface> surf(img->makeSurface(kN32_SkColorType, img->getColorSpace(),
90 SkISize::Make(kFullSize, kFullSize),
Matt Sarettcb6266b2017-01-17 10:48:53 -050091 kPremul_SkAlphaType));
robertphillipsb6c65e92016-02-04 10:52:42 -080092
93 SkCanvas* canvas = surf->getCanvas();
94
95 canvas->clear(SK_ColorBLUE);
robertphillipse8c34972016-02-16 12:09:36 -080096 img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad), nullptr);
robertphillipsb6c65e92016-02-04 10:52:42 -080097
98 SkBitmap bm;
Matt Sarettcb6266b2017-01-17 10:48:53 -050099 bm.allocN32Pixels(kFullSize, kFullSize, false);
robertphillipsb6c65e92016-02-04 10:52:42 -0800100
101 bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
102 SkASSERT_RELEASE(result);
103
104 // Only the center (red) portion should've been drawn into the canvas
105 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
106 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad));
107 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1,
108 kSmallerSize+kPad-1));
109 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
110 kSmallerSize+kPad));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700111
112 //--------------
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500113 // Test that asImage & makeTightSurface return appropriately sized objects
robertphillipsb4bd11e2016-03-21 13:44:18 -0700114 // of the correct backing type
115 SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height());
116 {
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500117 sk_sp<SkImage> tightImg(img->asImage(&newSubset));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700118
119 REPORTER_ASSERT(reporter, tightImg->width() == subset.width());
120 REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400121 REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked());
robertphillipsb4bd11e2016-03-21 13:44:18 -0700122 SkPixmap tmpPixmap;
Robert Phillips6de99042017-01-31 11:31:39 -0500123 REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700124 }
125 {
Michael Ludwig03f9ca32019-08-14 14:35:15 -0400126 sk_sp<SkSurface> tightSurf(img->makeTightSurface(kN32_SkColorType, img->getColorSpace(),
127 subset.size()));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700128
129 REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
130 REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
Robert Phillips8caf85f2018-04-05 09:30:38 -0400131 GrBackendTexture backendTex = tightSurf->getBackendTexture(
132 SkSurface::kDiscardWrite_BackendHandleAccess);
133 REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid());
robertphillipsb4bd11e2016-03-21 13:44:18 -0700134 SkPixmap tmpPixmap;
Robert Phillips6de99042017-01-31 11:31:39 -0500135 REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap));
robertphillipsb4bd11e2016-03-21 13:44:18 -0700136 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800137}
138
139DEF_TEST(SpecialImage_Raster, reporter) {
140 SkBitmap bm = create_bm();
141
robertphillips37bd7c32016-03-17 14:31:39 -0700142 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster(
robertphillipsc5035e72016-03-17 06:58:39 -0700143 SkIRect::MakeWH(kFullSize, kFullSize),
144 bm));
145
robertphillipsb6c65e92016-02-04 10:52:42 -0800146 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
147
robertphillipsc5035e72016-03-17 06:58:39 -0700148 {
robertphillips3e302272016-04-20 11:48:36 -0700149 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm));
Michael Ludwigb4580352019-06-21 16:01:42 -0400150 test_image(subSImg1, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700151 }
152
153 {
robertphillips37bd7c32016-03-17 14:31:39 -0700154 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400155 test_image(subSImg2, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700156 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800157}
158
Brian Osmanb9c49782018-10-12 12:01:22 -0400159static void test_specialimage_image(skiatest::Reporter* reporter) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800160 SkBitmap bm = create_bm();
161
reed9ce9d672016-03-17 10:51:11 -0700162 sk_sp<SkImage> fullImage(SkImage::MakeFromBitmap(bm));
robertphillipsb6c65e92016-02-04 10:52:42 -0800163
robertphillips37bd7c32016-03-17 14:31:39 -0700164 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage(
Robert Phillips27467652019-01-10 16:34:22 -0500165 nullptr,
robertphillipsc5035e72016-03-17 06:58:39 -0700166 SkIRect::MakeWH(kFullSize, kFullSize),
Brian Osmanb9c49782018-10-12 12:01:22 -0400167 fullImage));
robertphillipsc5035e72016-03-17 06:58:39 -0700168
robertphillipsb6c65e92016-02-04 10:52:42 -0800169 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
170
robertphillipsc5035e72016-03-17 06:58:39 -0700171 {
Robert Phillips27467652019-01-10 16:34:22 -0500172 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset, fullImage));
Michael Ludwigb4580352019-06-21 16:01:42 -0400173 test_image(subSImg1, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700174 }
175
176 {
robertphillips37bd7c32016-03-17 14:31:39 -0700177 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400178 test_image(subSImg2, reporter, nullptr, false);
robertphillipsc5035e72016-03-17 06:58:39 -0700179 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800180}
181
Brian Osman7992da32016-11-18 11:28:24 -0500182DEF_TEST(SpecialImage_Image_Legacy, reporter) {
Brian Osmanb9c49782018-10-12 12:01:22 -0400183 test_specialimage_image(reporter);
Brian Osman7992da32016-11-18 11:28:24 -0500184}
185
robertphillips83c17fa2016-03-18 08:14:27 -0700186static void test_texture_backed(skiatest::Reporter* reporter,
187 const sk_sp<SkSpecialImage>& orig,
188 const sk_sp<SkSpecialImage>& gpuBacked) {
189 REPORTER_ASSERT(reporter, gpuBacked);
robertphillips64612512016-04-08 12:10:42 -0700190 REPORTER_ASSERT(reporter, gpuBacked->isTextureBacked());
robertphillips83c17fa2016-03-18 08:14:27 -0700191 REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID());
192 REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() &&
193 gpuBacked->subset().height() == orig->subset().height());
brianosmanafbf71d2016-07-21 07:15:37 -0700194 REPORTER_ASSERT(reporter, gpuBacked->getColorSpace() == orig->getColorSpace());
robertphillips83c17fa2016-03-18 08:14:27 -0700195}
196
197// Test out the SkSpecialImage::makeTextureImage entry point
bsalomon68d91342016-04-12 09:59:58 -0700198DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700199 GrContext* context = ctxInfo.grContext();
robertphillips83c17fa2016-03-18 08:14:27 -0700200 SkBitmap bm = create_bm();
201
202 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
203
204 {
205 // raster
206 sk_sp<SkSpecialImage> rasterImage(SkSpecialImage::MakeFromRaster(
robertphillips83c17fa2016-03-18 08:14:27 -0700207 SkIRect::MakeWH(kFullSize,
208 kFullSize),
209 bm));
210
211 {
robertphillips3e302272016-04-20 11:48:36 -0700212 sk_sp<SkSpecialImage> fromRaster(rasterImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700213 test_texture_backed(reporter, rasterImage, fromRaster);
214 }
215
216 {
217 sk_sp<SkSpecialImage> subRasterImage(rasterImage->makeSubset(subset));
218
robertphillips3e302272016-04-20 11:48:36 -0700219 sk_sp<SkSpecialImage> fromSubRaster(subRasterImage->makeTextureImage(context));
robertphillips83c17fa2016-03-18 08:14:27 -0700220 test_texture_backed(reporter, subRasterImage, fromSubRaster);
221 }
222 }
223
224 {
225 // gpu
Greg Daniel6f5441a2020-01-28 17:02:49 -0500226 GrBitmapTextureMaker maker(context, bm);
Greg Danielc61d7e32020-02-04 14:27:45 -0500227 auto[view, grCT] = maker.view(GrMipMapped::kNo);
Greg Danielcc104db2020-02-03 14:17:08 -0500228 if (!view.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,
Greg Danielc52db712020-01-28 17:03:46 -0500236 std::move(view),
Greg Daniel6f5441a2020-01-28 17:02:49 -0500237 grCT,
Robert Phillips40b05c32019-09-20 12:40:55 -0400238 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();
robertphillipsb6c65e92016-02-04 10:52:42 -0800256 SkBitmap bm = create_bm();
Greg Daniel6f5441a2020-01-28 17:02:49 -0500257 GrBitmapTextureMaker maker(context, bm);
Greg Danielc61d7e32020-02-04 14:27:45 -0500258 auto[view, grCT] = maker.view(GrMipMapped::kNo);
Greg Danielcc104db2020-02-03 14:17:08 -0500259 if (!view.proxy()) {
robertphillipsb6c65e92016-02-04 10:52:42 -0800260 return;
261 }
262
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500263 sk_sp<SkSpecialImage> fullSImg(SkSpecialImage::MakeDeferredFromGpu(
264 context,
robertphillipsc5035e72016-03-17 06:58:39 -0700265 SkIRect::MakeWH(kFullSize, kFullSize),
266 kNeedNewImageUniqueID_SpecialImage,
Greg Danielc52db712020-01-28 17:03:46 -0500267 view,
Greg Daniel6f5441a2020-01-28 17:02:49 -0500268 grCT,
Robert Phillips40b05c32019-09-20 12:40:55 -0400269 nullptr));
robertphillipsc5035e72016-03-17 06:58:39 -0700270
robertphillipsb6c65e92016-02-04 10:52:42 -0800271 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
272
robertphillipsc5035e72016-03-17 06:58:39 -0700273 {
Robert Phillips2c6d2bf2017-02-21 10:19:29 -0500274 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeDeferredFromGpu(
Robert Phillips2f493142017-03-02 18:18:38 -0500275 context, subset,
robertphillipsc5035e72016-03-17 06:58:39 -0700276 kNeedNewImageUniqueID_SpecialImage,
Greg Danielc52db712020-01-28 17:03:46 -0500277 std::move(view),
Greg Daniel6f5441a2020-01-28 17:02:49 -0500278 grCT,
Robert Phillips40b05c32019-09-20 12:40:55 -0400279 nullptr));
Michael Ludwigb4580352019-06-21 16:01:42 -0400280 test_image(subSImg1, reporter, context, true);
robertphillipsc5035e72016-03-17 06:58:39 -0700281 }
282
283 {
robertphillips37bd7c32016-03-17 14:31:39 -0700284 sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset));
Michael Ludwigb4580352019-06-21 16:01:42 -0400285 test_image(subSImg2, reporter, context, true);
robertphillipsc5035e72016-03-17 06:58:39 -0700286 }
robertphillipsb6c65e92016-02-04 10:52:42 -0800287}
Brian Osmanba651682018-10-05 11:13:04 -0400288
289DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_ReadbackAndCachingSubsets_Gpu, reporter, ctxInfo) {
290 GrContext* context = ctxInfo.grContext();
291 SkImageInfo ii = SkImageInfo::Make(50, 50, kN32_SkColorType, kPremul_SkAlphaType);
292 auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
293
294 // Fill out our surface:
295 // Green | Blue
296 // Red | Green
297 {
298 surface->getCanvas()->clear(SK_ColorGREEN);
299 SkPaint p;
300 p.setColor(SK_ColorRED);
301 surface->getCanvas()->drawRect(SkRect::MakeXYWH(0, 25, 25, 25), p);
302 p.setColor(SK_ColorBLUE);
303 surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 0, 25, 25), p);
304 }
305
306 auto image = surface->makeImageSnapshot();
Robert Phillips27467652019-01-10 16:34:22 -0500307 auto redImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(10, 30, 10, 10), image);
308 auto blueImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(30, 10, 10, 10), image);
Brian Osmanba651682018-10-05 11:13:04 -0400309
310 // This isn't necessary, but if it ever becomes false, then the cache collision bug that we're
311 // checking below is irrelevant.
312 REPORTER_ASSERT(reporter, redImg->uniqueID() == blueImg->uniqueID());
313
314 SkBitmap redBM, blueBM;
315 SkAssertResult(redImg->getROPixels(&redBM));
316 SkAssertResult(blueImg->getROPixels(&blueBM));
317
318 // Each image should read from the correct sub-rect. Past bugs (skbug.com/8448) have included:
319 // - Always reading back from (0, 0), producing green
320 // - Incorrectly hitting the cache on the 2nd read-back, causing blueBM to be red
321 REPORTER_ASSERT(reporter, redBM.getColor(0, 0) == SK_ColorRED,
322 "0x%08x != 0x%08x", redBM.getColor(0, 0), SK_ColorRED);
323 REPORTER_ASSERT(reporter, blueBM.getColor(0, 0) == SK_ColorBLUE,
324 "0x%08x != 0x%08x", blueBM.getColor(0, 0), SK_ColorBLUE);
325}