xref: /third_party/skia/tests/ProgramsTest.cpp (revision cb93a386)
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 */
40static const uint32_t kMaxKeySize = 1024;
41
42namespace {
43class BigKeyProcessor : public GrFragmentProcessor {
44public:
45    static std::unique_ptr<GrFragmentProcessor> Make() {
46        return std::unique_ptr<GrFragmentProcessor>(new BigKeyProcessor);
47    }
48
49    const char* name() const override { return "Big_Ole_Key"; }
50
51    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
62    std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
63
64private:
65    BigKeyProcessor() : INHERITED(kBigKeyProcessor_ClassID, kNone_OptimizationFlags) {}
66    void onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
67        for (uint32_t i = 0; i < kMaxKeySize; i++) {
68            b->add32(i);
69        }
70    }
71    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
79GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
80
81#if GR_TEST_UTILS
82std::unique_ptr<GrFragmentProcessor> BigKeyProcessor::TestCreate(GrProcessorTestData*) {
83    return BigKeyProcessor::Make();
84}
85#endif
86
87//////////////////////////////////////////////////////////////////////////////
88
89class BlockInputFragmentProcessor : public GrFragmentProcessor {
90public:
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
95    const char* name() const override { return "Block_Input"; }
96
97    std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
98        return std::make_unique<GLFP>();
99    }
100
101    std::unique_ptr<GrFragmentProcessor> clone() const override {
102        return Make(this->childProcessor(0)->clone());
103    }
104
105private:
106    class GLFP : public ProgramImpl {
107    public:
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
117    BlockInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child)
118            : INHERITED(kBlockInputFragmentProcessor_ClassID, kNone_OptimizationFlags) {
119        this->registerChild(std::move(child));
120    }
121
122    void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
123
124    bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
125
126    using INHERITED = GrFragmentProcessor;
127};
128
129//////////////////////////////////////////////////////////////////////////////
130
131/*
132 * Begin test code
133 */
134static const int kRenderTargetHeight = 1;
135static const int kRenderTargetWidth = 1;
136
137static 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
158static void set_random_xpf(GrPaint* paint, GrProcessorTestData* d) {
159    paint->setXPFactory(GrXPFactoryTestFactory::Get(d));
160}
161
162static 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
211static 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
239bool GrDrawingManager::ProgramUnitTest(GrDirectContext*, int) { return true; }
240#else
241bool 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
329static 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
362static 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
388static 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
402DEF_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