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 "src/gpu/GrCaps.h" 13 #include "src/gpu/GrCoordTransform.h" 14 #include "src/gpu/GrFragmentProcessor.h" 15 #include "src/gpu/GrShaderCaps.h" 16 #include "src/gpu/GrSkSLFPFactoryCache.h" 17 #include "src/sksl/SkSLCompiler.h" 18 #include "src/sksl/SkSLPipelineStageCodeGenerator.h" 19 #include <atomic> 20 21 #if GR_TEST_UTILS 22 #define GR_FP_SRC_STRING const char* 23 #else 24 #define GR_FP_SRC_STRING static const char* 25 #endif 26 27 class GrContext_Base; 28 class GrSkSLFPFactory; 29 30 class GrSkSLFP : public GrFragmentProcessor { 31 public: 32 /** 33 * Returns a new unique identifier. Each different SkSL fragment processor should call 34 * NewIndex once, statically, and use this index for all calls to Make. 35 */ NewIndex()36 static int NewIndex() { 37 static std::atomic<int> nextIndex{0}; 38 return nextIndex++; 39 } 40 41 /** 42 * Creates a new fragment processor from an SkSL source string and a struct of inputs to the 43 * program. The input struct's type is derived from the 'in' and 'uniform' variables in the SkSL 44 * source, so e.g. the shader: 45 * 46 * in bool dither; 47 * uniform float x; 48 * uniform float y; 49 * .... 50 * 51 * would expect a pointer to a struct set up like: 52 * 53 * struct { 54 * bool dither; 55 * float x; 56 * float y; 57 * }; 58 * 59 * While both 'in' and 'uniform' variables go into this struct, the difference between them is 60 * that 'in' variables are statically "baked in" to the generated code, becoming literals, 61 * whereas uniform variables may be changed from invocation to invocation without having to 62 * recompile the shader. 63 * 64 * As the decision of whether to create a new shader or just upload new uniforms all happens 65 * behind the scenes, the difference between the two from an end-user perspective is primarily 66 * in performance: on the one hand, changing the value of an 'in' variable is very expensive 67 * (requiring the compiler to regenerate the code, upload a new shader to the GPU, and so 68 * forth), but on the other hand the compiler can optimize around its value because it is known 69 * at compile time. 'in' variables are therefore suitable for things like flags, where there are 70 * only a few possible values and a known-in-advance value can cause entire chunks of code to 71 * become dead (think static @ifs), while 'uniform's are used for continuous values like colors 72 * and coordinates, where it would be silly to create a separate shader for each possible set of 73 * values. Other than the (significant) performance implications, the only difference between 74 * the two is that 'in' variables can be used in static @if / @switch tests. When in doubt, use 75 * 'uniform'. 76 * 77 * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ 78 * based on the inputs, internally the process is divided into two steps: we first parse and 79 * semantically analyze the SkSL into an internal representation, and then "specialize" this 80 * internal representation based on the inputs. The unspecialized internal representation of 81 * the program is cached, so further specializations of the same code are much faster than the 82 * first call. 83 * 84 * This caching is based on the 'index' parameter, which should be derived by statically calling 85 * 'NewIndex()'. Each given SkSL string should have a single, statically defined index 86 * associated with it. 87 */ 88 static std::unique_ptr<GrSkSLFP> Make( 89 GrContext_Base* context, 90 int index, 91 const char* name, 92 const char* sksl, 93 const void* inputs, 94 size_t inputSize, 95 SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind, 96 const SkMatrix* matrix = nullptr); 97 98 static std::unique_ptr<GrSkSLFP> Make( 99 GrContext_Base* context, 100 int index, 101 const char* name, 102 SkString sksl, 103 const void* inputs, 104 size_t inputSize, 105 SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind, 106 const SkMatrix* matrix = nullptr); 107 108 const char* name() const override; 109 110 void addChild(std::unique_ptr<GrFragmentProcessor> child); 111 112 std::unique_ptr<GrFragmentProcessor> clone() const override; 113 114 private: 115 GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, 116 SkSL::Program::Kind kind, int fIndex, const char* name, const char* sksl, 117 SkString skslString, const void* inputs, size_t inputSize, const SkMatrix* matrix); 118 119 GrSkSLFP(const GrSkSLFP& other); 120 121 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 122 123 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 124 125 bool onIsEqual(const GrFragmentProcessor&) const override; 126 127 void createFactory() const; 128 129 sk_sp<GrSkSLFPFactoryCache> fFactoryCache; 130 131 const sk_sp<GrShaderCaps> fShaderCaps; 132 133 mutable sk_sp<GrSkSLFPFactory> fFactory; 134 135 SkSL::Program::Kind fKind; 136 137 int fIndex; 138 139 const char* fName; 140 141 // For object lifetime purposes, we have fields for the SkSL as both a const char* and a 142 // SkString. The const char* is the one we actually use, but it may point to the SkString's 143 // bytes. Since GrSkSLFPs are frequently created from constant strings, this allows us to 144 // generally avoid the overhead of copying the bytes into an SkString (in which case fSkSLString 145 // is the empty string), while still allowing the GrSkSLFP to manage the string's lifetime when 146 // needed. 147 SkString fSkSLString; 148 149 const char* fSkSL; 150 151 const std::unique_ptr<int8_t[]> fInputs; 152 153 size_t fInputSize; 154 155 GrCoordTransform fCoordTransform; 156 157 mutable SkSL::String fKey; 158 159 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 160 161 typedef GrFragmentProcessor INHERITED; 162 163 friend class GrGLSLSkSLFP; 164 165 friend class GrSkSLFPFactory; 166 }; 167 168 /** 169 * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends 170 * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL 171 * string, then use that to create the actual GrFragmentProcessor. 172 */ 173 class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> { 174 public: 175 /** 176 * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will 177 * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause 178 * the produced shaders to differ), so it is important to reuse the same factory instance for 179 * the same shader in order to avoid repeatedly re-parsing the SkSL. 180 */ 181 GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl, 182 SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind); 183 184 const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs, 185 size_t inputSize); 186 187 SkSL::Program::Kind fKind; 188 189 const char* fName; 190 191 SkSL::Compiler fCompiler; 192 193 std::shared_ptr<SkSL::Program> fBaseProgram; 194 195 std::vector<const SkSL::Variable*> fInAndUniformVars; 196 197 std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations; 198 199 friend class GrSkSLFP; 200 }; 201 202 #endif 203