xref: /aosp_15_r20/external/skia/tests/graphite/UpdateBackendTextureTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 #include "tools/graphite/GraphiteTestContext.h"
23 
24 using namespace skgpu;
25 using namespace skgpu::graphite;
26 
27 namespace {
28 const SkISize kSize = { 32, 32 };
29 constexpr int kNumMipLevels = 6;
30 
31 constexpr SkColor4f kColors[6] = {
32     { 1.0f, 0.0f, 0.0f, 1.0f }, // R
33     { 0.0f, 1.0f, 0.0f, 0.9f }, // G
34     { 0.0f, 0.0f, 1.0f, 0.7f }, // B
35     { 0.0f, 1.0f, 1.0f, 0.5f }, // C
36     { 1.0f, 0.0f, 1.0f, 0.3f }, // M
37     { 1.0f, 1.0f, 0.0f, 0.2f }, // Y
38 };
39 
40 constexpr SkColor4f kColorsNew[6] = {
41     { 1.0f, 1.0f, 0.0f, 0.2f },  // Y
42     { 1.0f, 0.0f, 0.0f, 1.0f },  // R
43     { 0.0f, 1.0f, 0.0f, 0.9f },  // G
44     { 0.0f, 0.0f, 1.0f, 0.7f },  // B
45     { 0.0f, 1.0f, 1.0f, 0.5f },  // C
46     { 1.0f, 0.0f, 1.0f, 0.3f },  // M
47 };
48 
check_solid_pixmap(skiatest::Reporter * reporter,const SkColor4f & expected,const SkPixmap & actual,SkColorType ct,const char * label)49 void check_solid_pixmap(skiatest::Reporter* reporter,
50                         const SkColor4f& expected,
51                         const SkPixmap& actual,
52                         SkColorType ct,
53                         const char* label) {
54     const float kTols[4] = { 0.01f, 0.01f, 0.01f, 0.01f };
55 
56     auto error = std::function<ComparePixmapsErrorReporter>(
57         [reporter, ct, label, expected](int x, int y, const float diffs[4]) {
58             SkASSERT(x >= 0 && y >= 0);
59             ERRORF(reporter, "%s %s - mismatch at %d, %d "
60                              "expected: (%.2f, %.2f, %.2f, %.2f) "
61                              "- diffs: (%.2f, %.2f, %.2f, %.2f)",
62                    ToolUtils::colortype_name(ct), label, x, y,
63                    expected.fR, expected.fG, expected.fB, expected.fA,
64                    diffs[0], diffs[1], diffs[2], diffs[3]);
65         });
66 
67     CheckSolidPixels(expected, actual, kTols, error);
68 }
69 
update_backend_texture(Recorder * recorder,const BackendTexture & backendTex,SkColorType ct,bool withMips,const SkColor4f colors[6],GpuFinishedProc finishedProc=nullptr,GpuFinishedContext finishedCtx=nullptr)70 void update_backend_texture(Recorder* recorder,
71                             const BackendTexture& backendTex,
72                             SkColorType ct,
73                             bool withMips,
74                             const SkColor4f colors[6],
75                             GpuFinishedProc finishedProc = nullptr,
76                             GpuFinishedContext finishedCtx = nullptr) {
77     SkPixmap pixmaps[6];
78     std::unique_ptr<char[]> memForPixmaps;
79 
80     int numMipLevels = ToolUtils::make_pixmaps(ct, kPremul_SkAlphaType, withMips, colors, pixmaps,
81                                                &memForPixmaps);
82     SkASSERT(numMipLevels == 1 || numMipLevels == kNumMipLevels);
83     SkASSERT(kSize == pixmaps[0].dimensions());
84 
85     recorder->updateBackendTexture(backendTex, pixmaps, numMipLevels, finishedProc, finishedCtx);
86 
87 }
88 
create_backend_texture(skiatest::Reporter * reporter,const Caps * caps,Recorder * recorder,SkColorType ct,bool withMips,Renderable renderable,skgpu::Protected isProtected,const SkColor4f colors[6],GpuFinishedProc finishedProc=nullptr,GpuFinishedContext finishedCtx=nullptr)89 BackendTexture create_backend_texture(skiatest::Reporter* reporter,
90                                       const Caps* caps,
91                                       Recorder* recorder,
92                                       SkColorType ct,
93                                       bool withMips,
94                                       Renderable renderable,
95                                       skgpu::Protected isProtected,
96                                       const SkColor4f colors[6],
97                                       GpuFinishedProc finishedProc = nullptr,
98                                       GpuFinishedContext finishedCtx = nullptr) {
99     Mipmapped mipmapped = withMips ? Mipmapped::kYes : Mipmapped::kNo;
100     TextureInfo info = caps->getDefaultSampledTextureInfo(ct,
101                                                           mipmapped,
102                                                           isProtected,
103                                                           renderable);
104 
105     BackendTexture backendTex = recorder->createBackendTexture(kSize, info);
106     REPORTER_ASSERT(reporter, backendTex.isValid());
107 
108     update_backend_texture(recorder, backendTex, ct, withMips, colors, finishedProc, finishedCtx);
109 
110     return backendTex;
111 }
112 
wrap_backend_texture(skiatest::Reporter * reporter,Recorder * recorder,const skgpu::graphite::BackendTexture & backendTex,SkColorType ct,bool withMips)113 sk_sp<SkImage> wrap_backend_texture(skiatest::Reporter* reporter,
114                                     Recorder* recorder,
115                                     const skgpu::graphite::BackendTexture& backendTex,
116                                     SkColorType ct,
117                                     bool withMips) {
118     sk_sp<SkImage> image = SkImages::WrapTexture(recorder,
119                                                  backendTex,
120                                                  ct,
121                                                  kPremul_SkAlphaType,
122                                                  /* colorSpace= */ nullptr);
123     REPORTER_ASSERT(reporter, image);
124     REPORTER_ASSERT(reporter, image->hasMipmaps() == withMips);
125 
126     return image;
127 }
128 
check_levels(skiatest::Reporter * reporter,Context * context,Recorder * recorder,SkImage * image,bool withMips,const SkColor4f colors[6])129 void check_levels(skiatest::Reporter* reporter,
130                   Context* context,
131                   Recorder* recorder,
132                   SkImage* image,
133                   bool withMips,
134                   const SkColor4f colors[6]) {
135     int numLevels = withMips ? kNumMipLevels : 1;
136 
137     SkSamplingOptions sampling = withMips
138                                  ? SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest)
139                                  : SkSamplingOptions(SkFilterMode::kNearest);
140 
141     SkImageInfo surfaceII = SkImageInfo::Make(kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
142     sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, surfaceII, Mipmapped::kNo);
143     SkCanvas* canvas = surf->getCanvas();
144 
145     for (int i = 0, drawSize = kSize.width(); i < numLevels; ++i, drawSize /= 2) {
146         if (i == 5) {
147             // TODO: Metal currently never draws the top-most mip-level (skbug.com/13792)
148             continue;
149         }
150 
151         SkImageInfo readbackII = SkImageInfo::Make({drawSize, drawSize}, kRGBA_8888_SkColorType,
152                                                    kUnpremul_SkAlphaType);
153         SkAutoPixmapStorage actual;
154         SkAssertResult(actual.tryAlloc(readbackII));
155         actual.erase(SkColors::kTransparent);
156 
157         SkPaint paint;
158         paint.setBlendMode(SkBlendMode::kSrc);
159 
160         canvas->clear(SkColors::kTransparent);
161 
162 #if 0
163         // This option gives greater control over the tilemodes and texture scaling
164         SkMatrix lm;
165         lm.setScale(1.0f / (1 << i), 1.0f / (1 << i));
166 
167         paint.setShader(image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, sampling, lm));
168         canvas->drawRect(SkRect::MakeWH(drawSize, drawSize), paint);
169 #else
170         canvas->drawImageRect(image, SkRect::MakeWH(drawSize, drawSize), sampling, &paint);
171 #endif
172 
173         if (!surf->readPixels(actual, 0, 0)) {
174             ERRORF(reporter, "readPixels failed");
175             return;
176         }
177 
178         SkString str;
179         str.appendf("mip-level %d", i);
180 
181         check_solid_pixmap(reporter, colors[i], actual, image->colorType(), str.c_str());
182     }
183 }
184 
185 } // anonymous namespace
186 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UpdateImageBackendTextureTest,reporter,context,CtsEnforcement::kApiLevel_V)187 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UpdateImageBackendTextureTest, reporter, context,
188                                          CtsEnforcement::kApiLevel_V) {
189     const Caps* caps = context->priv().caps();
190     std::unique_ptr<Recorder> recorder = context->makeRecorder();
191 
192     skgpu::Protected isProtected = skgpu::Protected(caps->protectedSupport());
193 
194     // TODO: test more than just RGBA8
195     for (SkColorType ct : { kRGBA_8888_SkColorType }) {
196         for (bool withMips : { true, false }) {
197             for (Renderable renderable : { Renderable::kYes, Renderable::kNo }) {
198 
199                 BackendTexture backendTex = create_backend_texture(reporter, caps, recorder.get(),
200                                                                    ct, withMips, renderable,
201                                                                    isProtected, kColors);
202 
203                 sk_sp<SkImage> image = wrap_backend_texture(reporter, recorder.get(), backendTex,
204                                                             ct, withMips);
205                 if (!image) {
206                     continue;
207                 }
208 
209                 if (isProtected == skgpu::Protected::kNo) {
210                     check_levels(reporter, context, recorder.get(), image.get(), withMips, kColors);
211                 }
212 
213                 image.reset();
214 
215                 update_backend_texture(recorder.get(), backendTex, ct, withMips, kColorsNew);
216 
217                 image = wrap_backend_texture(reporter, recorder.get(), backendTex, ct, withMips);
218                 if (!image) {
219                     continue;
220                 }
221 
222                 if (isProtected == skgpu::Protected::kNo) {
223                     check_levels(reporter, context, recorder.get(), image.get(), withMips,
224                                  kColorsNew);
225                 }
226 
227                 image.reset();
228 
229                 recorder->deleteBackendTexture(backendTex);
230             }
231         }
232     }
233 }
234 
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(UpdateBackendTextureFinishedProcTest,reporter,context,testContext,true,CtsEnforcement::kNextRelease)235 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(UpdateBackendTextureFinishedProcTest,
236                                                reporter,
237                                                context,
238                                                testContext,
239                                                true,
240                                                CtsEnforcement::kNextRelease) {
241     const Caps* caps = context->priv().caps();
242     std::unique_ptr<Recorder> recorder = context->makeRecorder();
243 
244     skgpu::Protected isProtected = skgpu::Protected(caps->protectedSupport());
245 
246     struct FinishContext {
247         bool fFinishedUpdate = false;
248         skiatest::Reporter* fReporter = nullptr;
249     };
250     FinishContext finishCtx;
251     finishCtx.fReporter = reporter;
252 
253     auto finishedProc = [](void* ctx, CallbackResult) {
254         FinishContext* finishedCtx = (FinishContext*) ctx;
255         REPORTER_ASSERT(finishedCtx->fReporter, !(finishedCtx->fFinishedUpdate));
256         finishedCtx->fFinishedUpdate = true;
257     };
258 
259     BackendTexture backendTex = create_backend_texture(reporter,
260                                                        caps,
261                                                        recorder.get(),
262                                                        kRGBA_8888_SkColorType,
263                                                        /*withMips=*/false,
264                                                        Renderable::kNo,
265                                                        isProtected,
266                                                        kColors,
267                                                        finishedProc,
268                                                        &finishCtx);
269 
270     REPORTER_ASSERT(reporter, !finishCtx.fFinishedUpdate);
271 
272     std::unique_ptr<Recording> recording = recorder->snap();
273     if (!recording) {
274         ERRORF(reporter, "Failed to make recording");
275         return;
276     }
277     InsertRecordingInfo insertInfo;
278     insertInfo.fRecording = recording.get();
279     context->insertRecording(insertInfo);
280 
281     REPORTER_ASSERT(reporter, !finishCtx.fFinishedUpdate);
282 
283     testContext->syncedSubmit(context);
284     REPORTER_ASSERT(reporter, finishCtx.fFinishedUpdate);
285 
286     recorder->deleteBackendTexture(backendTex);
287 }
288