blob: 827eef77625501c6c7a027415d32c165cd661201 [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
Greg Daniel2c19e7f2019-06-18 13:29:21 -04008#include "src/gpu/glsl/GrGLSLShaderBuilder.h"
9
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/gpu/GrShaderCaps.h"
11#include "src/gpu/GrShaderVar.h"
Brian Salomon3ec1f542019-06-17 17:54:57 +000012#include "src/gpu/GrSwizzle.h"
Brian Salomon87e9ddb2019-12-19 14:50:22 -050013#include "src/gpu/glsl/GrGLSLBlend.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
15#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
joshualitt30ba4362014-08-21 20:18:45 -070016
egdaniel2d721d32015-11-11 13:06:05 -080017GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
joshualitt30ba4362014-08-21 20:18:45 -070018 : fProgramBuilder(program)
egdaniel8dcdedc2015-11-11 06:27:20 -080019 , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
20 , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
joshualitt43466a12015-02-13 17:18:27 -080021 , fFeaturesAddedMask(0)
22 , fCodeIndex(kCode)
23 , fFinalized(false) {
24 // We push back some dummy pointers which will later become our header
25 for (int i = 0; i <= kCode; i++) {
26 fShaderStrings.push_back();
joshualitt43466a12015-02-13 17:18:27 -080027 }
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) {
Chris Dalton4f5cbcd2019-02-13 14:04:34 -070049 this->functions().append(GrGLSLTypeString(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()) {
Greg Daniel369ee6b2019-12-02 15:30:02 -050066 out->appendf(".%s", swizzle.asString().c_str());
Brian Salomon101b8442016-11-18 11:58:54 -050067 }
68}
69
egdaniel2d721d32015-11-11 13:06:05 -080070void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
egdaniel09aa1fc2016-04-20 07:09:46 -070071 SamplerHandle samplerHandle,
Brian Salomond19cd762020-01-06 13:16:31 -050072 const char* coordName) const {
Stephen Whited523a062019-06-19 13:12:46 -040073 const char* sampler = fProgramBuilder->samplerVariable(samplerHandle);
Ethan Nicholas13863662019-07-29 13:05:15 -040074 out->appendf("sample(%s, %s)", sampler, coordName);
Brian Salomon101b8442016-11-18 11:58:54 -050075 append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
joshualitt30ba4362014-08-21 20:18:45 -070076}
77
egdaniel09aa1fc2016-04-20 07:09:46 -070078void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
egdaniel2d721d32015-11-11 13:06:05 -080079 const char* coordName,
brianosman77320db2016-09-07 08:09:10 -070080 GrGLSLColorSpaceXformHelper* colorXformHelper) {
Brian Osmanc891b102018-06-14 14:50:17 -040081 SkString lookup;
Brian Salomond19cd762020-01-06 13:16:31 -050082 this->appendTextureLookup(&lookup, samplerHandle, coordName);
Brian Osmanc891b102018-06-14 14:50:17 -040083 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
joshualitt30ba4362014-08-21 20:18:45 -070084}
85
Brian Salomon87e9ddb2019-12-19 14:50:22 -050086void GrGLSLShaderBuilder::appendTextureLookupAndBlend(
87 const char* dst,
88 SkBlendMode mode,
89 SamplerHandle samplerHandle,
90 const char* coordName,
Brian Salomon87e9ddb2019-12-19 14:50:22 -050091 GrGLSLColorSpaceXformHelper* colorXformHelper) {
92 if (!dst) {
93 dst = "half4(1)";
94 }
joshualitt30ba4362014-08-21 20:18:45 -070095 SkString lookup;
Brian Salomon87e9ddb2019-12-19 14:50:22 -050096 this->codeAppendf("%s(", GrGLSLBlend::BlendFuncName(mode));
Brian Salomond19cd762020-01-06 13:16:31 -050097 this->appendTextureLookup(&lookup, samplerHandle, coordName);
Brian Osmanc891b102018-06-14 14:50:17 -040098 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
Brian Salomon87e9ddb2019-12-19 14:50:22 -050099 this->codeAppendf(", %s)", dst);
brianosman77320db2016-09-07 08:09:10 -0700100}
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 Osman11e6aa82019-10-16 13:58:42 -0400116 auto emitTFFunc = [=](const char* name, GrGLSLProgramDataManager::UniformHandle uniform,
117 TFKind kind) {
Nico Webere50efdf2018-10-01 14:40:44 -0400118 const GrShaderVar gTFArgs[] = { GrShaderVar("x", kHalf_GrSLType) };
Brian Osman3567c142018-06-18 10:20:32 -0400119 const char* coeffs = uniformHandler->getUniformCStr(uniform);
Brian Osmanf06ead92017-10-30 13:47:41 -0400120 SkString body;
Brian Osman11e6aa82019-10-16 13:58:42 -0400121 // Temporaries to make evaluation line readable. We always use the sRGBish names, so the
122 // PQ and HLG math is confusing.
Brian Osmanf06ead92017-10-30 13:47:41 -0400123 body.appendf("half G = %s[0];", coeffs);
124 body.appendf("half A = %s[1];", coeffs);
125 body.appendf("half B = %s[2];", coeffs);
126 body.appendf("half C = %s[3];", coeffs);
127 body.appendf("half D = %s[4];", coeffs);
128 body.appendf("half E = %s[5];", coeffs);
129 body.appendf("half F = %s[6];", coeffs);
130 body.append("half s = sign(x);");
131 body.append("x = abs(x);");
Brian Osman11e6aa82019-10-16 13:58:42 -0400132 switch (kind) {
133 case TFKind::sRGBish_TF:
134 body.append("x = (x < D) ? (C * x) + F : pow(A * x + B, G) + E;");
135 break;
136 case TFKind::PQish_TF:
137 body.append("x = pow(max(A + B * pow(x, C), 0) / (D + E * pow(x, C)), F);");
138 break;
139 case TFKind::HLGish_TF:
140 body.append("x = (x*A <= 1) ? pow(x*A, B) : exp((x-E)*C) + D;");
141 break;
142 case TFKind::HLGinvish_TF:
143 body.append("x = (x <= 1) ? A * pow(x, B) : C * log(x - D) + E;");
144 break;
145 default:
146 SkASSERT(false);
147 break;
148 }
149 body.append("return s * x;");
Brian Osman3567c142018-06-18 10:20:32 -0400150 SkString funcName;
151 this->emitFunction(kHalf_GrSLType, name, SK_ARRAY_COUNT(gTFArgs), gTFArgs, body.c_str(),
152 &funcName);
153 return funcName;
154 };
155
156 SkString srcTFFuncName;
157 if (colorXformHelper->applySrcTF()) {
Brian Osman11e6aa82019-10-16 13:58:42 -0400158 srcTFFuncName = emitTFFunc("src_tf", colorXformHelper->srcTFUniform(),
159 colorXformHelper->srcTFKind());
Brian Osman3567c142018-06-18 10:20:32 -0400160 }
161
162 SkString dstTFFuncName;
163 if (colorXformHelper->applyDstTF()) {
Brian Osman11e6aa82019-10-16 13:58:42 -0400164 dstTFFuncName = emitTFFunc("dst_tf", colorXformHelper->dstTFUniform(),
165 colorXformHelper->dstTFKind());
Brian Osmanf06ead92017-10-30 13:47:41 -0400166 }
167
168 SkString gamutXformFuncName;
169 if (colorXformHelper->applyGamutXform()) {
Nico Webere50efdf2018-10-01 14:40:44 -0400170 const GrShaderVar gGamutXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) };
Brian Osmanf06ead92017-10-30 13:47:41 -0400171 const char* xform = uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform());
172 SkString body;
Brian Osman3567c142018-06-18 10:20:32 -0400173 body.appendf("color.rgb = (%s * color.rgb);", xform);
Brian Osmanf06ead92017-10-30 13:47:41 -0400174 body.append("return color;");
175 this->emitFunction(kHalf4_GrSLType, "gamut_xform", SK_ARRAY_COUNT(gGamutXformArgs),
176 gGamutXformArgs, body.c_str(), &gamutXformFuncName);
177 }
178
179 // Now define a wrapper function that applies all the intermediate steps
180 {
Nico Webere50efdf2018-10-01 14:40:44 -0400181 const GrShaderVar gColorXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) };
Brian Osmanf06ead92017-10-30 13:47:41 -0400182 SkString body;
Brian Osman3567c142018-06-18 10:20:32 -0400183 if (colorXformHelper->applyUnpremul()) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -0400184 body.append("half nonZeroAlpha = max(color.a, 0.0001);");
185 body.append("color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha);");
Brian Osmanf06ead92017-10-30 13:47:41 -0400186 }
Brian Osman3567c142018-06-18 10:20:32 -0400187 if (colorXformHelper->applySrcTF()) {
188 body.appendf("color.r = %s(color.r);", srcTFFuncName.c_str());
189 body.appendf("color.g = %s(color.g);", srcTFFuncName.c_str());
190 body.appendf("color.b = %s(color.b);", srcTFFuncName.c_str());
Brian Osmanf06ead92017-10-30 13:47:41 -0400191 }
192 if (colorXformHelper->applyGamutXform()) {
193 body.appendf("color = %s(color);", gamutXformFuncName.c_str());
194 }
Brian Osman3567c142018-06-18 10:20:32 -0400195 if (colorXformHelper->applyDstTF()) {
196 body.appendf("color.r = %s(color.r);", dstTFFuncName.c_str());
197 body.appendf("color.g = %s(color.g);", dstTFFuncName.c_str());
198 body.appendf("color.b = %s(color.b);", dstTFFuncName.c_str());
199 }
200 if (colorXformHelper->applyPremul()) {
201 body.append("color.rgb *= color.a;");
202 }
Brian Osmanf06ead92017-10-30 13:47:41 -0400203 body.append("return color;");
204 SkString colorXformFuncName;
205 this->emitFunction(kHalf4_GrSLType, "color_xform", SK_ARRAY_COUNT(gColorXformArgs),
206 gColorXformArgs, body.c_str(), &colorXformFuncName);
207 out->appendf("%s(%s)", colorXformFuncName.c_str(), srcColor);
208 }
brianosman77320db2016-09-07 08:09:10 -0700209}
210
211void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
212 GrGLSLColorSpaceXformHelper* colorXformHelper) {
213 SkString xform;
214 this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
215 this->codeAppend(xform.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700216}
217
cdalton33ad7012016-02-22 07:55:44 -0800218bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
219 if (featureBit & fFeaturesAddedMask) {
220 return false;
joshualitt30ba4362014-08-21 20:18:45 -0700221 }
cdalton33ad7012016-02-22 07:55:44 -0800222 this->extensions().appendf("#extension %s: require\n", extensionName);
223 fFeaturesAddedMask |= featureBit;
224 return true;
joshualitt30ba4362014-08-21 20:18:45 -0700225}
226
egdaniel2d721d32015-11-11 13:06:05 -0800227void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
joshualitt47bb3822014-10-07 16:43:25 -0700228 for (int i = 0; i < vars.count(); ++i) {
Brian Salomon94efbf52016-11-29 13:43:05 -0500229 vars[i].appendDecl(fProgramBuilder->shaderCaps(), out);
joshualitt47bb3822014-10-07 16:43:25 -0700230 out->append(";\n");
231 }
232}
233
egdaniel2d721d32015-11-11 13:06:05 -0800234void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
Brian Salomon94efbf52016-11-29 13:43:05 -0500235 SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration ||
236 fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
cdaltone4017d82015-05-06 11:48:56 -0700237 fLayoutParams[interface].push_back() = param;
238}
239
egdaniel2d721d32015-11-11 13:06:05 -0800240void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
cdaltone4017d82015-05-06 11:48:56 -0700241 static const char* interfaceQualifierNames[] = {
csmartdalton276cc412016-11-21 11:55:00 -0700242 "in",
cdaltone4017d82015-05-06 11:48:56 -0700243 "out"
244 };
245
246 for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
247 const SkTArray<SkString>& params = fLayoutParams[interface];
248 if (params.empty()) {
249 continue;
250 }
251 this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
252 for (int i = 1; i < params.count(); ++i) {
253 this->layoutQualifiers().appendf(", %s", params[i].c_str());
254 }
255 this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
256 }
257
Brian Salomon4dea72a2019-12-18 10:43:10 -0500258 static_assert(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
259 static_assert(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
260 static_assert(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
cdaltone4017d82015-05-06 11:48:56 -0700261}
262
egdaniel2d721d32015-11-11 13:06:05 -0800263void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
joshualitt43466a12015-02-13 17:18:27 -0800264 SkASSERT(!fFinalized);
egdaniel574a4c12015-11-02 06:22:44 -0800265 this->compileAndAppendLayoutQualifiers();
egdanielc8a66eb2015-11-02 07:46:25 -0800266 SkASSERT(visibility);
cdalton5e58cee2016-02-11 12:49:47 -0800267 fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
egdaniel574a4c12015-11-02 06:22:44 -0800268 this->appendDecls(fInputs, &this->inputs());
egdaniel574a4c12015-11-02 06:22:44 -0800269 this->appendDecls(fOutputs, &this->outputs());
270 this->onFinalize();
joshualitt43466a12015-02-13 17:18:27 -0800271 // append the 'footer' to code
272 this->code().append("}");
273
274 for (int i = 0; i <= fCodeIndex; i++) {
Brian Osman6c431d52019-04-15 16:31:54 -0400275 fCompilerString.append(fShaderStrings[i].c_str(), fShaderStrings[i].size());
joshualitt43466a12015-02-13 17:18:27 -0800276 }
277
joshualitt43466a12015-02-13 17:18:27 -0800278 fFinalized = true;
joshualitt43466a12015-02-13 17:18:27 -0800279}