1 /*
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
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkScalar.h"
20 #include "include/core/SkSize.h"
21 #include "include/core/SkSurface.h"
22 #include "include/core/SkSurfaceProps.h"
23 #include "include/core/SkTypes.h"
24 #include "include/gpu/GpuTypes.h"
25 #include "include/gpu/ganesh/GrDirectContext.h"
26 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
27 #include "src/core/SkSpecialImage.h"
28 #include "src/gpu/ganesh/GrColorInfo.h" // IWYU pragma: keep
29 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
30 #include "src/gpu/ganesh/SkGr.h"
31 #include "src/gpu/ganesh/image/SkSpecialImage_Ganesh.h"
32 #include "tests/CtsEnforcement.h"
33 #include "tests/Test.h"
34
35 #include <utility>
36
37 class GrRecordingContext;
38 struct GrContextOptions;
39
40 // This test creates backing resources exactly sized to [kFullSize x kFullSize].
41 // It then wraps them in an SkSpecialImage with only the center (red) region being active.
42 // It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
43 // of the inactive (green) region leaked out.
44
45 static const int kSmallerSize = 10;
46 static const int kPad = 3;
47 static const int kFullSize = kSmallerSize + 2 * kPad;
48
49 // Create a bitmap with red in the center and green around it
create_bm()50 static SkBitmap create_bm() {
51 SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType,
52 kPremul_SkAlphaType);
53
54 SkBitmap bm;
55 bm.allocPixels(ii);
56
57 SkCanvas temp(bm);
58
59 temp.clear(SK_ColorGREEN);
60 SkPaint p;
61 p.setColor(SK_ColorRED);
62 p.setAntiAlias(false);
63
64 temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
65 SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
66 p);
67
68 bm.setImmutable();
69 return bm;
70 }
71
72 // Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
test_image(const sk_sp<SkSpecialImage> & img,skiatest::Reporter * reporter,GrRecordingContext * rContext,bool isGPUBacked)73 static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
74 GrRecordingContext* rContext, bool isGPUBacked) {
75 const SkIRect subset = img->subset();
76 REPORTER_ASSERT(reporter, kPad == subset.left());
77 REPORTER_ASSERT(reporter, kPad == subset.top());
78 REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
79 REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
80
81 //--------------
82 // Test that isTextureBacked reports the correct backing type
83 REPORTER_ASSERT(reporter, isGPUBacked == img->isGaneshBacked());
84 REPORTER_ASSERT(reporter, !img->isGraphiteBacked());
85
86 //--------------
87 // Test view - only succeeds if it's Ganesh backed
88 if (rContext) {
89 GrSurfaceProxyView view = SkSpecialImages::AsView(rContext, img);
90 REPORTER_ASSERT(reporter, SkToBool(view.asTextureProxy()) == isGPUBacked);
91 }
92
93 //--------------
94 // Test AsBitmap - this only works for raster-backed special images
95 if (!img->isGaneshBacked() && !img->isGraphiteBacked()) {
96 SkBitmap bitmap;
97 REPORTER_ASSERT(reporter, SkSpecialImages::AsBitmap(img.get(), &bitmap));
98 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
99 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
100 } else {
101 SkBitmap bitmap;
102 REPORTER_ASSERT(reporter, !SkSpecialImages::AsBitmap(img.get(), &bitmap));
103 }
104
105 //--------------
106 // Test that draw restricts itself to the subset
107 SkImageInfo imageInfo = SkImageInfo::Make(SkISize::Make(kFullSize, kFullSize),
108 kN32_SkColorType,
109 kPremul_SkAlphaType,
110 sk_ref_sp(img->getColorSpace()));
111 sk_sp<SkSurface> surf = isGPUBacked
112 ? SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kNo, imageInfo)
113 : SkSurfaces::Raster(imageInfo, {});
114
115 SkCanvas* canvas = surf->getCanvas();
116
117 canvas->clear(SK_ColorBLUE);
118 img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad));
119
120 SkBitmap bm;
121 bm.allocN32Pixels(kFullSize, kFullSize, false);
122
123 bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
124 SkASSERT_RELEASE(result);
125
126 // Only the center (red) portion should've been drawn into the canvas
127 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
128 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad));
129 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1,
130 kSmallerSize+kPad-1));
131 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
132 kSmallerSize+kPad));
133 }
134
DEF_TEST(SpecialImage_Raster,reporter)135 DEF_TEST(SpecialImage_Raster, reporter) {
136 SkBitmap bm = create_bm();
137
138 sk_sp<SkSpecialImage> fullSImage(SkSpecialImages::MakeFromRaster(
139 SkIRect::MakeWH(kFullSize, kFullSize), bm, SkSurfaceProps()));
140
141 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
142
143 {
144 sk_sp<SkSpecialImage> subSImg1(
145 SkSpecialImages::MakeFromRaster(subset, bm, SkSurfaceProps()));
146 test_image(subSImg1, reporter, nullptr, false);
147 }
148
149 {
150 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
151 test_image(subSImg2, reporter, nullptr, false);
152 }
153 }
154
test_specialimage_image(skiatest::Reporter * reporter)155 static void test_specialimage_image(skiatest::Reporter* reporter) {
156 SkBitmap bm = create_bm();
157
158 sk_sp<SkImage> fullImage(bm.asImage());
159
160 sk_sp<SkSpecialImage> fullSImage(SkSpecialImages::MakeFromRaster(
161 SkIRect::MakeWH(kFullSize, kFullSize), fullImage, SkSurfaceProps()));
162
163 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
164
165 {
166 sk_sp<SkSpecialImage> subSImg1(
167 SkSpecialImages::MakeFromRaster(subset, fullImage, SkSurfaceProps()));
168 test_image(subSImg1, reporter, nullptr, false);
169 }
170
171 {
172 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
173 test_image(subSImg2, reporter, nullptr, false);
174 }
175 }
176
DEF_TEST(SpecialImage_Image_Legacy,reporter)177 DEF_TEST(SpecialImage_Image_Legacy, reporter) {
178 test_specialimage_image(reporter);
179 }
180
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)181 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu,
182 reporter,
183 ctxInfo,
184 CtsEnforcement::kApiLevel_T) {
185 auto context = ctxInfo.directContext();
186 SkBitmap bm = create_bm();
187 auto [view, ct] = GrMakeUncachedBitmapProxyView(context, bm);
188 if (!view) {
189 return;
190 }
191
192 sk_sp<SkSpecialImage> fullSImg =
193 SkSpecialImages::MakeDeferredFromGpu(context,
194 SkIRect::MakeWH(kFullSize, kFullSize),
195 kNeedNewImageUniqueID_SpecialImage,
196 view,
197 {ct, kPremul_SkAlphaType, nullptr},
198 SkSurfaceProps());
199
200 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
201
202 {
203 sk_sp<SkSpecialImage> subSImg1 =
204 SkSpecialImages::MakeDeferredFromGpu(context,
205 subset,
206 kNeedNewImageUniqueID_SpecialImage,
207 std::move(view),
208 {ct, kPremul_SkAlphaType, nullptr},
209 SkSurfaceProps());
210 test_image(subSImg1, reporter, context, true);
211 }
212
213 {
214 sk_sp<SkSpecialImage> subSImg2 = fullSImg->makeSubset(subset);
215 test_image(subSImg2, reporter, context, true);
216 }
217 }
218