xref: /aosp_15_r20/external/skia/src/gpu/ganesh/glsl/GrGLSLShaderBuilder.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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