xref: /aosp_15_r20/external/skia/tests/ProgramsTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2011 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 // This is a GPU-backend specific test.
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBlendMode.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkSize.h"
14 #include "include/core/SkString.h"
15 #include "include/core/SkSurfaceProps.h"
16 #include "include/core/SkTypes.h"
17 #include "include/gpu/GpuTypes.h"
18 #include "include/gpu/ganesh/GrBackendSurface.h"
19 #include "include/gpu/ganesh/GrContextOptions.h"
20 #include "include/gpu/ganesh/GrDirectContext.h"
21 #include "include/gpu/ganesh/GrTypes.h"
22 #include "include/gpu/ganesh/gl/GrGLTypes.h"
23 #include "include/private/base/SkDebug.h"
24 #include "include/private/gpu/ganesh/GrTypesPriv.h"
25 #include "src/base/SkRandom.h"
26 #include "src/gpu/KeyBuilder.h"
27 #include "src/gpu/SkBackingFit.h"
28 #include "src/gpu/Swizzle.h"
29 #include "src/gpu/ganesh/GrAutoLocaleSetter.h"
30 #include "src/gpu/ganesh/GrCaps.h"
31 #include "src/gpu/ganesh/GrDirectContextPriv.h"
32 #include "src/gpu/ganesh/GrDrawOpTest.h"
33 #include "src/gpu/ganesh/GrDrawingManager.h"
34 #include "src/gpu/ganesh/GrFragmentProcessor.h"
35 #include "src/gpu/ganesh/GrPaint.h"
36 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
37 #include "src/gpu/ganesh/GrProxyProvider.h"
38 #include "src/gpu/ganesh/GrSurfaceProxy.h"
39 #include "src/gpu/ganesh/SurfaceDrawContext.h"
40 #include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
41 #include "src/gpu/ganesh/effects/GrPorterDuffXferProcessor.h"
42 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
43 #include "tests/CtsEnforcement.h"
44 #include "tests/Test.h"
45 
46 #include <algorithm>
47 #include <array>
48 #include <cstdint>
49 #include <memory>
50 #include <tuple>
51 #include <utility>
52 
53 class GrRecordingContext;
54 struct GrShaderCaps;
55 
56 #ifdef SK_GL
57 #include "src/gpu/ganesh/gl/GrGLGpu.h"
58 #endif
59 
60 /*
61  * A simple processor which just tries to insert a massive key and verify that it can retrieve the
62  * whole thing correctly
63  */
64 static const uint32_t kMaxKeySize = 1024;
65 
66 namespace {
67 class BigKeyProcessor : public GrFragmentProcessor {
68 public:
Make()69     static std::unique_ptr<GrFragmentProcessor> Make() {
70         return std::unique_ptr<GrFragmentProcessor>(new BigKeyProcessor);
71     }
72 
name() const73     const char* name() const override { return "Big_Ole_Key"; }
74 
onMakeProgramImpl() const75     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
76         class Impl : public ProgramImpl {
77         public:
78             void emitCode(EmitArgs& args) override {
79                 args.fFragBuilder->codeAppendf("return half4(1);\n");
80             }
81         };
82 
83         return std::make_unique<Impl>();
84     }
85 
clone() const86     std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
87 
88 private:
BigKeyProcessor()89     BigKeyProcessor() : INHERITED(kBigKeyProcessor_ClassID, kNone_OptimizationFlags) {}
onAddToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const90     void onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override {
91         for (uint32_t i = 0; i < kMaxKeySize; i++) {
92             b->add32(i);
93         }
94     }
onIsEqual(const GrFragmentProcessor &) const95     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
96 
97     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
98 
99     using INHERITED = GrFragmentProcessor;
100 };
101 }  // anonymous namespace
102 
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor)103 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor)
104 
105 #if defined(GPU_TEST_UTILS)
106 std::unique_ptr<GrFragmentProcessor> BigKeyProcessor::TestCreate(GrProcessorTestData*) {
107     return BigKeyProcessor::Make();
108 }
109 #endif
110 
111 //////////////////////////////////////////////////////////////////////////////
112 
113 class BlockInputFragmentProcessor : public GrFragmentProcessor {
114 public:
Make(std::unique_ptr<GrFragmentProcessor> fp)115     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
116         return std::unique_ptr<GrFragmentProcessor>(new BlockInputFragmentProcessor(std::move(fp)));
117     }
118 
name() const119     const char* name() const override { return "Block_Input"; }
120 
onMakeProgramImpl() const121     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
122         return std::make_unique<GLFP>();
123     }
124 
clone() const125     std::unique_ptr<GrFragmentProcessor> clone() const override {
126         return Make(this->childProcessor(0)->clone());
127     }
128 
129 private:
130     class GLFP : public ProgramImpl {
131     public:
emitCode(EmitArgs & args)132         void emitCode(EmitArgs& args) override {
133             SkString temp = this->invokeChild(0, args);
134             args.fFragBuilder->codeAppendf("return %s;", temp.c_str());
135         }
136 
137     private:
138         using INHERITED = ProgramImpl;
139     };
140 
BlockInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child)141     BlockInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child)
142             : INHERITED(kBlockInputFragmentProcessor_ClassID, kNone_OptimizationFlags) {
143         this->registerChild(std::move(child));
144     }
145 
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const146     void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {}
147 
onIsEqual(const GrFragmentProcessor &) const148     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
149 
150     using INHERITED = GrFragmentProcessor;
151 };
152 
153 //////////////////////////////////////////////////////////////////////////////
154 
155 /*
156  * Begin test code
157  */
158 static const int kRenderTargetHeight = 1;
159 static const int kRenderTargetWidth = 1;
160 
random_surface_draw_context(GrRecordingContext * rContext,SkRandom * random,const GrCaps * caps)161 static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> random_surface_draw_context(
162         GrRecordingContext* rContext, SkRandom* random, const GrCaps* caps) {
163     GrSurfaceOrigin origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin
164                                                 : kBottomLeft_GrSurfaceOrigin;
165 
166     GrColorType ct = GrColorType::kRGBA_8888;
167     const GrBackendFormat format = caps->getDefaultBackendFormat(ct, GrRenderable::kYes);
168 
169     int sampleCnt = random->nextBool() ? caps->getRenderTargetSampleCount(2, format) : 1;
170     // Above could be 0 if msaa isn't supported.
171     sampleCnt = std::max(1, sampleCnt);
172 
173     return skgpu::ganesh::SurfaceDrawContext::Make(rContext,
174                                                    GrColorType::kRGBA_8888,
175                                                    nullptr,
176                                                    SkBackingFit::kExact,
177                                                    {kRenderTargetWidth, kRenderTargetHeight},
178                                                    SkSurfaceProps(),
179                                                    /*label=*/{},
180                                                    sampleCnt,
181                                                    skgpu::Mipmapped::kNo,
182                                                    GrProtected::kNo,
183                                                    origin);
184 }
185 
186 #if defined(GPU_TEST_UTILS)
set_random_xpf(GrPaint * paint,GrProcessorTestData * d)187 static void set_random_xpf(GrPaint* paint, GrProcessorTestData* d) {
188     paint->setXPFactory(GrXPFactoryTestFactory::Get(d));
189 }
190 
create_random_proc_tree(GrProcessorTestData * d,int minLevels,int maxLevels)191 static std::unique_ptr<GrFragmentProcessor> create_random_proc_tree(GrProcessorTestData* d,
192                                                                     int minLevels, int maxLevels) {
193     SkASSERT(1 <= minLevels);
194     SkASSERT(minLevels <= maxLevels);
195 
196     // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
197     // If returning a leaf node, make sure that it doesn't have children (e.g. another
198     // GrComposeEffect)
199     const float terminateProbability = 0.3f;
200     if (1 == minLevels) {
201         bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
202         if (terminate) {
203             std::unique_ptr<GrFragmentProcessor> fp;
204             while (true) {
205                 fp = GrFragmentProcessorTestFactory::Make(d);
206                 if (!fp) {
207                     return nullptr;
208                 }
209                 if (0 == fp->numNonNullChildProcessors()) {
210                     break;
211                 }
212             }
213             return fp;
214         }
215     }
216     // If we didn't terminate, choose either the left or right subtree to fulfill
217     // the minLevels requirement of this tree; the other child can have as few levels as it wants.
218     // Also choose a random xfer mode.
219     if (minLevels > 1) {
220         --minLevels;
221     }
222     auto minLevelsChild = create_random_proc_tree(d, minLevels, maxLevels - 1);
223     std::unique_ptr<GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1, maxLevels - 1));
224     if (!minLevelsChild || !otherChild) {
225         return nullptr;
226     }
227     SkBlendMode mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0,
228                                                                (int)SkBlendMode::kLastMode));
229     std::unique_ptr<GrFragmentProcessor> fp;
230     if (d->fRandom->nextF() < 0.5f) {
231         fp = GrBlendFragmentProcessor::Make(std::move(minLevelsChild), std::move(otherChild), mode);
232         SkASSERT(fp);
233     } else {
234         fp = GrBlendFragmentProcessor::Make(std::move(otherChild), std::move(minLevelsChild), mode);
235         SkASSERT(fp);
236     }
237     return fp;
238 }
239 
set_random_color_coverage_stages(GrPaint * paint,GrProcessorTestData * d,int maxStages,int maxTreeLevels)240 static void set_random_color_coverage_stages(GrPaint* paint,
241                                              GrProcessorTestData* d,
242                                              int maxStages,
243                                              int maxTreeLevels) {
244     // Randomly choose to either create a linear pipeline of procs or create one proc tree
245     const float procTreeProbability = 0.5f;
246     if (d->fRandom->nextF() < procTreeProbability) {
247         std::unique_ptr<GrFragmentProcessor> fp(create_random_proc_tree(d, 2, maxTreeLevels));
248         if (fp) {
249             paint->setColorFragmentProcessor(std::move(fp));
250         }
251     } else {
252         if (maxStages >= 1) {
253             if (std::unique_ptr<GrFragmentProcessor> fp = GrFragmentProcessorTestFactory::Make(d)) {
254                 paint->setColorFragmentProcessor(std::move(fp));
255             }
256         }
257         if (maxStages >= 2) {
258             if (std::unique_ptr<GrFragmentProcessor> fp = GrFragmentProcessorTestFactory::Make(d)) {
259                 paint->setCoverageFragmentProcessor(std::move(fp));
260             }
261         }
262     }
263 }
264 
265 #endif
266 
267 #if !defined(GPU_TEST_UTILS)
ProgramUnitTest(GrDirectContext *,int)268 bool GrDrawingManager::ProgramUnitTest(GrDirectContext*, int) { return true; }
269 #else
ProgramUnitTest(GrDirectContext * direct,int maxStages,int maxLevels)270 bool GrDrawingManager::ProgramUnitTest(GrDirectContext* direct, int maxStages, int maxLevels) {
271     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
272     const GrCaps* caps = direct->priv().caps();
273 
274     GrProcessorTestData::ViewInfo views[2];
275 
276     // setup arbitrary textures
277     skgpu::Mipmapped mipmapped = skgpu::Mipmapped(caps->mipmapSupport());
278     {
279         static constexpr SkISize kDims = {34, 18};
280         const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
281                                                                      GrRenderable::kYes);
282         auto proxy = proxyProvider->createProxy(format,
283                                                 kDims,
284                                                 GrRenderable::kYes,
285                                                 1,
286                                                 mipmapped,
287                                                 SkBackingFit::kExact,
288                                                 skgpu::Budgeted::kNo,
289                                                 GrProtected::kNo,
290                                                 /*label=*/{},
291                                                 GrInternalSurfaceFlags::kNone);
292         skgpu::Swizzle swizzle = caps->getReadSwizzle(format, GrColorType::kRGBA_8888);
293         views[0] = {{std::move(proxy), kBottomLeft_GrSurfaceOrigin, swizzle},
294                     GrColorType::kRGBA_8888, kPremul_SkAlphaType};
295     }
296     {
297         static constexpr SkISize kDims = {16, 22};
298         const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8,
299                                                                      GrRenderable::kNo);
300         auto proxy = proxyProvider->createProxy(format,
301                                                 kDims,
302                                                 GrRenderable::kNo,
303                                                 1,
304                                                 mipmapped,
305                                                 SkBackingFit::kExact,
306                                                 skgpu::Budgeted::kNo,
307                                                 GrProtected::kNo,
308                                                 /*label=*/{},
309                                                 GrInternalSurfaceFlags::kNone);
310         skgpu::Swizzle swizzle = caps->getReadSwizzle(format, GrColorType::kAlpha_8);
311         views[1] = {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle},
312                       GrColorType::kAlpha_8, kPremul_SkAlphaType};
313     }
314 
315     if (!std::get<0>(views[0]) || !std::get<0>(views[1])) {
316         SkDebugf("Could not allocate textures for test");
317         return false;
318     }
319 
320     SkRandom random;
321     static const int NUM_TESTS = 1024;
322     for (int t = 0; t < NUM_TESTS; t++) {
323         // setup random render target(can fail)
324         auto surfaceDrawContext = random_surface_draw_context(direct, &random, caps);
325         if (!surfaceDrawContext) {
326             SkDebugf("Could not allocate surfaceDrawContext");
327             return false;
328         }
329 
330         GrPaint paint;
331         GrProcessorTestData ptd(&random, direct, /*maxTreeDepth=*/1, std::size(views), views);
332         set_random_color_coverage_stages(&paint, &ptd, maxStages, maxLevels);
333         set_random_xpf(&paint, &ptd);
334         GrDrawRandomOp(&random, surfaceDrawContext.get(), std::move(paint));
335     }
336     // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
337     direct->flush(GrFlushInfo());
338     direct->submit(GrSyncCpu::kNo);
339 
340     // Validate that GrFPs work correctly without an input.
341     auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(direct,
342                                                        GrColorType::kRGBA_8888,
343                                                        nullptr,
344                                                        SkBackingFit::kExact,
345                                                        {kRenderTargetWidth, kRenderTargetHeight},
346                                                        SkSurfaceProps(),
347                                                        /*label=*/{});
348     if (!sdc) {
349         SkDebugf("Could not allocate a surfaceDrawContext");
350         return false;
351     }
352 
353     int fpFactoryCnt = GrFragmentProcessorTestFactory::Count();
354     for (int i = 0; i < fpFactoryCnt; ++i) {
355         // Since FP factories internally randomize, call each 10 times.
356         for (int j = 0; j < 10; ++j) {
357             GrProcessorTestData ptd(&random, direct, /*maxTreeDepth=*/1, std::size(views),
358                                     views);
359 
360             GrPaint paint;
361             paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
362             auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &ptd);
363             auto blockFP = BlockInputFragmentProcessor::Make(std::move(fp));
364             paint.setColorFragmentProcessor(std::move(blockFP));
365             GrDrawRandomOp(&random, sdc.get(), std::move(paint));
366 
367             direct->flush(GrFlushInfo());
368             direct->submit(GrSyncCpu::kNo);
369         }
370     }
371 
372     return true;
373 }
374 #endif
375 
get_programs_max_stages(const sk_gpu_test::ContextInfo & ctxInfo)376 static int get_programs_max_stages(const sk_gpu_test::ContextInfo& ctxInfo) {
377     int maxStages = 6;
378 #ifdef SK_GL
379     auto context = ctxInfo.directContext();
380     if (skiatest::IsGLContextType(ctxInfo.type())) {
381         GrGLGpu* gpu = static_cast<GrGLGpu*>(context->priv().getGpu());
382         if (kGLES_GrGLStandard == gpu->glStandard()) {
383         // We've had issues with driver crashes and HW limits being exceeded with many effects on
384         // Android devices. We have passes on ARM devices with the default number of stages.
385         // TODO When we run ES 3.00 GLSL in more places, test again
386 #ifdef SK_BUILD_FOR_ANDROID
387         if (gpu->ctxInfo().vendor() != GrGLVendor::kARM) {
388             maxStages = 1;
389         }
390 #endif
391         // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
392 #ifdef SK_BUILD_FOR_IOS
393             maxStages = 3;
394 #endif
395         }
396         // On Angle D3D we will hit a limit of out variables if we use too many stages. This is
397         // particularly true on D3D9 with a low limit on varyings and the fact that every varying is
398         // packed as though it has 4 components.
399         if (ctxInfo.type() == skgpu::ContextType::kANGLE_D3D9_ES2) {
400             maxStages = 2;
401         } else if (ctxInfo.type() == skgpu::ContextType::kANGLE_D3D11_ES2) {
402             maxStages = 3;
403         }
404     }
405 #endif
406     return maxStages;
407 }
408 
get_programs_max_levels(const sk_gpu_test::ContextInfo & ctxInfo)409 static int get_programs_max_levels(const sk_gpu_test::ContextInfo& ctxInfo) {
410     // A full tree with 5 levels (31 nodes) may cause a program that exceeds shader limits
411     // (e.g. uniform or varying limits); maxTreeLevels should be a number from 1 to 4 inclusive.
412     int maxTreeLevels = 4;
413     if (skiatest::IsGLContextType(ctxInfo.type())) {
414         // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
415 #ifdef SK_BUILD_FOR_IOS
416         maxTreeLevels = 2;
417 #endif
418 #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_GL)
419         GrGLGpu* gpu = static_cast<GrGLGpu*>(ctxInfo.directContext()->priv().getGpu());
420         // Tecno Spark 3 Pro with Power VR Rogue GE8300 will fail shader compiles with
421         // no message if the shader is particularly long.
422         if (gpu->ctxInfo().vendor() == GrGLVendor::kImagination) {
423             maxTreeLevels = 3;
424         }
425 #endif
426         if (ctxInfo.type() == skgpu::ContextType::kANGLE_D3D9_ES2 ||
427             ctxInfo.type() == skgpu::ContextType::kANGLE_D3D11_ES2) {
428             // On Angle D3D we will hit a limit of out variables if we use too many stages.
429             maxTreeLevels = 2;
430         }
431     }
432     return maxTreeLevels;
433 }
434 
test_programs(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)435 static void test_programs(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo) {
436     int maxStages = get_programs_max_stages(ctxInfo);
437     if (maxStages == 0) {
438         return;
439     }
440     int maxLevels = get_programs_max_levels(ctxInfo);
441     if (maxLevels == 0) {
442         return;
443     }
444 
445     REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(ctxInfo.directContext(), maxStages,
446                                                                 maxLevels));
447 }
448 
DEF_GANESH_TEST(Programs,reporter,options,CtsEnforcement::kNever)449 DEF_GANESH_TEST(Programs, reporter, options, CtsEnforcement::kNever) {
450     // Set a locale that would cause shader compilation to fail because of , as decimal separator.
451     // skbug 3330
452 #ifdef SK_BUILD_FOR_WIN
453     GrAutoLocaleSetter als("sv-SE");
454 #else
455     GrAutoLocaleSetter als("sv_SE.UTF-8");
456 #endif
457 
458     // We suppress prints to avoid spew
459     GrContextOptions opts = options;
460     opts.fSuppressPrints = true;
461     sk_gpu_test::GrContextFactory debugFactory(opts);
462     skiatest::RunWithGaneshTestContexts(test_programs, &skgpu::IsRenderingContext, reporter, opts);
463 }
464