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