GLProgramsTest.cpp revision a13e202563979fd5076936606dcc1d660da8c632
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9// This is a GPU-backend specific test. It relies on static intializers to work
10
11#include "SkTypes.h"
12
13#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
14
15#include "GrAutoLocaleSetter.h"
16#include "GrBatchTest.h"
17#include "GrContextFactory.h"
18#include "GrDrawingManager.h"
19#include "GrInvariantOutput.h"
20#include "GrPipeline.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 "batches/GrDrawBatch.h"
29
30#include "effects/GrConfigConversionEffect.h"
31#include "effects/GrPorterDuffXferProcessor.h"
32#include "effects/GrXfermodeFragmentProcessor.h"
33
34#include "gl/GrGLFragmentProcessor.h"
35#include "gl/GrGLGpu.h"
36#include "gl/GrGLPathRendering.h"
37#include "gl/builders/GrGLProgramBuilder.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 */
43static const uint32_t kMaxKeySize = 1024;
44
45class GLBigKeyProcessor : public GrGLFragmentProcessor {
46public:
47    GLBigKeyProcessor(const GrProcessor&) {}
48
49    virtual void emitCode(EmitArgs& args) override {
50        // pass through
51        GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
52        if (args.fInputColor) {
53            fsBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor);
54        } else {
55            fsBuilder->codeAppendf("%s = vec4(1.0);\n", args.fOutputColor);
56        }
57    }
58
59    static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
60        for (uint32_t i = 0; i < kMaxKeySize; i++) {
61            b->add32(i);
62        }
63    }
64
65private:
66    typedef GrGLFragmentProcessor INHERITED;
67};
68
69class BigKeyProcessor : public GrFragmentProcessor {
70public:
71    static GrFragmentProcessor* Create() {
72        return new BigKeyProcessor;
73    }
74
75    const char* name() const override { return "Big Ole Key"; }
76
77    GrGLFragmentProcessor* onCreateGLInstance() const override {
78        return new GLBigKeyProcessor(*this);
79    }
80
81private:
82    BigKeyProcessor() {
83        this->initClassID<BigKeyProcessor>();
84    }
85    virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
86                                     GrProcessorKeyBuilder* b) const override {
87        GLBigKeyProcessor::GenKey(*this, caps, b);
88    }
89    bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
90    void onComputeInvariantOutput(GrInvariantOutput* inout) const override { }
91
92    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
93
94    typedef GrFragmentProcessor INHERITED;
95};
96
97GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
98
99const GrFragmentProcessor* BigKeyProcessor::TestCreate(GrProcessorTestData*) {
100    return BigKeyProcessor::Create();
101}
102
103//////////////////////////////////////////////////////////////////////////////
104
105class BlockInputFragmentProcessor : public GrFragmentProcessor {
106public:
107    static GrFragmentProcessor* Create(const GrFragmentProcessor* fp) {
108        return new BlockInputFragmentProcessor(fp);
109    }
110
111    const char* name() const override { return "Block Input"; }
112
113    GrGLFragmentProcessor* onCreateGLInstance() const override { return new GLFP; }
114
115private:
116    class GLFP : public GrGLFragmentProcessor {
117    public:
118        void emitCode(EmitArgs& args) override {
119            this->emitChild(0, nullptr, args);
120        }
121
122    private:
123        typedef GrGLFragmentProcessor INHERITED;
124    };
125
126    BlockInputFragmentProcessor(const GrFragmentProcessor* child) {
127        this->initClassID<BlockInputFragmentProcessor>();
128        this->registerChildProcessor(child);
129    }
130
131    void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {}
132
133    bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
134
135    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
136        inout->setToOther(kRGBA_GrColorComponentFlags, GrColor_WHITE,
137                          GrInvariantOutput::kWillNot_ReadInput);
138        this->childProcessor(0).computeInvariantOutput(inout);
139    }
140
141    typedef GrFragmentProcessor INHERITED;
142};
143
144//////////////////////////////////////////////////////////////////////////////
145
146/*
147 * Begin test code
148 */
149static const int kRenderTargetHeight = 1;
150static const int kRenderTargetWidth = 1;
151
152static GrRenderTarget* random_render_target(GrTextureProvider* textureProvider, SkRandom* random,
153                                            const GrCaps* caps) {
154    // setup render target
155    GrTextureParams params;
156    GrSurfaceDesc texDesc;
157    texDesc.fWidth = kRenderTargetWidth;
158    texDesc.fHeight = kRenderTargetHeight;
159    texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
160    texDesc.fConfig = kRGBA_8888_GrPixelConfig;
161    texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
162                                                   kBottomLeft_GrSurfaceOrigin;
163    texDesc.fSampleCnt = random->nextBool() == true ? SkTMin(4, caps->maxSampleCount()) : 0;
164
165    GrUniqueKey key;
166    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
167    GrUniqueKey::Builder builder(&key, kDomain, 2);
168    builder[0] = texDesc.fOrigin;
169    builder[1] = texDesc.fSampleCnt;
170    builder.finish();
171
172    GrTexture* texture = textureProvider->findAndRefTextureByUniqueKey(key);
173    if (!texture) {
174        texture = textureProvider->createTexture(texDesc, true);
175        if (texture) {
176            textureProvider->assignUniqueKeyToTexture(key, texture);
177        }
178    }
179    return texture ? texture->asRenderTarget() : nullptr;
180}
181
182static void set_random_xpf(GrPipelineBuilder* pipelineBuilder, GrProcessorTestData* d) {
183    SkAutoTUnref<const GrXPFactory> xpf(GrProcessorTestFactory<GrXPFactory>::Create(d));
184    SkASSERT(xpf);
185    pipelineBuilder->setXPFactory(xpf.get());
186}
187
188static const GrFragmentProcessor* create_random_proc_tree(GrProcessorTestData* d,
189                                                           int minLevels, int maxLevels) {
190    SkASSERT(1 <= minLevels);
191    SkASSERT(minLevels <= maxLevels);
192
193    // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
194    // If returning a leaf node, make sure that it doesn't have children (e.g. another
195    // GrComposeEffect)
196    const float terminateProbability = 0.3f;
197    if (1 == minLevels) {
198        bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
199        if (terminate) {
200            const GrFragmentProcessor* fp;
201            while (true) {
202                fp = GrProcessorTestFactory<GrFragmentProcessor>::Create(d);
203                SkASSERT(fp);
204                if (0 == fp->numChildProcessors()) {
205                    break;
206                }
207                fp->unref();
208            }
209            return fp;
210        }
211    }
212    // If we didn't terminate, choose either the left or right subtree to fulfill
213    // the minLevels requirement of this tree; the other child can have as few levels as it wants.
214    // Also choose a random xfer mode that's supported by CreateFrom2Procs().
215    if (minLevels > 1) {
216        --minLevels;
217    }
218    SkAutoTUnref<const GrFragmentProcessor> minLevelsChild(create_random_proc_tree(d, minLevels,
219                                                                                   maxLevels - 1));
220    SkAutoTUnref<const GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1,
221                                                                               maxLevels - 1));
222    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(d->fRandom->nextRangeU(0,
223                                                          SkXfermode::kLastCoeffMode));
224    const GrFragmentProcessor* fp;
225    if (d->fRandom->nextF() < 0.5f) {
226        fp = GrXfermodeFragmentProcessor::CreateFromTwoProcessors(minLevelsChild, otherChild, mode);
227        SkASSERT(fp);
228    } else {
229        fp = GrXfermodeFragmentProcessor::CreateFromTwoProcessors(otherChild, minLevelsChild, mode);
230        SkASSERT(fp);
231    }
232    return fp;
233}
234
235static void set_random_color_coverage_stages(GrPipelineBuilder* pipelineBuilder,
236                                             GrProcessorTestData* d, int maxStages) {
237    // Randomly choose to either create a linear pipeline of procs or create one proc tree
238    const float procTreeProbability = 0.5f;
239    if (d->fRandom->nextF() < procTreeProbability) {
240        // A full tree with 5 levels (31 nodes) may exceed the max allowed length of the gl
241        // processor key; maxTreeLevels should be a number from 1 to 4 inclusive.
242        const int maxTreeLevels = 4;
243        SkAutoTUnref<const GrFragmentProcessor> fp(
244                                        create_random_proc_tree(d, 2, maxTreeLevels));
245        pipelineBuilder->addColorFragmentProcessor(fp);
246    } else {
247        int numProcs = d->fRandom->nextULessThan(maxStages + 1);
248        int numColorProcs = d->fRandom->nextULessThan(numProcs + 1);
249
250        for (int s = 0; s < numProcs;) {
251            SkAutoTUnref<const GrFragmentProcessor> fp(
252                GrProcessorTestFactory<GrFragmentProcessor>::Create(d));
253            SkASSERT(fp);
254
255            // finally add the stage to the correct pipeline in the drawstate
256            if (s < numColorProcs) {
257                pipelineBuilder->addColorFragmentProcessor(fp);
258            } else {
259                pipelineBuilder->addCoverageFragmentProcessor(fp);
260            }
261            ++s;
262        }
263    }
264}
265
266static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
267    int state = 0;
268    for (int i = 1; i <= GrPipelineBuilder::kLast_Flag; i <<= 1) {
269        state |= random->nextBool() * i;
270    }
271
272    // If we don't have an MSAA rendertarget then we have to disable useHWAA
273    if ((state | GrPipelineBuilder::kHWAntialias_Flag) &&
274        !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled()) {
275        state &= ~GrPipelineBuilder::kHWAntialias_Flag;
276    }
277    pipelineBuilder->enableState(state);
278}
279
280// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
281static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
282    GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
283                                 kReplace_StencilOp,
284                                 kReplace_StencilOp,
285                                 kAlways_StencilFunc,
286                                 0xffff,
287                                 0xffff,
288                                 0xffff);
289    GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
290                                 kKeep_StencilOp,
291                                 kKeep_StencilOp,
292                                 kNever_StencilFunc,
293                                 0xffff,
294                                 0xffff,
295                                 0xffff);
296
297    if (random->nextBool()) {
298        pipelineBuilder->setStencil(kDoesWriteStencil);
299    } else {
300        pipelineBuilder->setStencil(kDoesNotWriteStencil);
301    }
302}
303
304bool GrDrawingManager::ProgramUnitTest(GrContext* context, GrDrawTarget* drawTarget, int maxStages) {
305
306    GrDrawingManager* drawingManager = context->drawingManager();
307
308    // setup dummy textures
309    GrSurfaceDesc dummyDesc;
310    dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
311    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
312    dummyDesc.fWidth = 34;
313    dummyDesc.fHeight = 18;
314    SkAutoTUnref<GrTexture> dummyTexture1(
315        context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0));
316    dummyDesc.fFlags = kNone_GrSurfaceFlags;
317    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
318    dummyDesc.fWidth = 16;
319    dummyDesc.fHeight = 22;
320    SkAutoTUnref<GrTexture> dummyTexture2(
321        context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0));
322
323    if (!dummyTexture1 || ! dummyTexture2) {
324        SkDebugf("Could not allocate dummy textures");
325        return false;
326    }
327
328    GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
329
330    // dummy scissor state
331    GrScissorState scissor;
332
333    // wide open clip
334    GrClip clip;
335
336    SkRandom random;
337    static const int NUM_TESTS = 2048;
338    for (int t = 0; t < NUM_TESTS; t++) {
339        // setup random render target(can fail)
340        SkAutoTUnref<GrRenderTarget> rt(random_render_target(
341            context->textureProvider(), &random, context->caps()));
342        if (!rt.get()) {
343            SkDebugf("Could not allocate render target");
344            return false;
345        }
346
347        GrPipelineBuilder pipelineBuilder;
348        pipelineBuilder.setRenderTarget(rt.get());
349        pipelineBuilder.setClip(clip);
350
351        SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
352        SkASSERT(batch);
353
354        GrProcessorTestData ptd(&random, context, context->caps(), dummyTextures);
355        set_random_color_coverage_stages(&pipelineBuilder, &ptd, maxStages);
356        set_random_xpf(&pipelineBuilder, &ptd);
357        set_random_state(&pipelineBuilder, &random);
358        set_random_stencil(&pipelineBuilder, &random);
359
360        drawTarget->drawBatch(pipelineBuilder, batch);
361    }
362    // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
363    drawingManager->flush();
364
365    // Validate that GrFPs work correctly without an input.
366    GrSurfaceDesc rtDesc;
367    rtDesc.fWidth = kRenderTargetWidth;
368    rtDesc.fHeight = kRenderTargetHeight;
369    rtDesc.fFlags = kRenderTarget_GrSurfaceFlag;
370    rtDesc.fConfig = kRGBA_8888_GrPixelConfig;
371    SkAutoTUnref<GrRenderTarget> rt(
372        context->textureProvider()->createTexture(rtDesc, false)->asRenderTarget());
373    int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count();
374    for (int i = 0; i < fpFactoryCnt; ++i) {
375        // Since FP factories internally randomize, call each 10 times.
376        for (int j = 0; j < 10; ++j) {
377            SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
378            SkASSERT(batch);
379            GrProcessorTestData ptd(&random, context, context->caps(), dummyTextures);
380            GrPipelineBuilder builder;
381            builder.setXPFactory(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
382            builder.setRenderTarget(rt);
383            builder.setClip(clip);
384
385            SkAutoTUnref<const GrFragmentProcessor> fp(
386                GrProcessorTestFactory<GrFragmentProcessor>::CreateIdx(i, &ptd));
387            SkAutoTUnref<const GrFragmentProcessor> blockFP(
388                BlockInputFragmentProcessor::Create(fp));
389            builder.addColorFragmentProcessor(blockFP);
390
391            drawTarget->drawBatch(builder, batch);
392            drawingManager->flush();
393        }
394    }
395
396    return true;
397}
398
399DEF_GPUTEST(GLPrograms, reporter, factory) {
400    // Set a locale that would cause shader compilation to fail because of , as decimal separator.
401    // skbug 3330
402#ifdef SK_BUILD_FOR_WIN
403    GrAutoLocaleSetter als("sv-SE");
404#else
405    GrAutoLocaleSetter als("sv_SE.UTF-8");
406#endif
407
408    // We suppress prints to avoid spew
409    GrContextOptions opts;
410    opts.fSuppressPrints = true;
411    GrContextFactory debugFactory(opts);
412    for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
413        GrContext* context = debugFactory.get(static_cast<GrContextFactory::GLContextType>(type));
414        if (context) {
415            GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
416
417            /*
418             * For the time being, we only support the test with desktop GL or for android on
419             * ARM platforms
420             * TODO When we run ES 3.00 GLSL in more places, test again
421             */
422            int maxStages;
423            if (kGL_GrGLStandard == gpu->glStandard() ||
424                kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
425                maxStages = 6;
426            } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
427                       kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
428                maxStages = 1;
429            } else {
430                return;
431            }
432#if SK_ANGLE
433            // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
434            if (type == GrContextFactory::kANGLE_GLContextType) {
435                maxStages = 2;
436            }
437#endif
438#if SK_COMMAND_BUFFER
439            // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
440            // TODO(hendrikw): This only needs to happen with the ANGLE comand buffer backend.
441            if (type == GrContextFactory::kCommandBuffer_GLContextType) {
442                maxStages = 2;
443            }
444#endif
445            GrTestTarget testTarget;
446            context->getTestTarget(&testTarget);
447            REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(
448                                            context, testTarget.target(), maxStages));
449        }
450    }
451}
452
453#endif
454