• Home
  • History
  • Annotate
  • 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. It relies on static intializers to work
9 
10 #include "SkTypes.h"
11 
12 #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
13 
14 #include "GrAutoLocaleSetter.h"
15 #include "GrContextFactory.h"
16 #include "GrContextPriv.h"
17 #include "GrDrawOpTest.h"
18 #include "GrDrawingManager.h"
19 #include "GrPipeline.h"
20 #include "GrRenderTargetContextPriv.h"
21 #include "GrResourceProvider.h"
22 #include "GrTest.h"
23 #include "GrXferProcessor.h"
24 #include "SkChecksum.h"
25 #include "SkRandom.h"
26 #include "Test.h"
27 
28 #include "ops/GrDrawOp.h"
29 
30 #include "effects/GrConfigConversionEffect.h"
31 #include "effects/GrPorterDuffXferProcessor.h"
32 #include "effects/GrXfermodeFragmentProcessor.h"
33 
34 #include "gl/GrGLGpu.h"
35 #include "glsl/GrGLSLFragmentProcessor.h"
36 #include "glsl/GrGLSLFragmentShaderBuilder.h"
37 #include "glsl/GrGLSLProgramBuilder.h"
38 
39 /*
40  * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
41  * whole thing correctly
42  */
43 static const uint32_t kMaxKeySize = 1024;
44 
45 class GLBigKeyProcessor : public GrGLSLFragmentProcessor {
46 public:
emitCode(EmitArgs & args)47     void emitCode(EmitArgs& args) override {
48         // pass through
49         GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
50         if (args.fInputColor) {
51             fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor);
52         } else {
53             fragBuilder->codeAppendf("%s = vec4(1.0);\n", args.fOutputColor);
54         }
55     }
56 
GenKey(const GrProcessor &,const GrShaderCaps &,GrProcessorKeyBuilder * b)57     static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
58         for (uint32_t i = 0; i < kMaxKeySize; i++) {
59             b->add32(i);
60         }
61     }
62 
63 private:
64     typedef GrGLSLFragmentProcessor INHERITED;
65 };
66 
67 class BigKeyProcessor : public GrFragmentProcessor {
68 public:
Make()69     static sk_sp<GrFragmentProcessor> Make() {
70         return sk_sp<GrFragmentProcessor>(new BigKeyProcessor);
71     }
72 
name() const73     const char* name() const override { return "Big Ole Key"; }
74 
onCreateGLSLInstance() const75     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
76         return new GLBigKeyProcessor;
77     }
78 
79 private:
BigKeyProcessor()80     BigKeyProcessor() : INHERITED(kNone_OptimizationFlags) { this->initClassID<BigKeyProcessor>(); }
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const81     virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
82                                        GrProcessorKeyBuilder* b) const override {
83         GLBigKeyProcessor::GenKey(*this, caps, b);
84     }
onIsEqual(const GrFragmentProcessor &) const85     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
86 
87     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
88 
89     typedef GrFragmentProcessor INHERITED;
90 };
91 
92 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
93 
94 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData *)95 sk_sp<GrFragmentProcessor> BigKeyProcessor::TestCreate(GrProcessorTestData*) {
96     return BigKeyProcessor::Make();
97 }
98 #endif
99 
100 //////////////////////////////////////////////////////////////////////////////
101 
102 class BlockInputFragmentProcessor : public GrFragmentProcessor {
103 public:
Make(sk_sp<GrFragmentProcessor> fp)104     static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor> fp) {
105         return sk_sp<GrFragmentProcessor>(new BlockInputFragmentProcessor(fp));
106     }
107 
name() const108     const char* name() const override { return "Block Input"; }
109 
onCreateGLSLInstance() const110     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLFP; }
111 
112 private:
113     class GLFP : public GrGLSLFragmentProcessor {
114     public:
emitCode(EmitArgs & args)115         void emitCode(EmitArgs& args) override {
116             this->emitChild(0, nullptr, args);
117         }
118 
119     private:
120         typedef GrGLSLFragmentProcessor INHERITED;
121     };
122 
BlockInputFragmentProcessor(sk_sp<GrFragmentProcessor> child)123     BlockInputFragmentProcessor(sk_sp<GrFragmentProcessor> child)
124             : INHERITED(kNone_OptimizationFlags) {
125         this->initClassID<BlockInputFragmentProcessor>();
126         this->registerChildProcessor(std::move(child));
127     }
128 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const129     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {}
130 
onIsEqual(const GrFragmentProcessor &) const131     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
132 
133     typedef GrFragmentProcessor INHERITED;
134 };
135 
136 //////////////////////////////////////////////////////////////////////////////
137 
138 /*
139  * Begin test code
140  */
141 static const int kRenderTargetHeight = 1;
142 static const int kRenderTargetWidth = 1;
143 
random_render_target_context(GrContext * context,SkRandom * random,const GrCaps * caps)144 static sk_sp<GrRenderTargetContext> random_render_target_context(GrContext* context,
145                                                                  SkRandom* random,
146                                                                  const GrCaps* caps) {
147     GrSurfaceOrigin origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin
148                                                 : kBottomLeft_GrSurfaceOrigin;
149     int sampleCnt = random->nextBool() ? SkTMin(4, caps->maxSampleCount()) : 0;
150 
151     sk_sp<GrRenderTargetContext> renderTargetContext(context->makeRenderTargetContext(
152                                                                            SkBackingFit::kExact,
153                                                                            kRenderTargetWidth,
154                                                                            kRenderTargetHeight,
155                                                                            kRGBA_8888_GrPixelConfig,
156                                                                            nullptr,
157                                                                            sampleCnt,
158                                                                            origin));
159     return renderTargetContext;
160 }
161 
162 #if GR_TEST_UTILS
set_random_xpf(GrPaint * paint,GrProcessorTestData * d)163 static void set_random_xpf(GrPaint* paint, GrProcessorTestData* d) {
164     paint->setXPFactory(GrXPFactoryTestFactory::Get(d));
165 }
166 
create_random_proc_tree(GrProcessorTestData * d,int minLevels,int maxLevels)167 static sk_sp<GrFragmentProcessor> create_random_proc_tree(GrProcessorTestData* d,
168                                                           int minLevels, int maxLevels) {
169     SkASSERT(1 <= minLevels);
170     SkASSERT(minLevels <= maxLevels);
171 
172     // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
173     // If returning a leaf node, make sure that it doesn't have children (e.g. another
174     // GrComposeEffect)
175     const float terminateProbability = 0.3f;
176     if (1 == minLevels) {
177         bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
178         if (terminate) {
179             sk_sp<GrFragmentProcessor> fp;
180             while (true) {
181                 fp = GrProcessorTestFactory<GrFragmentProcessor>::Make(d);
182                 SkASSERT(fp);
183                 if (0 == fp->numChildProcessors()) {
184                     break;
185                 }
186             }
187             return fp;
188         }
189     }
190     // If we didn't terminate, choose either the left or right subtree to fulfill
191     // the minLevels requirement of this tree; the other child can have as few levels as it wants.
192     // Also choose a random xfer mode.
193     if (minLevels > 1) {
194         --minLevels;
195     }
196     sk_sp<GrFragmentProcessor> minLevelsChild(create_random_proc_tree(d, minLevels, maxLevels - 1));
197     sk_sp<GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1, maxLevels - 1));
198     SkBlendMode mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0,
199                                                                (int)SkBlendMode::kLastMode));
200     sk_sp<GrFragmentProcessor> fp;
201     if (d->fRandom->nextF() < 0.5f) {
202         fp = GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(minLevelsChild),
203                                                                 std::move(otherChild), mode);
204         SkASSERT(fp);
205     } else {
206         fp = GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(otherChild),
207                                                                 std::move(minLevelsChild), mode);
208         SkASSERT(fp);
209     }
210     return fp;
211 }
212 
set_random_color_coverage_stages(GrPaint * paint,GrProcessorTestData * d,int maxStages)213 static void set_random_color_coverage_stages(GrPaint* paint,
214                                              GrProcessorTestData* d,
215                                              int maxStages) {
216     // Randomly choose to either create a linear pipeline of procs or create one proc tree
217     const float procTreeProbability = 0.5f;
218     if (d->fRandom->nextF() < procTreeProbability) {
219         // A full tree with 5 levels (31 nodes) may cause a program that exceeds shader limits
220         // (e.g. uniform or varying limits); maxTreeLevels should be a number from 1 to 4 inclusive.
221         const int maxTreeLevels = 4;
222         sk_sp<GrFragmentProcessor> fp(create_random_proc_tree(d, 2, maxTreeLevels));
223         paint->addColorFragmentProcessor(std::move(fp));
224     } else {
225         int numProcs = d->fRandom->nextULessThan(maxStages + 1);
226         int numColorProcs = d->fRandom->nextULessThan(numProcs + 1);
227 
228         for (int s = 0; s < numProcs;) {
229             sk_sp<GrFragmentProcessor> fp(GrProcessorTestFactory<GrFragmentProcessor>::Make(d));
230             SkASSERT(fp);
231 
232             // finally add the stage to the correct pipeline in the drawstate
233             if (s < numColorProcs) {
234                 paint->addColorFragmentProcessor(std::move(fp));
235             } else {
236                 paint->addCoverageFragmentProcessor(std::move(fp));
237             }
238             ++s;
239         }
240     }
241 }
242 
set_random_state(GrPaint * paint,SkRandom * random)243 static bool set_random_state(GrPaint* paint, SkRandom* random) {
244     if (random->nextBool()) {
245         paint->setDisableOutputConversionToSRGB(true);
246     }
247     if (random->nextBool()) {
248         paint->setAllowSRGBInputs(true);
249     }
250     return random->nextBool();
251 }
252 
253 // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
get_random_stencil(SkRandom * random)254 static const GrUserStencilSettings* get_random_stencil(SkRandom* random) {
255     static constexpr GrUserStencilSettings kDoesWriteStencil(
256         GrUserStencilSettings::StaticInit<
257             0xffff,
258             GrUserStencilTest::kAlways,
259             0xffff,
260             GrUserStencilOp::kReplace,
261             GrUserStencilOp::kReplace,
262             0xffff>()
263     );
264     static constexpr GrUserStencilSettings kDoesNotWriteStencil(
265         GrUserStencilSettings::StaticInit<
266             0xffff,
267             GrUserStencilTest::kNever,
268             0xffff,
269             GrUserStencilOp::kKeep,
270             GrUserStencilOp::kKeep,
271             0xffff>()
272     );
273 
274     if (random->nextBool()) {
275         return &kDoesWriteStencil;
276     } else {
277         return &kDoesNotWriteStencil;
278     }
279 }
280 #endif
281 
282 #if !GR_TEST_UTILS
ProgramUnitTest(GrContext *,int)283 bool GrDrawingManager::ProgramUnitTest(GrContext*, int) { return true; }
284 #else
ProgramUnitTest(GrContext * context,int maxStages)285 bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages) {
286     GrDrawingManager* drawingManager = context->contextPriv().drawingManager();
287 
288     // setup dummy textures
289     GrSurfaceDesc dummyDesc;
290     dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
291     dummyDesc.fConfig = kRGBA_8888_GrPixelConfig;
292     dummyDesc.fWidth = 34;
293     dummyDesc.fHeight = 18;
294     sk_sp<GrTexture> dummyTexture1(
295         context->resourceProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));
296     dummyDesc.fFlags = kNone_GrSurfaceFlags;
297     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
298     dummyDesc.fWidth = 16;
299     dummyDesc.fHeight = 22;
300     sk_sp<GrTexture> dummyTexture2(
301         context->resourceProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));
302 
303     if (!dummyTexture1 || ! dummyTexture2) {
304         SkDebugf("Could not allocate dummy textures");
305         return false;
306     }
307 
308     GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
309 
310     // dummy scissor state
311     GrScissorState scissor;
312 
313     SkRandom random;
314     static const int NUM_TESTS = 1024;
315     for (int t = 0; t < NUM_TESTS; t++) {
316         // setup random render target(can fail)
317         sk_sp<GrRenderTargetContext> renderTargetContext(random_render_target_context(
318             context, &random, context->caps()));
319         if (!renderTargetContext) {
320             SkDebugf("Could not allocate renderTargetContext");
321             return false;
322         }
323 
324         GrPaint grPaint;
325 
326         std::unique_ptr<GrMeshDrawOp> op(GrRandomDrawOp(&random, context));
327         SkASSERT(op);
328 
329         GrProcessorTestData ptd(&random, context, renderTargetContext.get(), dummyTextures);
330         set_random_color_coverage_stages(&grPaint, &ptd, maxStages);
331         set_random_xpf(&grPaint, &ptd);
332         bool snapToCenters = set_random_state(&grPaint, &random);
333         const GrUserStencilSettings* uss = get_random_stencil(&random);
334         // We don't use kHW because we will hit an assertion if the render target is not
335         // multisampled
336         static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kCoverage};
337         GrAAType aaType = kAATypes[random.nextULessThan(SK_ARRAY_COUNT(kAATypes))];
338 
339         renderTargetContext->priv().testingOnly_addMeshDrawOp(std::move(grPaint), aaType,
340                                                               std::move(op), uss, snapToCenters);
341     }
342     // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
343     drawingManager->flush();
344 
345     // Validate that GrFPs work correctly without an input.
346     sk_sp<GrRenderTargetContext> renderTargetContext(context->makeRenderTargetContext(
347                                                                            SkBackingFit::kExact,
348                                                                            kRenderTargetWidth,
349                                                                            kRenderTargetHeight,
350                                                                            kRGBA_8888_GrPixelConfig,
351                                                                            nullptr));
352     if (!renderTargetContext) {
353         SkDebugf("Could not allocate a renderTargetContext");
354         return false;
355     }
356 
357     int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count();
358     for (int i = 0; i < fpFactoryCnt; ++i) {
359         // Since FP factories internally randomize, call each 10 times.
360         for (int j = 0; j < 10; ++j) {
361             std::unique_ptr<GrMeshDrawOp> op(GrRandomDrawOp(&random, context));
362             SkASSERT(op);
363             GrProcessorTestData ptd(&random, context, renderTargetContext.get(), dummyTextures);
364             GrPaint grPaint;
365             grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
366 
367             sk_sp<GrFragmentProcessor> fp(
368                 GrProcessorTestFactory<GrFragmentProcessor>::MakeIdx(i, &ptd));
369             sk_sp<GrFragmentProcessor> blockFP(
370                 BlockInputFragmentProcessor::Make(std::move(fp)));
371             grPaint.addColorFragmentProcessor(std::move(blockFP));
372 
373             renderTargetContext->priv().testingOnly_addMeshDrawOp(
374                     std::move(grPaint), GrAAType::kNone, std::move(op));
375             drawingManager->flush();
376         }
377     }
378 
379     return true;
380 }
381 #endif
382 
get_glprograms_max_stages(GrContext * context)383 static int get_glprograms_max_stages(GrContext* context) {
384     GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
385     /*
386      * For the time being, we only support the test with desktop GL or for android on
387      * ARM platforms
388      * TODO When we run ES 3.00 GLSL in more places, test again
389      */
390     if (kGL_GrGLStandard == gpu->glStandard() ||
391         kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
392         return 6;
393     } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
394                kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
395         return 1;
396     }
397     return 0;
398 }
399 
test_glprograms_native(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)400 static void test_glprograms_native(skiatest::Reporter* reporter,
401                                    const sk_gpu_test::ContextInfo& ctxInfo) {
402     int maxStages = get_glprograms_max_stages(ctxInfo.grContext());
403     if (maxStages == 0) {
404         return;
405     }
406     REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(ctxInfo.grContext(), maxStages));
407 }
408 
test_glprograms_other_contexts(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)409 static void test_glprograms_other_contexts(
410             skiatest::Reporter* reporter,
411             const sk_gpu_test::ContextInfo& ctxInfo) {
412     int maxStages = get_glprograms_max_stages(ctxInfo.grContext());
413 #ifdef SK_BUILD_FOR_WIN
414     // Some long shaders run out of temporary registers in the D3D compiler on ANGLE and
415     // command buffer.
416     maxStages = SkTMin(maxStages, 2);
417 #endif
418     if (maxStages == 0) {
419         return;
420     }
421     REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(ctxInfo.grContext(), maxStages));
422 }
423 
is_native_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type)424 static bool is_native_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type) {
425     return type == sk_gpu_test::GrContextFactory::kGL_ContextType ||
426            type == sk_gpu_test::GrContextFactory::kGLES_ContextType;
427 }
428 
is_other_rendering_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type)429 static bool is_other_rendering_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type) {
430     return !is_native_gl_context_type(type) &&
431            kOpenGL_GrBackend == sk_gpu_test::GrContextFactory::ContextTypeBackend(type) &&
432            sk_gpu_test::GrContextFactory::IsRenderingContext(type);
433 }
434 
435 DEF_GPUTEST(GLPrograms, reporter, /*factory*/) {
436     // Set a locale that would cause shader compilation to fail because of , as decimal separator.
437     // skbug 3330
438 #ifdef SK_BUILD_FOR_WIN
439     GrAutoLocaleSetter als("sv-SE");
440 #else
441     GrAutoLocaleSetter als("sv_SE.UTF-8");
442 #endif
443 
444     // We suppress prints to avoid spew
445     GrContextOptions opts;
446     opts.fSuppressPrints = true;
447     sk_gpu_test::GrContextFactory debugFactory(opts);
448     skiatest::RunWithGPUTestContexts(test_glprograms_native, &is_native_gl_context_type,
449                                      reporter, &debugFactory);
450     skiatest::RunWithGPUTestContexts(test_glprograms_other_contexts,
451                                      &is_other_rendering_gl_context_type, reporter, &debugFactory);
452 }
453 
454 #endif
455