• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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