• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrBackendSurface.h"
19 #include "include/gpu/GrContextOptions.h"
20 #include "include/gpu/GrDirectContext.h"
21 #include "include/gpu/GrTypes.h"
22 #include "include/gpu/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 GR_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::v1::SurfaceDrawContext> random_surface_draw_context(
162         GrRecordingContext* rContext,
163         SkRandom* random,
164         const GrCaps* caps) {
165     GrSurfaceOrigin origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin
166                                                 : kBottomLeft_GrSurfaceOrigin;
167 
168     GrColorType ct = GrColorType::kRGBA_8888;
169     const GrBackendFormat format = caps->getDefaultBackendFormat(ct, GrRenderable::kYes);
170 
171     int sampleCnt = random->nextBool() ? caps->getRenderTargetSampleCount(2, format) : 1;
172     // Above could be 0 if msaa isn't supported.
173     sampleCnt = std::max(1, sampleCnt);
174 
175     return skgpu::v1::SurfaceDrawContext::Make(
176             rContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact,
177             {kRenderTargetWidth, kRenderTargetHeight}, SkSurfaceProps(), /*label=*/{},
178             sampleCnt, GrMipmapped::kNo, GrProtected::kNo, origin);
179 }
180 
181 #if GR_TEST_UTILS
set_random_xpf(GrPaint * paint,GrProcessorTestData * d)182 static void set_random_xpf(GrPaint* paint, GrProcessorTestData* d) {
183     paint->setXPFactory(GrXPFactoryTestFactory::Get(d));
184 }
185 
create_random_proc_tree(GrProcessorTestData * d,int minLevels,int maxLevels)186 static std::unique_ptr<GrFragmentProcessor> create_random_proc_tree(GrProcessorTestData* d,
187                                                                     int minLevels, int maxLevels) {
188     SkASSERT(1 <= minLevels);
189     SkASSERT(minLevels <= maxLevels);
190 
191     // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
192     // If returning a leaf node, make sure that it doesn't have children (e.g. another
193     // GrComposeEffect)
194     const float terminateProbability = 0.3f;
195     if (1 == minLevels) {
196         bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
197         if (terminate) {
198             std::unique_ptr<GrFragmentProcessor> fp;
199             while (true) {
200                 fp = GrFragmentProcessorTestFactory::Make(d);
201                 if (!fp) {
202                     return nullptr;
203                 }
204                 if (0 == fp->numNonNullChildProcessors()) {
205                     break;
206                 }
207             }
208             return fp;
209         }
210     }
211     // If we didn't terminate, choose either the left or right subtree to fulfill
212     // the minLevels requirement of this tree; the other child can have as few levels as it wants.
213     // Also choose a random xfer mode.
214     if (minLevels > 1) {
215         --minLevels;
216     }
217     auto minLevelsChild = create_random_proc_tree(d, minLevels, maxLevels - 1);
218     std::unique_ptr<GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1, maxLevels - 1));
219     if (!minLevelsChild || !otherChild) {
220         return nullptr;
221     }
222     SkBlendMode mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0,
223                                                                (int)SkBlendMode::kLastMode));
224     std::unique_ptr<GrFragmentProcessor> fp;
225     if (d->fRandom->nextF() < 0.5f) {
226         fp = GrBlendFragmentProcessor::Make(std::move(minLevelsChild), std::move(otherChild), mode);
227         SkASSERT(fp);
228     } else {
229         fp = GrBlendFragmentProcessor::Make(std::move(otherChild), std::move(minLevelsChild), mode);
230         SkASSERT(fp);
231     }
232     return fp;
233 }
234 
set_random_color_coverage_stages(GrPaint * paint,GrProcessorTestData * d,int maxStages,int maxTreeLevels)235 static void set_random_color_coverage_stages(GrPaint* paint,
236                                              GrProcessorTestData* d,
237                                              int maxStages,
238                                              int maxTreeLevels) {
239     // Randomly choose to either create a linear pipeline of procs or create one proc tree
240     const float procTreeProbability = 0.5f;
241     if (d->fRandom->nextF() < procTreeProbability) {
242         std::unique_ptr<GrFragmentProcessor> fp(create_random_proc_tree(d, 2, maxTreeLevels));
243         if (fp) {
244             paint->setColorFragmentProcessor(std::move(fp));
245         }
246     } else {
247         if (maxStages >= 1) {
248             if (std::unique_ptr<GrFragmentProcessor> fp = GrFragmentProcessorTestFactory::Make(d)) {
249                 paint->setColorFragmentProcessor(std::move(fp));
250             }
251         }
252         if (maxStages >= 2) {
253             if (std::unique_ptr<GrFragmentProcessor> fp = GrFragmentProcessorTestFactory::Make(d)) {
254                 paint->setCoverageFragmentProcessor(std::move(fp));
255             }
256         }
257     }
258 }
259 
260 #endif
261 
262 #if !GR_TEST_UTILS
ProgramUnitTest(GrDirectContext *,int)263 bool GrDrawingManager::ProgramUnitTest(GrDirectContext*, int) { return true; }
264 #else
ProgramUnitTest(GrDirectContext * direct,int maxStages,int maxLevels)265 bool GrDrawingManager::ProgramUnitTest(GrDirectContext* direct, int maxStages, int maxLevels) {
266     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
267     const GrCaps* caps = direct->priv().caps();
268 
269     GrProcessorTestData::ViewInfo views[2];
270 
271     // setup arbitrary textures
272     GrMipmapped mipmapped = GrMipmapped(caps->mipmapSupport());
273     {
274         static constexpr SkISize kDims = {34, 18};
275         const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
276                                                                      GrRenderable::kYes);
277         auto proxy = proxyProvider->createProxy(format,
278                                                 kDims,
279                                                 GrRenderable::kYes,
280                                                 1,
281                                                 mipmapped,
282                                                 SkBackingFit::kExact,
283                                                 skgpu::Budgeted::kNo,
284                                                 GrProtected::kNo,
285                                                 /*label=*/{},
286                                                 GrInternalSurfaceFlags::kNone);
287         skgpu::Swizzle swizzle = caps->getReadSwizzle(format, GrColorType::kRGBA_8888);
288         views[0] = {{std::move(proxy), kBottomLeft_GrSurfaceOrigin, swizzle},
289                     GrColorType::kRGBA_8888, kPremul_SkAlphaType};
290     }
291     {
292         static constexpr SkISize kDims = {16, 22};
293         const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8,
294                                                                      GrRenderable::kNo);
295         auto proxy = proxyProvider->createProxy(format,
296                                                 kDims,
297                                                 GrRenderable::kNo,
298                                                 1,
299                                                 mipmapped,
300                                                 SkBackingFit::kExact,
301                                                 skgpu::Budgeted::kNo,
302                                                 GrProtected::kNo,
303                                                 /*label=*/{},
304                                                 GrInternalSurfaceFlags::kNone);
305         skgpu::Swizzle swizzle = caps->getReadSwizzle(format, GrColorType::kAlpha_8);
306         views[1] = {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle},
307                       GrColorType::kAlpha_8, kPremul_SkAlphaType};
308     }
309 
310     if (!std::get<0>(views[0]) || !std::get<0>(views[1])) {
311         SkDebugf("Could not allocate textures for test");
312         return false;
313     }
314 
315     SkRandom random;
316     static const int NUM_TESTS = 1024;
317     for (int t = 0; t < NUM_TESTS; t++) {
318         // setup random render target(can fail)
319         auto surfaceDrawContext = random_surface_draw_context(direct, &random, caps);
320         if (!surfaceDrawContext) {
321             SkDebugf("Could not allocate surfaceDrawContext");
322             return false;
323         }
324 
325         GrPaint paint;
326         GrProcessorTestData ptd(&random, direct, /*maxTreeDepth=*/1, std::size(views), views);
327         set_random_color_coverage_stages(&paint, &ptd, maxStages, maxLevels);
328         set_random_xpf(&paint, &ptd);
329         GrDrawRandomOp(&random, surfaceDrawContext.get(), std::move(paint));
330     }
331     // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
332     direct->flush(GrFlushInfo());
333     direct->submit(false);
334 
335     // Validate that GrFPs work correctly without an input.
336     auto sdc = skgpu::v1::SurfaceDrawContext::Make(
337             direct, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact,
338             {kRenderTargetWidth, kRenderTargetHeight}, SkSurfaceProps(),
339             /*label=*/{});
340     if (!sdc) {
341         SkDebugf("Could not allocate a surfaceDrawContext");
342         return false;
343     }
344 
345     int fpFactoryCnt = GrFragmentProcessorTestFactory::Count();
346     for (int i = 0; i < fpFactoryCnt; ++i) {
347         // Since FP factories internally randomize, call each 10 times.
348         for (int j = 0; j < 10; ++j) {
349             GrProcessorTestData ptd(&random, direct, /*maxTreeDepth=*/1, std::size(views),
350                                     views);
351 
352             GrPaint paint;
353             paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
354             auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &ptd);
355             auto blockFP = BlockInputFragmentProcessor::Make(std::move(fp));
356             paint.setColorFragmentProcessor(std::move(blockFP));
357             GrDrawRandomOp(&random, sdc.get(), std::move(paint));
358 
359             direct->flush(GrFlushInfo());
360             direct->submit(false);
361         }
362     }
363 
364     return true;
365 }
366 #endif
367 
get_programs_max_stages(const sk_gpu_test::ContextInfo & ctxInfo)368 static int get_programs_max_stages(const sk_gpu_test::ContextInfo& ctxInfo) {
369     int maxStages = 6;
370 #ifdef SK_GL
371     auto context = ctxInfo.directContext();
372     if (skiatest::IsGLContextType(ctxInfo.type())) {
373         GrGLGpu* gpu = static_cast<GrGLGpu*>(context->priv().getGpu());
374         if (kGLES_GrGLStandard == gpu->glStandard()) {
375         // We've had issues with driver crashes and HW limits being exceeded with many effects on
376         // Android devices. We have passes on ARM devices with the default number of stages.
377         // TODO When we run ES 3.00 GLSL in more places, test again
378 #ifdef SK_BUILD_FOR_ANDROID
379         if (gpu->ctxInfo().vendor() != GrGLVendor::kARM) {
380             maxStages = 1;
381         }
382 #endif
383         // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
384 #ifdef SK_BUILD_FOR_IOS
385             maxStages = 3;
386 #endif
387         }
388         // On Angle D3D we will hit a limit of out variables if we use too many stages. This is
389         // particularly true on D3D9 with a low limit on varyings and the fact that every varying is
390         // packed as though it has 4 components.
391         if (ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D9_ES2_ContextType) {
392             maxStages = 2;
393         } else if (ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES2_ContextType) {
394             maxStages = 3;
395         }
396     }
397 #endif
398     return maxStages;
399 }
400 
get_programs_max_levels(const sk_gpu_test::ContextInfo & ctxInfo)401 static int get_programs_max_levels(const sk_gpu_test::ContextInfo& ctxInfo) {
402     // A full tree with 5 levels (31 nodes) may cause a program that exceeds shader limits
403     // (e.g. uniform or varying limits); maxTreeLevels should be a number from 1 to 4 inclusive.
404     int maxTreeLevels = 4;
405     if (skiatest::IsGLContextType(ctxInfo.type())) {
406         // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
407 #ifdef SK_BUILD_FOR_IOS
408         maxTreeLevels = 2;
409 #endif
410 #if defined(SK_BUILD_FOR_ANDROID) && defined(SK_GL)
411         GrGLGpu* gpu = static_cast<GrGLGpu*>(ctxInfo.directContext()->priv().getGpu());
412         // Tecno Spark 3 Pro with Power VR Rogue GE8300 will fail shader compiles with
413         // no message if the shader is particularly long.
414         if (gpu->ctxInfo().vendor() == GrGLVendor::kImagination) {
415             maxTreeLevels = 3;
416         }
417 #endif
418         if (ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D9_ES2_ContextType ||
419             ctxInfo.type() == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES2_ContextType) {
420             // On Angle D3D we will hit a limit of out variables if we use too many stages.
421             maxTreeLevels = 2;
422         }
423     }
424     return maxTreeLevels;
425 }
426 
test_programs(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)427 static void test_programs(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo) {
428     int maxStages = get_programs_max_stages(ctxInfo);
429     if (maxStages == 0) {
430         return;
431     }
432     int maxLevels = get_programs_max_levels(ctxInfo);
433     if (maxLevels == 0) {
434         return;
435     }
436 
437     REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(ctxInfo.directContext(), maxStages,
438                                                                 maxLevels));
439 }
440 
DEF_GANESH_TEST(Programs,reporter,options,CtsEnforcement::kNever)441 DEF_GANESH_TEST(Programs, reporter, options, CtsEnforcement::kNever) {
442     // Set a locale that would cause shader compilation to fail because of , as decimal separator.
443     // skbug 3330
444 #ifdef SK_BUILD_FOR_WIN
445     GrAutoLocaleSetter als("sv-SE");
446 #else
447     GrAutoLocaleSetter als("sv_SE.UTF-8");
448 #endif
449 
450     // We suppress prints to avoid spew
451     GrContextOptions opts = options;
452     opts.fSuppressPrints = true;
453     sk_gpu_test::GrContextFactory debugFactory(opts);
454     skiatest::RunWithGaneshTestContexts(
455             test_programs, &sk_gpu_test::GrContextFactory::IsRenderingContext, reporter, opts);
456 }
457