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