blob: e2b1c559bcbf99e7d1f26dd866537f995d1e60e2 [file] [log] [blame]
joshualitt30ba4362014-08-21 20:18:45 -07001/*
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
Brian Salomon99938a82016-11-21 13:41:08 -05008#include "GrShaderVar.h"
Brian Salomon94efbf52016-11-29 13:43:05 -05009#include "GrShaderCaps.h"
bsalomoncdee0092016-01-08 13:20:12 -080010#include "GrSwizzle.h"
egdaniel2d721d32015-11-11 13:06:05 -080011#include "glsl/GrGLSLShaderBuilder.h"
brianosman77320db2016-09-07 08:09:10 -070012#include "glsl/GrGLSLColorSpaceXformHelper.h"
egdaniel8dcdedc2015-11-11 06:27:20 -080013#include "glsl/GrGLSLProgramBuilder.h"
joshualitt30ba4362014-08-21 20:18:45 -070014
egdaniel2d721d32015-11-11 13:06:05 -080015GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
joshualitt30ba4362014-08-21 20:18:45 -070016 : fProgramBuilder(program)
egdaniel8dcdedc2015-11-11 06:27:20 -080017 , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
18 , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
joshualitt43466a12015-02-13 17:18:27 -080019 , fFeaturesAddedMask(0)
20 , fCodeIndex(kCode)
21 , fFinalized(false) {
22 // We push back some dummy pointers which will later become our header
23 for (int i = 0; i <= kCode; i++) {
24 fShaderStrings.push_back();
halcanary96fcdcc2015-08-27 07:41:13 -070025 fCompilerStrings.push_back(nullptr);
joshualitt43466a12015-02-13 17:18:27 -080026 fCompilerStringLengths.push_back(0);
27 }
28
29 this->main() = "void main() {";
joshualitt30ba4362014-08-21 20:18:45 -070030}
31
Brian Salomon99938a82016-11-21 13:41:08 -050032void GrGLSLShaderBuilder::declAppend(const GrShaderVar& var) {
egdanielb2f94d12014-08-29 10:08:36 -070033 SkString tempDecl;
Brian Salomon94efbf52016-11-29 13:43:05 -050034 var.appendDecl(fProgramBuilder->shaderCaps(), &tempDecl);
egdanielb2f94d12014-08-29 10:08:36 -070035 this->codeAppendf("%s;", tempDecl.c_str());
36}
37
csmartdalton75864b02017-02-09 09:47:21 -050038void GrGLSLShaderBuilder::declareGlobal(const GrShaderVar& v) {
39 v.appendDecl(this->getProgramBuilder()->shaderCaps(), &this->definitions());
40 this->definitions().append(";");
41}
42
egdaniel2d721d32015-11-11 13:06:05 -080043void GrGLSLShaderBuilder::emitFunction(GrSLType returnType,
44 const char* name,
45 int argCnt,
Brian Salomon99938a82016-11-21 13:41:08 -050046 const GrShaderVar* args,
egdaniel2d721d32015-11-11 13:06:05 -080047 const char* body,
48 SkString* outName) {
Robert Phillips8296e752017-08-25 08:45:21 -040049 this->functions().append(GrGLSLTypeString(fProgramBuilder->shaderCaps(), returnType));
joshualitt30ba4362014-08-21 20:18:45 -070050 fProgramBuilder->nameVariable(outName, '\0', name);
joshualitt43466a12015-02-13 17:18:27 -080051 this->functions().appendf(" %s", outName->c_str());
52 this->functions().append("(");
joshualitt30ba4362014-08-21 20:18:45 -070053 for (int i = 0; i < argCnt; ++i) {
Brian Salomon94efbf52016-11-29 13:43:05 -050054 args[i].appendDecl(fProgramBuilder->shaderCaps(), &this->functions());
joshualitt30ba4362014-08-21 20:18:45 -070055 if (i < argCnt - 1) {
joshualitt43466a12015-02-13 17:18:27 -080056 this->functions().append(", ");
joshualitt30ba4362014-08-21 20:18:45 -070057 }
58 }
joshualitt43466a12015-02-13 17:18:27 -080059 this->functions().append(") {\n");
60 this->functions().append(body);
61 this->functions().append("}\n\n");
joshualitt30ba4362014-08-21 20:18:45 -070062}
63
Brian Salomon101b8442016-11-18 11:58:54 -050064static inline void append_texture_swizzle(SkString* out, GrSwizzle swizzle) {
65 if (swizzle != GrSwizzle::RGBA()) {
66 out->appendf(".%s", swizzle.c_str());
67 }
68}
69
egdaniel2d721d32015-11-11 13:06:05 -080070void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
egdaniel09aa1fc2016-04-20 07:09:46 -070071 SamplerHandle samplerHandle,
egdaniel2d721d32015-11-11 13:06:05 -080072 const char* coordName,
73 GrSLType varyingType) const {
Brian Salomon99938a82016-11-21 13:41:08 -050074 const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
Ethan Nicholas5338f992017-04-19 15:54:07 -040075 out->appendf("texture(%s, %s)", sampler.c_str(), coordName);
Brian Salomon101b8442016-11-18 11:58:54 -050076 append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
joshualitt30ba4362014-08-21 20:18:45 -070077}
78
egdaniel09aa1fc2016-04-20 07:09:46 -070079void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
egdaniel2d721d32015-11-11 13:06:05 -080080 const char* coordName,
brianosman77320db2016-09-07 08:09:10 -070081 GrSLType varyingType,
82 GrGLSLColorSpaceXformHelper* colorXformHelper) {
Brian Osmanc891b102018-06-14 14:50:17 -040083 SkString lookup;
84 this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
85 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
joshualitt30ba4362014-08-21 20:18:45 -070086}
87
brianosman77320db2016-09-07 08:09:10 -070088void GrGLSLShaderBuilder::appendTextureLookupAndModulate(
89 const char* modulation,
90 SamplerHandle samplerHandle,
91 const char* coordName,
92 GrSLType varyingType,
93 GrGLSLColorSpaceXformHelper* colorXformHelper) {
joshualitt30ba4362014-08-21 20:18:45 -070094 SkString lookup;
egdaniel09aa1fc2016-04-20 07:09:46 -070095 this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
Brian Osmanc891b102018-06-14 14:50:17 -040096 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
97 if (modulation) {
98 this->codeAppendf(" * %s", modulation);
brianosman77320db2016-09-07 08:09:10 -070099 }
100}
101
102void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
103 const char* srcColor,
104 GrGLSLColorSpaceXformHelper* colorXformHelper) {
Brian Osmanc891b102018-06-14 14:50:17 -0400105 if (!colorXformHelper || colorXformHelper->isNoop()) {
106 *out = srcColor;
107 return;
108 }
109
Brian Osmanc624d9d2017-03-08 11:42:02 -0500110 GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
Brian Osmanf06ead92017-10-30 13:47:41 -0400111
Brian Osman3567c142018-06-18 10:20:32 -0400112 // We define up to three helper functions, to keep things clearer. One for the source transfer
113 // function, one for the (inverse) destination transfer function, and one for the gamut xform.
114 // Any combination of these may be present, although some configurations are much more likely.
Brian Osmanf06ead92017-10-30 13:47:41 -0400115
Brian Osman3567c142018-06-18 10:20:32 -0400116 auto emitTFFunc = [=](const char* name, GrGLSLProgramDataManager::UniformHandle uniform) {
117 static const GrShaderVar gTFArgs[] = { GrShaderVar("x", kHalf_GrSLType) };
118 const char* coeffs = uniformHandler->getUniformCStr(uniform);
Brian Osmanf06ead92017-10-30 13:47:41 -0400119 SkString body;
120 // Temporaries to make evaluation line readable
121 body.appendf("half G = %s[0];", coeffs);
122 body.appendf("half A = %s[1];", coeffs);
123 body.appendf("half B = %s[2];", coeffs);
124 body.appendf("half C = %s[3];", coeffs);
125 body.appendf("half D = %s[4];", coeffs);
126 body.appendf("half E = %s[5];", coeffs);
127 body.appendf("half F = %s[6];", coeffs);
128 body.append("half s = sign(x);");
129 body.append("x = abs(x);");
130 body.appendf("return s * ((x < D) ? (C * x) + F : pow(A * x + B, G) + E);");
Brian Osman3567c142018-06-18 10:20:32 -0400131 SkString funcName;
132 this->emitFunction(kHalf_GrSLType, name, SK_ARRAY_COUNT(gTFArgs), gTFArgs, body.c_str(),
133 &funcName);
134 return funcName;
135 };
136
137 SkString srcTFFuncName;
138 if (colorXformHelper->applySrcTF()) {
139 srcTFFuncName = emitTFFunc("src_tf", colorXformHelper->srcTFUniform());
140 }
141
142 SkString dstTFFuncName;
143 if (colorXformHelper->applyDstTF()) {
144 dstTFFuncName = emitTFFunc("dst_tf", colorXformHelper->dstTFUniform());
Brian Osmanf06ead92017-10-30 13:47:41 -0400145 }
146
147 SkString gamutXformFuncName;
148 if (colorXformHelper->applyGamutXform()) {
Brian Osmanf06ead92017-10-30 13:47:41 -0400149 static const GrShaderVar gGamutXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) };
150 const char* xform = uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform());
151 SkString body;
Brian Osman3567c142018-06-18 10:20:32 -0400152 body.appendf("color.rgb = (%s * color.rgb);", xform);
Brian Osmanf06ead92017-10-30 13:47:41 -0400153 body.append("return color;");
154 this->emitFunction(kHalf4_GrSLType, "gamut_xform", SK_ARRAY_COUNT(gGamutXformArgs),
155 gGamutXformArgs, body.c_str(), &gamutXformFuncName);
156 }
157
158 // Now define a wrapper function that applies all the intermediate steps
159 {
160 static const GrShaderVar gColorXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) };
161 SkString body;
Brian Osman3567c142018-06-18 10:20:32 -0400162 if (colorXformHelper->applyUnpremul()) {
163 body.append("half nonZeroAlpha = max(color.a, 0.00001);");
164 body.append("color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha);");
Brian Osmanf06ead92017-10-30 13:47:41 -0400165 }
Brian Osman3567c142018-06-18 10:20:32 -0400166 if (colorXformHelper->applySrcTF()) {
167 body.appendf("color.r = %s(color.r);", srcTFFuncName.c_str());
168 body.appendf("color.g = %s(color.g);", srcTFFuncName.c_str());
169 body.appendf("color.b = %s(color.b);", srcTFFuncName.c_str());
Brian Osmanf06ead92017-10-30 13:47:41 -0400170 }
171 if (colorXformHelper->applyGamutXform()) {
172 body.appendf("color = %s(color);", gamutXformFuncName.c_str());
173 }
Brian Osman3567c142018-06-18 10:20:32 -0400174 if (colorXformHelper->applyDstTF()) {
175 body.appendf("color.r = %s(color.r);", dstTFFuncName.c_str());
176 body.appendf("color.g = %s(color.g);", dstTFFuncName.c_str());
177 body.appendf("color.b = %s(color.b);", dstTFFuncName.c_str());
178 }
179 if (colorXformHelper->applyPremul()) {
180 body.append("color.rgb *= color.a;");
181 }
Brian Osmanf06ead92017-10-30 13:47:41 -0400182 body.append("return color;");
183 SkString colorXformFuncName;
184 this->emitFunction(kHalf4_GrSLType, "color_xform", SK_ARRAY_COUNT(gColorXformArgs),
185 gColorXformArgs, body.c_str(), &colorXformFuncName);
186 out->appendf("%s(%s)", colorXformFuncName.c_str(), srcColor);
187 }
brianosman77320db2016-09-07 08:09:10 -0700188}
189
190void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
191 GrGLSLColorSpaceXformHelper* colorXformHelper) {
192 SkString xform;
193 this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
194 this->codeAppend(xform.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700195}
196
cdaltonf8a6ce82016-04-11 13:02:05 -0700197void GrGLSLShaderBuilder::appendTexelFetch(SkString* out,
Greg Danielbc5d4d72017-05-05 10:28:42 -0400198 TexelBufferHandle texelBufferHandle,
cdaltonf8a6ce82016-04-11 13:02:05 -0700199 const char* coordExpr) const {
Greg Danielbc5d4d72017-05-05 10:28:42 -0400200 const GrShaderVar& texelBuffer = fProgramBuilder->texelBufferVariable(texelBufferHandle);
Brian Salomon94efbf52016-11-29 13:43:05 -0500201 SkASSERT(fProgramBuilder->shaderCaps()->texelFetchSupport());
cdaltonf8a6ce82016-04-11 13:02:05 -0700202
Greg Danielbc5d4d72017-05-05 10:28:42 -0400203 out->appendf("texelFetch(%s, %s)", texelBuffer.c_str(), coordExpr);
cdaltonf8a6ce82016-04-11 13:02:05 -0700204}
205
Greg Danielbc5d4d72017-05-05 10:28:42 -0400206void GrGLSLShaderBuilder::appendTexelFetch(TexelBufferHandle texelBufferHandle,
207 const char* coordExpr) {
208 this->appendTexelFetch(&this->code(), texelBufferHandle, coordExpr);
cdaltonf8a6ce82016-04-11 13:02:05 -0700209}
210
cdalton33ad7012016-02-22 07:55:44 -0800211bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
212 if (featureBit & fFeaturesAddedMask) {
213 return false;
joshualitt30ba4362014-08-21 20:18:45 -0700214 }
cdalton33ad7012016-02-22 07:55:44 -0800215 this->extensions().appendf("#extension %s: require\n", extensionName);
216 fFeaturesAddedMask |= featureBit;
217 return true;
joshualitt30ba4362014-08-21 20:18:45 -0700218}
219
egdaniel2d721d32015-11-11 13:06:05 -0800220void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
joshualitt47bb3822014-10-07 16:43:25 -0700221 for (int i = 0; i < vars.count(); ++i) {
Brian Salomon94efbf52016-11-29 13:43:05 -0500222 vars[i].appendDecl(fProgramBuilder->shaderCaps(), out);
joshualitt47bb3822014-10-07 16:43:25 -0700223 out->append(";\n");
224 }
225}
226
egdaniel2d721d32015-11-11 13:06:05 -0800227void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
Brian Salomon94efbf52016-11-29 13:43:05 -0500228 SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration ||
229 fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
cdaltone4017d82015-05-06 11:48:56 -0700230 fLayoutParams[interface].push_back() = param;
231}
232
egdaniel2d721d32015-11-11 13:06:05 -0800233void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
cdaltone4017d82015-05-06 11:48:56 -0700234 static const char* interfaceQualifierNames[] = {
csmartdalton276cc412016-11-21 11:55:00 -0700235 "in",
cdaltone4017d82015-05-06 11:48:56 -0700236 "out"
237 };
238
239 for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
240 const SkTArray<SkString>& params = fLayoutParams[interface];
241 if (params.empty()) {
242 continue;
243 }
244 this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
245 for (int i = 1; i < params.count(); ++i) {
246 this->layoutQualifiers().appendf(", %s", params[i].c_str());
247 }
248 this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
249 }
250
csmartdalton276cc412016-11-21 11:55:00 -0700251 GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
252 GR_STATIC_ASSERT(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
cdaltone4017d82015-05-06 11:48:56 -0700253 GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
254}
255
egdaniel2d721d32015-11-11 13:06:05 -0800256void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
joshualitt43466a12015-02-13 17:18:27 -0800257 SkASSERT(!fFinalized);
Brian Salomon94efbf52016-11-29 13:43:05 -0500258 this->versionDecl() = fProgramBuilder->shaderCaps()->versionDeclString();
egdaniel574a4c12015-11-02 06:22:44 -0800259 this->compileAndAppendLayoutQualifiers();
egdanielc8a66eb2015-11-02 07:46:25 -0800260 SkASSERT(visibility);
cdalton5e58cee2016-02-11 12:49:47 -0800261 fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
egdaniel574a4c12015-11-02 06:22:44 -0800262 this->appendDecls(fInputs, &this->inputs());
egdaniel574a4c12015-11-02 06:22:44 -0800263 this->appendDecls(fOutputs, &this->outputs());
264 this->onFinalize();
joshualitt43466a12015-02-13 17:18:27 -0800265 // append the 'footer' to code
266 this->code().append("}");
267
268 for (int i = 0; i <= fCodeIndex; i++) {
269 fCompilerStrings[i] = fShaderStrings[i].c_str();
270 fCompilerStringLengths[i] = (int)fShaderStrings[i].size();
271 }
272
joshualitt43466a12015-02-13 17:18:27 -0800273 fFinalized = true;
joshualitt43466a12015-02-13 17:18:27 -0800274}