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