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