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#include "src/gpu/effects/GrSkSLFP.h"
9
10#include "include/effects/SkRuntimeEffect.h"
11#include "include/private/GrContext_Base.h"
12#include "src/gpu/GrBaseContextPriv.h"
13#include "src/gpu/GrColorInfo.h"
14#include "src/gpu/GrTexture.h"
15#include "src/sksl/SkSLUtil.h"
16
17#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
18#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
19#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
20
21class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
22public:
23 GrGLSLSkSLFP(SkSL::PipelineStageArgs&& args) : fArgs(std::move(args)) {}
24
25 SkSL::String expandFormatArgs(const SkSL::String& raw,
26 EmitArgs& args,
27 std::vector<SkSL::Compiler::FormatArg>::const_iterator& fmtArg) {
28 SkSL::String result;
29 int substringStartIndex = 0;
30 for (size_t i = 0; i < raw.length(); ++i) {
31 char c = raw[i];
32 if (c == SkSL::Compiler::kFormatArgPlaceholder) {
33 result += SkSL::StringFragment(raw.c_str() + substringStartIndex,
34 i - substringStartIndex);
35 const SkSL::Compiler::FormatArg& arg = *fmtArg++;
36 switch (arg.fKind) {
37 case SkSL::Compiler::FormatArg::Kind::kInput:
38 result += args.fInputColor;
39 break;
40 case SkSL::Compiler::FormatArg::Kind::kOutput:
41 result += args.fOutputColor;
42 break;
43 case SkSL::Compiler::FormatArg::Kind::kCoords:
44 result += args.fSampleCoord;
45 break;
46 case SkSL::Compiler::FormatArg::Kind::kUniform:
47 result += args.fUniformHandler->getUniformCStr(fUniformHandles[arg.fIndex]);
48 break;
49 case SkSL::Compiler::FormatArg::Kind::kChildProcessor: {
50 SkSL::String coords = this->expandFormatArgs(arg.fCoords, args, fmtArg);
51 result += this->invokeChild(arg.fIndex, args, coords).c_str();
52 break;
53 }
54 case SkSL::Compiler::FormatArg::Kind::kChildProcessorWithMatrix: {
55 const auto& fp(args.fFp.cast<GrSkSLFP>());
56 const auto& sampleUsages(fp.fEffect->fSampleUsages);
57
58 SkASSERT((size_t)arg.fIndex < sampleUsages.size());
59 const SkSL::SampleUsage& sampleUsage(sampleUsages[arg.fIndex]);
60
61 SkSL::String coords = this->expandFormatArgs(arg.fCoords, args, fmtArg);
62 result += this->invokeChildWithMatrix(
63 arg.fIndex, args,
64 sampleUsage.hasUniformMatrix() ? "" : coords)
65 .c_str();
66 break;
67 }
68 case SkSL::Compiler::FormatArg::Kind::kFunctionName:
69 SkASSERT((int) fFunctionNames.size() > arg.fIndex);
70 result += fFunctionNames[arg.fIndex].c_str();
71 break;
72 }
73 substringStartIndex = i + 1;
74 }
75 }
76 result += SkSL::StringFragment(raw.c_str() + substringStartIndex,
77 raw.length() - substringStartIndex);
78 return result;
79 }
80
81 void emitCode(EmitArgs& args) override {
82 const GrSkSLFP& fp = args.fFp.cast<GrSkSLFP>();
83 for (const auto& v : fp.fEffect->uniforms()) {
84 auto handle = args.fUniformHandler->addUniformArray(&fp,
85 kFragment_GrShaderFlag,
86 v.fGPUType,
87 v.fName.c_str(),
88 v.isArray() ? v.fCount : 0);
89 fUniformHandles.push_back(handle);
90 }
91 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
92 std::vector<SkString> childNames;
93 // We need to ensure that we emit each child's helper function at least once.
94 // Any child FP that isn't sampled won't trigger a call otherwise, leading to asserts later.
95 for (int i = 0; i < this->numChildProcessors(); ++i) {
96 if (this->childProcessor(i)) {
97 this->emitChildFunction(i, args);
98 }
99 }
100 for (const auto& f : fArgs.fFunctions) {
101 fFunctionNames.emplace_back();
102 auto fmtArgIter = f.fFormatArgs.cbegin();
103 SkSL::String body = this->expandFormatArgs(f.fBody, args, fmtArgIter);
104 SkASSERT(fmtArgIter == f.fFormatArgs.cend());
105 fragBuilder->emitFunction(f.fReturnType,
106 f.fName.c_str(),
107 f.fParameters.size(),
108 f.fParameters.data(),
109 body.c_str(),
110 &fFunctionNames.back());
111 }
112 fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor);
113 auto fmtArgIter = fArgs.fFormatArgs.cbegin();
114 fragBuilder->codeAppend(this->expandFormatArgs(fArgs.fCode, args, fmtArgIter).c_str());
115 SkASSERT(fmtArgIter == fArgs.fFormatArgs.cend());
116 }
117
118 void onSetData(const GrGLSLProgramDataManager& pdman,
119 const GrFragmentProcessor& _proc) override {
120 size_t uniIndex = 0;
121 const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
122 const uint8_t* uniformData = outer.fUniforms->bytes();
123 for (const auto& v : outer.fEffect->uniforms()) {
124 const float* data = reinterpret_cast<const float*>(uniformData + v.fOffset);
125 switch (v.fType) {
126 case SkRuntimeEffect::Uniform::Type::kFloat:
127 pdman.set1fv(fUniformHandles[uniIndex++], v.fCount, data);
128 break;
129 case SkRuntimeEffect::Uniform::Type::kFloat2:
130 pdman.set2fv(fUniformHandles[uniIndex++], v.fCount, data);
131 break;
132 case SkRuntimeEffect::Uniform::Type::kFloat3:
133 pdman.set3fv(fUniformHandles[uniIndex++], v.fCount, data);
134 break;
135 case SkRuntimeEffect::Uniform::Type::kFloat4:
136 pdman.set4fv(fUniformHandles[uniIndex++], v.fCount, data);
137 break;
138 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
139 pdman.setMatrix2fv(fUniformHandles[uniIndex++], v.fCount, data);
140 break;
141 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
142 pdman.setMatrix3fv(fUniformHandles[uniIndex++], v.fCount, data);
143 break;
144 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
145 pdman.setMatrix4fv(fUniformHandles[uniIndex++], v.fCount, data);
146 break;
147 default:
148 SkDEBUGFAIL("Unsupported uniform type");
149 break;
150 }
151 }
152 }
153
154 // nearly-finished GLSL; still contains printf-style "%s" format tokens
155 SkSL::PipelineStageArgs fArgs;
156 std::vector<UniformHandle> fUniformHandles;
157 std::vector<SkString> fFunctionNames;
158};
159
160std::unique_ptr<GrSkSLFP> GrSkSLFP::Make(GrContext_Base* context, sk_sp<SkRuntimeEffect> effect,
161 const char* name, sk_sp<SkData> uniforms) {
162 if (uniforms->size() != effect->uniformSize()) {
163 return nullptr;
164 }
165 return std::unique_ptr<GrSkSLFP>(new GrSkSLFP(
166 context->priv().caps()->refShaderCaps(), context->priv().getShaderErrorHandler(),
167 std::move(effect), name, std::move(uniforms)));
168}
169
170GrSkSLFP::GrSkSLFP(sk_sp<const GrShaderCaps> shaderCaps, ShaderErrorHandler* shaderErrorHandler,
171 sk_sp<SkRuntimeEffect> effect, const char* name, sk_sp<SkData> uniforms)
172 : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags)
173 , fShaderCaps(std::move(shaderCaps))
174 , fShaderErrorHandler(shaderErrorHandler)
175 , fEffect(std::move(effect))
176 , fName(name)
177 , fUniforms(std::move(uniforms)) {
178 if (fEffect->usesSampleCoords()) {
179 this->setUsesSampleCoordsDirectly();
180 }
181}
182
183GrSkSLFP::GrSkSLFP(const GrSkSLFP& other)
184 : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags)
185 , fShaderCaps(other.fShaderCaps)
186 , fShaderErrorHandler(other.fShaderErrorHandler)
187 , fEffect(other.fEffect)
188 , fName(other.fName)
189 , fUniforms(other.fUniforms) {
190 if (fEffect->usesSampleCoords()) {
191 this->setUsesSampleCoordsDirectly();
192 }
193
194 this->cloneAndRegisterAllChildProcessors(other);
195}
196
197const char* GrSkSLFP::name() const {
198 return fName;
199}
200
201void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child) {
202 int childIndex = this->numChildProcessors();
203 SkASSERT((size_t)childIndex < fEffect->fSampleUsages.size());
204 this->registerChild(std::move(child), fEffect->fSampleUsages[childIndex]);
205}
206
207GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const {
208 // Note: This is actually SkSL (again) but with inline format specifiers.
209 SkSL::PipelineStageArgs args;
210 SkAssertResult(fEffect->toPipelineStage(fShaderCaps.get(), fShaderErrorHandler, &args));
211 return new GrGLSLSkSLFP(std::move(args));
212}
213
214void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
215 // In the unlikely event of a hash collision, we also include the uniform size in the key.
216 // That ensures that we will (at worst) use the wrong program, but one that expects the same
217 // amount of uniform data.
218 b->add32(fEffect->hash());
219 b->add32(SkToU32(fUniforms->size()));
220}
221
222bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const {
223 const GrSkSLFP& sk = other.cast<GrSkSLFP>();
224 return fEffect->hash() == sk.fEffect->hash() && fUniforms->equals(sk.fUniforms.get());
225}
226
227std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const {
228 return std::unique_ptr<GrFragmentProcessor>(new GrSkSLFP(*this));
229}
230
231/**************************************************************************************************/
232
233GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP);
234
235#if GR_TEST_UTILS
236
237#include "include/effects/SkArithmeticImageFilter.h"
238#include "include/effects/SkOverdrawColorFilter.h"
239#include "src/core/SkColorFilterBase.h"
240#include "src/gpu/effects/generated/GrConstColorProcessor.h"
241
242extern const char* SKSL_OVERDRAW_SRC;
243
244std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
245 SkColor colors[SkOverdrawColorFilter::kNumColors];
246 for (SkColor& c : colors) {
247 c = d->fRandom->nextU();
248 }
249 auto filter = SkOverdrawColorFilter::MakeWithSkColors(colors);
250 auto [success, fp] = as_CFB(filter)->asFragmentProcessor(/*inputFP=*/nullptr, d->context(),
251 GrColorInfo{});
252 SkASSERT(success);
253 return std::move(fp);
254}
255
256#endif
257