blob: ae9be33bd0c4405128fee2d84d3f8cb13390ae63 [file] [log] [blame]
Ethan Nicholas00543112018-07-31 09:44:36 -04001/*
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 "GrCaps.h"
Ethan Nicholas222e2752018-10-11 11:21:34 -040012#include "GrContext.h"
13#include "GrContextPriv.h"
Ethan Nicholas00543112018-07-31 09:44:36 -040014#include "GrCoordTransform.h"
Ethan Nicholas222e2752018-10-11 11:21:34 -040015#include "GrFragmentProcessor.h"
Ethan Nicholas00543112018-07-31 09:44:36 -040016#include "GrShaderCaps.h"
17#include "SkSLCompiler.h"
18#include "SkSLPipelineStageCodeGenerator.h"
19#include "SkRefCnt.h"
Ethan Nicholas222e2752018-10-11 11:21:34 -040020#include "glsl/GrGLSLFragmentProcessor.h"
21#include "glsl/GrGLSLProgramDataManager.h"
22#include "glsl/GrGLSLUniformHandler.h"
Ethan Nicholas00543112018-07-31 09:44:36 -040023#include "../private/GrSkSLFPFactoryCache.h"
24
Ethan Nicholas78aceb22018-08-31 16:13:58 -040025#if GR_TEST_UTILS
26#define GR_FP_SRC_STRING const char*
27#else
28#define GR_FP_SRC_STRING static const char*
29#endif
30
Ethan Nicholas00543112018-07-31 09:44:36 -040031class GrContext;
32class GrSkSLFPFactory;
Ethan Nicholas222e2752018-10-11 11:21:34 -040033class GrGLSLSkSLFP;
Ethan Nicholas00543112018-07-31 09:44:36 -040034
35class GrSkSLFP : public GrFragmentProcessor {
36public:
Ethan Nicholas222e2752018-10-11 11:21:34 -040037 using UniformHandle = GrGLSLUniformHandler::UniformHandle;
38
39 template<typename Inputs, typename ExtraData>
40 using DataHookFn = void(const GrGLSLProgramDataManager& pdman, const GrGLSLSkSLFP& glslProc,
41 const Inputs& inputs, ExtraData* extraData);
42
Ethan Nicholas00543112018-07-31 09:44:36 -040043 /**
44 * Returns a new unique identifier. Each different SkSL fragment processor should call
45 * NewIndex once, statically, and use this index for all calls to Make.
46 */
47 static int NewIndex() {
48 static int index = 0;
49 return sk_atomic_inc(&index);
50 }
51
52 /**
53 * Creates a new fragment processor from an SkSL source string and a struct of inputs to the
54 * program. The input struct's type is derived from the 'in' variables in the SkSL source, so
55 * e.g. the shader:
56 *
57 * in bool dither;
58 * in float x;
59 * in float y;
60 * ....
61 *
62 * would expect a pointer to a struct set up like:
63 *
64 * struct {
65 * bool dither;
66 * float x;
67 * float y;
68 * };
69 *
70 * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ
71 * based on the inputs, internally the process is divided into two steps: we first parse and
72 * semantically analyze the SkSL into an internal representation, and then "specialize" this
73 * internal representation based on the inputs. The unspecialized internal representation of
74 * the program is cached, so further specializations of the same code are much faster than the
75 * first call.
76 *
77 * This caching is based on the 'index' parameter, which should be derived by statically calling
78 * 'NewIndex()'. Each given SkSL string should have a single, statically defined index
79 * associated with it.
80 */
Ethan Nicholas222e2752018-10-11 11:21:34 -040081 template<typename Inputs>
82 static std::unique_ptr<GrSkSLFP> Make(GrContext* context, int index, const char* name,
83 const char* sksl, const Inputs& inputs) {
84 void* resultBytes = GrSkSLFP::operator new(sizeof(GrSkSLFP) + sizeof(Inputs));
85 void* inputBytes = (int8_t*) resultBytes + sizeof(GrSkSLFP);
86 memcpy(inputBytes, &inputs, sizeof(Inputs));
87 GrSkSLFP* result = new (resultBytes) GrSkSLFP(context->contextPriv().getFPFactoryCache(),
88 context->contextPriv().caps()->shaderCaps(),
89 index, name, sksl, inputBytes,
90 sizeof(Inputs), nullptr, 0, nullptr);
91 return std::unique_ptr<GrSkSLFP>(result);
92 }
93
94 /**
95 * As the above overload of Make, but also tracks an additional extraData struct which is shared
96 * between all instances of the FP. The extraData struct is copied into the GrGLSLSkSLFP and is
97 * passed as an argument to the setDataHook function. setDataHook is called after the automatic
98 * handling of 'in uniform' variables is completed and is responsible for providing values for
99 * all non-'in' uniform variables.
100 */
101 template<typename Inputs, typename ExtraData>
102 static std::unique_ptr<GrSkSLFP> Make(GrContext* context, int index, const char* name,
103 const char* sksl, const Inputs& inputs,
104 const ExtraData& extraData,
105 DataHookFn<Inputs, ExtraData>* setDataHook) {
106 void* resultBytes = GrSkSLFP::operator new(sizeof(GrSkSLFP) + sizeof(Inputs) +
107 sizeof(ExtraData));
108 void* inputBytes = (int8_t*) resultBytes + sizeof(GrSkSLFP);
109 memcpy(inputBytes, &inputs, sizeof(Inputs));
110 void* extraDataBytes = (int8_t*) resultBytes + sizeof(GrSkSLFP) + sizeof(Inputs);
111 memcpy(extraDataBytes, &extraData, sizeof(ExtraData));
112 auto genericFn = [setDataHook] (const GrGLSLProgramDataManager& pdman,
113 const GrGLSLSkSLFP& glslProc,
114 const void* inputs,
115 void* extraData) {
116 (*setDataHook)(pdman, glslProc, *reinterpret_cast<const Inputs*>(inputs),
117 reinterpret_cast<ExtraData*>(extraData));
118 };
119 return std::unique_ptr<GrSkSLFP>(new (resultBytes) GrSkSLFP(
120 context->contextPriv().getFPFactoryCache(),
121 context->contextPriv().caps()->shaderCaps(),
122 index, name, sksl, inputBytes,
123 sizeof(Inputs), extraDataBytes,
124 sizeof(ExtraData), genericFn));
125 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400126
127 const char* name() const override;
128
Ethan Nicholasce008112018-08-30 09:19:50 -0400129 void addChild(std::unique_ptr<GrFragmentProcessor> child);
130
Ethan Nicholas222e2752018-10-11 11:21:34 -0400131 void setSetDataHook(void (*hook)(const GrGLSLProgramDataManager& pdman,
132 const GrGLSLSkSLFP& glslProc,
133 const GrSkSLFP& proc));
134
135 const void* inputs() const { return fInputs; }
136
Ethan Nicholas00543112018-07-31 09:44:36 -0400137 std::unique_ptr<GrFragmentProcessor> clone() const override;
138
139private:
Ethan Nicholas222e2752018-10-11 11:21:34 -0400140 using UntypedDataHookFn = std::function<void(const GrGLSLProgramDataManager&,
141 const GrGLSLSkSLFP&,
142 const void*,
143 void*)>;
Ethan Nicholas00543112018-07-31 09:44:36 -0400144 GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, int fIndex,
Ethan Nicholas222e2752018-10-11 11:21:34 -0400145 const char* name, const char* sksl, const void* inputs, size_t inputSize,
146 const void* extraData, size_t extraDataSize, UntypedDataHookFn setDataHook);
Ethan Nicholas00543112018-07-31 09:44:36 -0400147
148 GrSkSLFP(const GrSkSLFP& other);
149
150 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
151
152 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
153
154 bool onIsEqual(const GrFragmentProcessor&) const override;
155
156 void createFactory() const;
157
158 sk_sp<GrSkSLFPFactoryCache> fFactoryCache;
159
160 const sk_sp<GrShaderCaps> fShaderCaps;
161
162 mutable sk_sp<GrSkSLFPFactory> fFactory;
163
164 int fIndex;
165
166 const char* fName;
167
168 const char* fSkSL;
169
Ethan Nicholas222e2752018-10-11 11:21:34 -0400170 const void* fInputs;
Ethan Nicholas00543112018-07-31 09:44:36 -0400171
172 size_t fInputSize;
173
Ethan Nicholas222e2752018-10-11 11:21:34 -0400174 const void* fExtraData;
175
176 size_t fExtraDataSize;
177
178 UntypedDataHookFn fSetDataHook;
179
Ethan Nicholas00543112018-07-31 09:44:36 -0400180 mutable SkSL::String fKey;
181
182 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
183
184 typedef GrFragmentProcessor INHERITED;
185
Ethan Nicholasce008112018-08-30 09:19:50 -0400186 friend class GrGLSLSkSLFP;
187
Ethan Nicholas00543112018-07-31 09:44:36 -0400188 friend class GrSkSLFPFactory;
189};
190
Ethan Nicholas222e2752018-10-11 11:21:34 -0400191class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
192public:
193 GrGLSLSkSLFP(SkSL::Context* context, const std::vector<const SkSL::Variable*>* uniformVars,
194 SkSL::String glsl, std::vector<SkSL::Compiler::FormatArg> formatArgs,
195 void* extraData);
196
197 GrSLType uniformType(const SkSL::Type& type);
198
199 /**
200 * Returns the extraData pointer.
201 */
202 void* extraData() const;
203
204 void emitCode(EmitArgs& args) override;
205
206 void onSetData(const GrGLSLProgramDataManager& pdman,
207 const GrFragmentProcessor& _proc) override;
208
209 UniformHandle uniformHandle(int index) const { return fUniformHandles[index]; }
210
211private:
212 const SkSL::Context& fContext;
213
214 const std::vector<const SkSL::Variable*>& fUniformVars;
215
216 // nearly-finished GLSL; still contains printf-style "%s" format tokens
217 const SkSL::String fGLSL;
218
219 std::vector<SkSL::Compiler::FormatArg> fFormatArgs;
220
221 std::vector<UniformHandle> fUniformHandles;
222
223 void* fExtraData;
224};
225
Ethan Nicholas00543112018-07-31 09:44:36 -0400226/**
227 * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
228 * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
229 * string, then use that to create the actual GrFragmentProcessor.
230 */
231class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> {
232public:
233 /**
234 * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will
235 * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause
236 * the produced shaders to differ), so it is important to reuse the same factory instance for
237 * the same shader in order to avoid repeatedly re-parsing the SkSL.
238 */
239 GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl);
240
241 const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs,
242 size_t inputSize);
243
244 const char* fName;
245
246 SkSL::Compiler fCompiler;
247
248 std::shared_ptr<SkSL::Program> fBaseProgram;
249
250 std::vector<const SkSL::Variable*> fInputVars;
251
Ethan Nicholas222e2752018-10-11 11:21:34 -0400252 std::vector<const SkSL::Variable*> fUniformVars;
253
Ethan Nicholas00543112018-07-31 09:44:36 -0400254 std::vector<const SkSL::Variable*> fKeyVars;
255
256 std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
257
258 friend class GrSkSLFP;
259};
260
261#endif