1 /*
2 * Copyright 2022 Google LLC
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 "tests/Test.h"
9
10 #include "include/core/SkColorSpace.h"
11 #include "include/gpu/graphite/BackendTexture.h"
12 #include "include/gpu/graphite/Context.h"
13 #include "include/gpu/graphite/Image.h"
14 #include "include/gpu/graphite/Recorder.h"
15 #include "include/gpu/graphite/Surface.h"
16 #include "src/core/SkAutoPixmapStorage.h"
17 #include "src/gpu/graphite/Caps.h"
18 #include "src/gpu/graphite/ContextPriv.h"
19 #include "src/gpu/graphite/Surface_Graphite.h"
20 #include "tests/TestUtils.h"
21 #include "tools/ToolUtils.h"
22
23 using namespace skgpu;
24 using namespace skgpu::graphite;
25
26 namespace {
27 const SkISize kSize = { 32, 32 };
28 constexpr int kNumMipLevels = 6;
29
check_solid_pixmap(skiatest::Reporter * reporter,const SkColor4f & expected,const SkPixmap & actual,SkColorType ct,const char * label)30 void check_solid_pixmap(skiatest::Reporter* reporter,
31 const SkColor4f& expected,
32 const SkPixmap& actual,
33 SkColorType ct,
34 const char* label) {
35 const float kTols[4] = { 0.01f, 0.01f, 0.01f, 0.01f };
36
37 auto error = std::function<ComparePixmapsErrorReporter>(
38 [reporter, ct, label, expected](int x, int y, const float diffs[4]) {
39 SkASSERT(x >= 0 && y >= 0);
40 ERRORF(reporter, "%s %s - mismatch at %d, %d "
41 "expected: (%.2f, %.2f, %.2f, %.2f) "
42 "- diffs: (%.2f, %.2f, %.2f, %.2f)",
43 ToolUtils::colortype_name(ct), label, x, y,
44 expected.fR, expected.fG, expected.fB, expected.fA,
45 diffs[0], diffs[1], diffs[2], diffs[3]);
46 });
47
48 CheckSolidPixels(expected, actual, kTols, error);
49 }
50
update_backend_texture(Recorder * recorder,const BackendTexture & backendTex,SkColorType ct,bool withMips,const SkColor4f colors[6])51 void update_backend_texture(Recorder* recorder,
52 const BackendTexture& backendTex,
53 SkColorType ct,
54 bool withMips,
55 const SkColor4f colors[6]) {
56 SkPixmap pixmaps[6];
57 std::unique_ptr<char[]> memForPixmaps;
58
59 int numMipLevels = ToolUtils::make_pixmaps(ct, kPremul_SkAlphaType, withMips, colors, pixmaps,
60 &memForPixmaps);
61 SkASSERT(numMipLevels == 1 || numMipLevels == kNumMipLevels);
62 SkASSERT(kSize == pixmaps[0].dimensions());
63
64 recorder->updateBackendTexture(backendTex, pixmaps, numMipLevels);
65
66 }
67
create_backend_texture(skiatest::Reporter * reporter,const Caps * caps,Recorder * recorder,SkColorType ct,bool withMips,Renderable renderable,const SkColor4f colors[6])68 BackendTexture create_backend_texture(skiatest::Reporter* reporter,
69 const Caps* caps,
70 Recorder* recorder,
71 SkColorType ct,
72 bool withMips,
73 Renderable renderable,
74 const SkColor4f colors[6]) {
75 Mipmapped mipmapped = withMips ? Mipmapped::kYes : Mipmapped::kNo;
76 TextureInfo info = caps->getDefaultSampledTextureInfo(ct,
77 mipmapped,
78 Protected::kNo,
79 renderable);
80
81 BackendTexture backendTex = recorder->createBackendTexture(kSize, info);
82 REPORTER_ASSERT(reporter, backendTex.isValid());
83
84 update_backend_texture(recorder, backendTex, ct, withMips, colors);
85
86 return backendTex;
87 }
88
wrap_backend_texture(skiatest::Reporter * reporter,Recorder * recorder,const skgpu::graphite::BackendTexture & backendTex,SkColorType ct,bool withMips)89 sk_sp<SkImage> wrap_backend_texture(skiatest::Reporter* reporter,
90 Recorder* recorder,
91 const skgpu::graphite::BackendTexture& backendTex,
92 SkColorType ct,
93 bool withMips) {
94 sk_sp<SkImage> image = SkImages::WrapTexture(recorder,
95 backendTex,
96 ct,
97 kPremul_SkAlphaType,
98 /* colorSpace= */ nullptr);
99 REPORTER_ASSERT(reporter, image);
100 REPORTER_ASSERT(reporter, image->hasMipmaps() == withMips);
101
102 return image;
103 }
104
check_levels(skiatest::Reporter * reporter,Context * context,Recorder * recorder,SkImage * image,bool withMips,const SkColor4f colors[6])105 void check_levels(skiatest::Reporter* reporter,
106 Context* context,
107 Recorder* recorder,
108 SkImage* image,
109 bool withMips,
110 const SkColor4f colors[6]) {
111 int numLevels = withMips ? kNumMipLevels : 1;
112
113 SkSamplingOptions sampling = withMips
114 ? SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest)
115 : SkSamplingOptions(SkFilterMode::kNearest);
116
117 SkImageInfo surfaceII = SkImageInfo::Make(kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
118 sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, surfaceII, Mipmapped::kNo);
119 SkCanvas* canvas = surf->getCanvas();
120
121 for (int i = 0, drawSize = kSize.width(); i < numLevels; ++i, drawSize /= 2) {
122 if (i == 5) {
123 // TODO: Metal currently never draws the top-most mip-level (skbug.com/13792)
124 continue;
125 }
126
127 SkImageInfo readbackII = SkImageInfo::Make({drawSize, drawSize}, kRGBA_8888_SkColorType,
128 kUnpremul_SkAlphaType);
129 SkAutoPixmapStorage actual;
130 SkAssertResult(actual.tryAlloc(readbackII));
131 actual.erase(SkColors::kTransparent);
132
133 SkPaint paint;
134 paint.setBlendMode(SkBlendMode::kSrc);
135
136 canvas->clear(SkColors::kTransparent);
137
138 #if 0
139 // This option gives greater control over the tilemodes and texture scaling
140 SkMatrix lm;
141 lm.setScale(1.0f / (1 << i), 1.0f / (1 << i));
142
143 paint.setShader(image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, sampling, lm));
144 canvas->drawRect(SkRect::MakeWH(drawSize, drawSize), paint);
145 #else
146 canvas->drawImageRect(image, SkRect::MakeWH(drawSize, drawSize), sampling, &paint);
147 #endif
148
149 if (!surf->readPixels(actual, 0, 0)) {
150 ERRORF(reporter, "readPixels failed");
151 return;
152 }
153
154 SkString str;
155 str.appendf("mip-level %d", i);
156
157 check_solid_pixmap(reporter, colors[i], actual, image->colorType(), str.c_str());
158 }
159 }
160
161 } // anonymous namespace
162
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UpdateImageBackendTextureTest,reporter,context,CtsEnforcement::kNextRelease)163 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UpdateImageBackendTextureTest, reporter, context,
164 CtsEnforcement::kNextRelease) {
165 // TODO: Remove this check once Vulkan supports creating default TexutreInfo from caps and we
166 // implement createBackendTexture.
167 if (context->backend() == BackendApi::kVulkan) {
168 return;
169 }
170
171 const Caps* caps = context->priv().caps();
172 std::unique_ptr<Recorder> recorder = context->makeRecorder();
173
174 constexpr SkColor4f kColors[6] = {
175 { 1.0f, 0.0f, 0.0f, 1.0f }, // R
176 { 0.0f, 1.0f, 0.0f, 0.9f }, // G
177 { 0.0f, 0.0f, 1.0f, 0.7f }, // B
178 { 0.0f, 1.0f, 1.0f, 0.5f }, // C
179 { 1.0f, 0.0f, 1.0f, 0.3f }, // M
180 { 1.0f, 1.0f, 0.0f, 0.2f }, // Y
181 };
182
183 constexpr SkColor4f kColorsNew[6] = {
184 { 1.0f, 1.0f, 0.0f, 0.2f }, // Y
185 { 1.0f, 0.0f, 0.0f, 1.0f }, // R
186 { 0.0f, 1.0f, 0.0f, 0.9f }, // G
187 { 0.0f, 0.0f, 1.0f, 0.7f }, // B
188 { 0.0f, 1.0f, 1.0f, 0.5f }, // C
189 { 1.0f, 0.0f, 1.0f, 0.3f }, // M
190 };
191
192 // TODO: test more than just RGBA8
193 for (SkColorType ct : { kRGBA_8888_SkColorType }) {
194 for (bool withMips : { true, false }) {
195 for (Renderable renderable : { Renderable::kYes, Renderable::kNo }) {
196
197 BackendTexture backendTex = create_backend_texture(reporter, caps, recorder.get(),
198 ct, withMips, renderable,
199 kColors);
200
201 sk_sp<SkImage> image = wrap_backend_texture(reporter, recorder.get(), backendTex,
202 ct, withMips);
203 if (!image) {
204 continue;
205 }
206
207 check_levels(reporter, context, recorder.get(), image.get(), withMips, kColors);
208
209 image.reset();
210
211 update_backend_texture(recorder.get(), backendTex, ct, withMips, kColorsNew);
212
213 image = wrap_backend_texture(reporter, recorder.get(), backendTex, ct, withMips);
214 if (!image) {
215 continue;
216 }
217
218 check_levels(reporter, context, recorder.get(), image.get(), withMips, kColorsNew);
219
220 image.reset();
221
222 recorder->deleteBackendTexture(backendTex);
223 }
224 }
225 }
226 }
227