1/*
2 * Copyright 2018 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#ifndef GrSkSLFP_DEFINED
9#define GrSkSLFP_DEFINED
10
11#include "include/core/SkRefCnt.h"
12#include "include/gpu/GrContextOptions.h"
13#include "src/gpu/GrCaps.h"
14#include "src/gpu/GrCoordTransform.h"
15#include "src/gpu/GrFragmentProcessor.h"
16#include "src/sksl/SkSLCompiler.h"
17#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
18#include <atomic>
19
20#if GR_TEST_UTILS
21#define GR_FP_SRC_STRING const char*
22#else
23#define GR_FP_SRC_STRING static const char*
24#endif
25
26class GrContext_Base;
27class GrShaderCaps;
28class SkData;
29class SkRuntimeEffect;
30
31class GrSkSLFP : public GrFragmentProcessor {
32public:
33 /**
34 * Creates a new fragment processor from an SkRuntimeEffect and a struct of inputs to the
35 * program. The input struct's type is derived from the 'in' and 'uniform' variables in the SkSL
36 * source, so e.g. the shader:
37 *
38 * in bool dither;
39 * uniform float x;
40 * uniform float y;
41 * ....
42 *
43 * would expect a pointer to a struct set up like:
44 *
45 * struct {
46 * bool dither;
47 * float x;
48 * float y;
49 * };
50 *
51 * While both 'in' and 'uniform' variables go into this struct, the difference between them is
52 * that 'in' variables are statically "baked in" to the generated code, becoming literals,
53 * whereas uniform variables may be changed from invocation to invocation without having to
54 * recompile the shader.
55 *
56 * As the decision of whether to create a new shader or just upload new uniforms all happens
57 * behind the scenes, the difference between the two from an end-user perspective is primarily
58 * in performance: on the one hand, changing the value of an 'in' variable is very expensive
59 * (requiring the compiler to regenerate the code, upload a new shader to the GPU, and so
60 * forth), but on the other hand the compiler can optimize around its value because it is known
61 * at compile time. 'in' variables are therefore suitable for things like flags, where there are
62 * only a few possible values and a known-in-advance value can cause entire chunks of code to
63 * become dead (think static @ifs), while 'uniform's are used for continuous values like colors
64 * and coordinates, where it would be silly to create a separate shader for each possible set of
65 * values. Other than the (significant) performance implications, the only difference between
66 * the two is that 'in' variables can be used in static @if / @switch tests. When in doubt, use
67 * 'uniform'.
68 */
69 static std::unique_ptr<GrSkSLFP> Make(GrContext_Base* context,
70 sk_sp<SkRuntimeEffect> effect,
71 const char* name,
72 sk_sp<SkData> inputs,
73 const SkMatrix* matrix = nullptr);
74
75 const char* name() const override;
76
77 void addChild(std::unique_ptr<GrFragmentProcessor> child);
78
79 std::unique_ptr<GrFragmentProcessor> clone() const override;
80
81private:
82 using ShaderErrorHandler = GrContextOptions::ShaderErrorHandler;
83
84 GrSkSLFP(sk_sp<const GrShaderCaps> shaderCaps, ShaderErrorHandler* shaderErrorHandler,
85 sk_sp<SkRuntimeEffect> effect, const char* name, sk_sp<SkData> inputs,
86 const SkMatrix* matrix);
87
88 GrSkSLFP(const GrSkSLFP& other);
89
90 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
91
92 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
93
94 bool onIsEqual(const GrFragmentProcessor&) const override;
95
96 sk_sp<const GrShaderCaps> fShaderCaps;
97 ShaderErrorHandler* fShaderErrorHandler;
98
99 sk_sp<SkRuntimeEffect> fEffect;
100 const char* fName;
101 sk_sp<SkData> fInputs;
102
103 GrCoordTransform fCoordTransform;
104
105 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
106
107 typedef GrFragmentProcessor INHERITED;
108
109 friend class GrGLSLSkSLFP;
110
111 friend class GrSkSLFPFactory;
112};
113
114#endif
115