1 /*
2 * Copyright 2014 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 #include "src/gpu/ganesh/glsl/GrGLSLShaderBuilder.h"
8
9 #include "include/private/gpu/ganesh/GrTypesPriv.h"
10 #include "modules/skcms/skcms.h"
11 #include "src/core/SkSLTypeShared.h"
12 #include "src/gpu/Blend.h"
13 #include "src/gpu/Swizzle.h"
14 #include "src/gpu/ganesh/GrShaderCaps.h"
15 #include "src/gpu/ganesh/GrShaderVar.h"
16 #include "src/gpu/ganesh/glsl/GrGLSLColorSpaceXformHelper.h"
17 #include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h"
18 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
19 #include "src/sksl/SkSLGLSL.h"
20
21 using namespace skia_private;
22
GrGLSLShaderBuilder(GrGLSLProgramBuilder * program)23 GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
24 : fProgramBuilder(program)
25 , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
26 , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
27 , fFeaturesAddedMask(0)
28 , fCodeIndex(kCode)
29 , fFinalized(false)
30 , fTmpVariableCounter(0) {
31 // We push back some placeholder pointers which will later become our header
32 for (int i = 0; i <= kCode; i++) {
33 fShaderStrings.push_back();
34 }
35
36 this->main() = "void main() {";
37 }
38
declAppend(const GrShaderVar & var)39 void GrGLSLShaderBuilder::declAppend(const GrShaderVar& var) {
40 SkString tempDecl;
41 var.appendDecl(fProgramBuilder->shaderCaps(), &tempDecl);
42 this->codeAppendf("%s;", tempDecl.c_str());
43 }
44
declareGlobal(const GrShaderVar & v)45 void GrGLSLShaderBuilder::declareGlobal(const GrShaderVar& v) {
46 v.appendDecl(this->getProgramBuilder()->shaderCaps(), &this->definitions());
47 this->definitions().append(";");
48 }
49
getMangledFunctionName(const char * baseName)50 SkString GrGLSLShaderBuilder::getMangledFunctionName(const char* baseName) {
51 return fProgramBuilder->nameVariable(/*prefix=*/'\0', baseName);
52 }
53
appendFunctionDecl(SkSLType returnType,const char * mangledName,SkSpan<const GrShaderVar> args)54 void GrGLSLShaderBuilder::appendFunctionDecl(SkSLType returnType,
55 const char* mangledName,
56 SkSpan<const GrShaderVar> args) {
57 this->functions().appendf("%s %s(", SkSLTypeString(returnType), mangledName);
58 for (size_t i = 0; i < args.size(); ++i) {
59 if (i > 0) {
60 this->functions().append(", ");
61 }
62 args[i].appendDecl(fProgramBuilder->shaderCaps(), &this->functions());
63 }
64
65 this->functions().append(")");
66 }
67
emitFunction(SkSLType returnType,const char * mangledName,SkSpan<const GrShaderVar> args,const char * body)68 void GrGLSLShaderBuilder::emitFunction(SkSLType returnType,
69 const char* mangledName,
70 SkSpan<const GrShaderVar> args,
71 const char* body) {
72 this->appendFunctionDecl(returnType, mangledName, args);
73 this->functions().appendf(" {\n"
74 "%s"
75 "}\n\n", body);
76 }
77
emitFunction(const char * declaration,const char * body)78 void GrGLSLShaderBuilder::emitFunction(const char* declaration, const char* body) {
79 this->functions().appendf("%s {\n"
80 "%s"
81 "}\n\n", declaration, body);
82 }
83
emitFunctionPrototype(SkSLType returnType,const char * mangledName,SkSpan<const GrShaderVar> args)84 void GrGLSLShaderBuilder::emitFunctionPrototype(SkSLType returnType,
85 const char* mangledName,
86 SkSpan<const GrShaderVar> args) {
87 this->appendFunctionDecl(returnType, mangledName, args);
88 this->functions().append(";\n");
89 }
90
emitFunctionPrototype(const char * declaration)91 void GrGLSLShaderBuilder::emitFunctionPrototype(const char* declaration) {
92 this->functions().appendf("%s\n", declaration);
93 }
94
append_texture_swizzle(SkString * out,skgpu::Swizzle swizzle)95 static inline void append_texture_swizzle(SkString* out, skgpu::Swizzle swizzle) {
96 if (swizzle != skgpu::Swizzle::RGBA()) {
97 out->appendf(".%s", swizzle.asString().c_str());
98 }
99 }
100
appendTextureLookup(SkString * out,SamplerHandle samplerHandle,const char * coordName) const101 void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
102 SamplerHandle samplerHandle,
103 const char* coordName) const {
104 const char* sampler = fProgramBuilder->samplerVariable(samplerHandle);
105 out->appendf("sample(%s, %s)", sampler, coordName);
106 append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
107 }
108
appendTextureLookup(SamplerHandle samplerHandle,const char * coordName,GrGLSLColorSpaceXformHelper * colorXformHelper)109 void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
110 const char* coordName,
111 GrGLSLColorSpaceXformHelper* colorXformHelper) {
112 SkString lookup;
113 this->appendTextureLookup(&lookup, samplerHandle, coordName);
114 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
115 }
116
appendTextureLookupAndBlend(const char * dst,SkBlendMode mode,SamplerHandle samplerHandle,const char * coordName,GrGLSLColorSpaceXformHelper * colorXformHelper)117 void GrGLSLShaderBuilder::appendTextureLookupAndBlend(
118 const char* dst,
119 SkBlendMode mode,
120 SamplerHandle samplerHandle,
121 const char* coordName,
122 GrGLSLColorSpaceXformHelper* colorXformHelper) {
123 if (!dst) {
124 dst = "half4(1)";
125 }
126 SkString lookup;
127 this->codeAppendf("%s(", skgpu::BlendFuncName(mode));
128 this->appendTextureLookup(&lookup, samplerHandle, coordName);
129 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
130 this->codeAppendf(", %s)", dst);
131 }
132
appendInputLoad(SamplerHandle samplerHandle)133 void GrGLSLShaderBuilder::appendInputLoad(SamplerHandle samplerHandle) {
134 const char* input = fProgramBuilder->inputSamplerVariable(samplerHandle);
135 SkString load;
136 load.appendf("subpassLoad(%s)", input);
137 append_texture_swizzle(&load, fProgramBuilder->inputSamplerSwizzle(samplerHandle));
138 this->codeAppend(load.c_str());
139 }
140
appendColorGamutXform(SkString * out,const char * srcColor,GrGLSLColorSpaceXformHelper * colorXformHelper)141 void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
142 const char* srcColor,
143 GrGLSLColorSpaceXformHelper* colorXformHelper) {
144 if (!colorXformHelper || colorXformHelper->isNoop()) {
145 *out = srcColor;
146 return;
147 }
148
149 GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
150
151 // We define up to three helper functions, to keep things clearer. One for the source transfer
152 // function, one for the (inverse) destination transfer function, and one for the gamut xform.
153 // Any combination of these may be present, although some configurations are much more likely.
154
155 auto emitTFFunc = [this, &uniformHandler](const char* name,
156 GrGLSLProgramDataManager::UniformHandle uniform,
157 skcms_TFType tfType) {
158 const GrShaderVar gTFArgs[] = { GrShaderVar("x", SkSLType::kFloat) };
159 const char* coeffs = uniformHandler->getUniformCStr(uniform);
160 SkString body;
161 // Temporaries to make evaluation line readable. We always use the sRGBish names, so the
162 // PQ and HLG math is confusing.
163 body.appendf("float G = %s[0];", coeffs);
164 body.appendf("float A = %s[1];", coeffs);
165 body.appendf("float B = %s[2];", coeffs);
166 body.appendf("float C = %s[3];", coeffs);
167 body.appendf("float D = %s[4];", coeffs);
168 body.appendf("float E = %s[5];", coeffs);
169 body.appendf("float F = %s[6];", coeffs);
170 body.append("float s = sign(x);");
171 body.append("x = abs(x);");
172 switch (tfType) {
173 case skcms_TFType_sRGBish:
174 body.append("x = (x < D) ? (C * x) + F : pow(A * x + B, G) + E;");
175 break;
176 case skcms_TFType_PQish:
177 body.append("x = pow(max(A + B * pow(x, C), 0) / (D + E * pow(x, C)), F);");
178 break;
179 case skcms_TFType_HLGish:
180 body.append("x = (x*A <= 1) ? pow(x*A, B) : exp((x-E)*C) + D; x *= (F+1);");
181 break;
182 case skcms_TFType_HLGinvish:
183 body.append("x /= (F+1); x = (x <= 1) ? A * pow(x, B) : C * log(x - D) + E;");
184 break;
185 default:
186 SkASSERT(false);
187 break;
188 }
189 body.append("return s * x;");
190 SkString funcName = this->getMangledFunctionName(name);
191 this->emitFunction(SkSLType::kFloat, funcName.c_str(), {gTFArgs, std::size(gTFArgs)},
192 body.c_str());
193 return funcName;
194 };
195
196 SkString srcTFFuncName;
197 if (colorXformHelper->applySrcTF()) {
198 srcTFFuncName = emitTFFunc("src_tf", colorXformHelper->srcTFUniform(),
199 colorXformHelper->srcTFType());
200 }
201
202 SkString dstTFFuncName;
203 if (colorXformHelper->applyDstTF()) {
204 dstTFFuncName = emitTFFunc("dst_tf", colorXformHelper->dstTFUniform(),
205 colorXformHelper->dstTFType());
206 }
207
208 SkString gamutXformFuncName;
209 if (colorXformHelper->applyGamutXform()) {
210 const GrShaderVar gGamutXformArgs[] = { GrShaderVar("color", SkSLType::kFloat4) };
211 const char* xform = uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform());
212 SkString body;
213 body.appendf("color.rgb = (%s * color.rgb);", xform);
214 body.append("return color;");
215 gamutXformFuncName = this->getMangledFunctionName("gamut_xform");
216 this->emitFunction(SkSLType::kFloat4, gamutXformFuncName.c_str(),
217 {gGamutXformArgs, std::size(gGamutXformArgs)}, body.c_str());
218 }
219
220 // Now define a wrapper function that applies all the intermediate steps
221 {
222 const GrShaderVar gColorXformArgs[] = { GrShaderVar("color", SkSLType::kFloat4) };
223 SkString body;
224 if (colorXformHelper->applyUnpremul()) {
225 body.append("color = unpremul(color);");
226 }
227 if (colorXformHelper->applySrcTF()) {
228 body.appendf("color.r = %s(color.r);", srcTFFuncName.c_str());
229 body.appendf("color.g = %s(color.g);", srcTFFuncName.c_str());
230 body.appendf("color.b = %s(color.b);", srcTFFuncName.c_str());
231 }
232 if (colorXformHelper->applyGamutXform()) {
233 body.appendf("color = %s(color);", gamutXformFuncName.c_str());
234 }
235 if (colorXformHelper->applyDstTF()) {
236 body.appendf("color.r = %s(color.r);", dstTFFuncName.c_str());
237 body.appendf("color.g = %s(color.g);", dstTFFuncName.c_str());
238 body.appendf("color.b = %s(color.b);", dstTFFuncName.c_str());
239 }
240 if (colorXformHelper->applyPremul()) {
241 body.append("color.rgb *= color.a;");
242 }
243 body.append("return half4(color);");
244 SkString colorXformFuncName = this->getMangledFunctionName("color_xform");
245 this->emitFunction(SkSLType::kHalf4, colorXformFuncName.c_str(),
246 {gColorXformArgs, std::size(gColorXformArgs)}, body.c_str());
247 out->appendf("%s(%s)", colorXformFuncName.c_str(), srcColor);
248 }
249 }
250
appendColorGamutXform(const char * srcColor,GrGLSLColorSpaceXformHelper * colorXformHelper)251 void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
252 GrGLSLColorSpaceXformHelper* colorXformHelper) {
253 SkString xform;
254 this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
255 this->codeAppend(xform.c_str());
256 }
257
addFeature(uint32_t featureBit,const char * extensionName)258 bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
259 if (featureBit & fFeaturesAddedMask) {
260 return false;
261 }
262 this->extensions().appendf("#extension %s: require\n", extensionName);
263 fFeaturesAddedMask |= featureBit;
264 return true;
265 }
266
appendDecls(const VarArray & vars,SkString * out) const267 void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
268 for (const auto& v : vars.items()) {
269 v.appendDecl(fProgramBuilder->shaderCaps(), out);
270 out->append(";\n");
271 }
272 }
273
addLayoutQualifier(const char * param,InterfaceQualifier interface)274 void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
275 SkASSERT(fProgramBuilder->shaderCaps()->fGLSLGeneration >= SkSL::GLSLGeneration::k330 ||
276 fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
277 fLayoutParams[interface].push_back() = param;
278 }
279
compileAndAppendLayoutQualifiers()280 void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
281 static const char* interfaceQualifierNames[] = {
282 "in",
283 "out"
284 };
285
286 for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
287 const TArray<SkString>& params = fLayoutParams[interface];
288 if (params.empty()) {
289 continue;
290 }
291 this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
292 for (int i = 1; i < params.size(); ++i) {
293 this->layoutQualifiers().appendf(", %s", params[i].c_str());
294 }
295 this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
296 }
297
298 static_assert(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
299 static_assert(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
300 static_assert(std::size(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
301 }
302
finalize(uint32_t visibility)303 void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
304 SkASSERT(!fFinalized);
305 this->compileAndAppendLayoutQualifiers();
306 SkASSERT(visibility);
307 fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
308 this->appendDecls(fInputs, &this->inputs());
309 this->appendDecls(fOutputs, &this->outputs());
310 this->onFinalize();
311 // append the 'footer' to code
312 this->code().append("}");
313
314 for (int i = 0; i <= fCodeIndex; i++) {
315 fCompilerString.append(fShaderStrings[i].c_str(), fShaderStrings[i].size());
316 }
317
318 fFinalized = true;
319 }
320