blob: 17f7f10287b4259d985f0b5d2d349657b2c6921f [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) {
joshualitt43466a12015-02-13 17:18:27 -080049 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()) {
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);
Brian Salomon101b8442016-11-18 11:58:54 -050075 GrSLType samplerType = sampler.getType();
egdaniel990dbc82016-07-13 14:09:30 -070076 if (samplerType == kTexture2DRectSampler_GrSLType) {
bsalomone179a912016-01-20 06:18:10 -080077 if (varyingType == kVec2f_GrSLType) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -050078 out->appendf("texture(%s, textureSize(%s) * %s)",
Brian Salomon101b8442016-11-18 11:58:54 -050079 sampler.c_str(), sampler.c_str(), coordName);
bsalomone179a912016-01-20 06:18:10 -080080 } else {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -050081 out->appendf("texture(%s, vec3(textureSize(%s) * %s.xy, %s.z))",
Brian Salomon101b8442016-11-18 11:58:54 -050082 sampler.c_str(), sampler.c_str(), coordName, coordName);
bsalomone179a912016-01-20 06:18:10 -080083 }
84 } else {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -050085 out->appendf("texture(%s, %s)", sampler.c_str(), coordName);
bsalomone179a912016-01-20 06:18:10 -080086 }
Brian Salomon101b8442016-11-18 11:58:54 -050087 append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
joshualitt30ba4362014-08-21 20:18:45 -070088}
89
egdaniel09aa1fc2016-04-20 07:09:46 -070090void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
egdaniel2d721d32015-11-11 13:06:05 -080091 const char* coordName,
brianosman77320db2016-09-07 08:09:10 -070092 GrSLType varyingType,
93 GrGLSLColorSpaceXformHelper* colorXformHelper) {
94 if (colorXformHelper && colorXformHelper->getXformMatrix()) {
95 // With a color gamut transform, we need to wrap the lookup in another function call
96 SkString lookup;
97 this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
98 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
99 } else {
100 this->appendTextureLookup(&this->code(), samplerHandle, coordName, varyingType);
101 }
joshualitt30ba4362014-08-21 20:18:45 -0700102}
103
brianosman77320db2016-09-07 08:09:10 -0700104void GrGLSLShaderBuilder::appendTextureLookupAndModulate(
105 const char* modulation,
106 SamplerHandle samplerHandle,
107 const char* coordName,
108 GrSLType varyingType,
109 GrGLSLColorSpaceXformHelper* colorXformHelper) {
joshualitt30ba4362014-08-21 20:18:45 -0700110 SkString lookup;
egdaniel09aa1fc2016-04-20 07:09:46 -0700111 this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
brianosman77320db2016-09-07 08:09:10 -0700112 if (colorXformHelper && colorXformHelper->getXformMatrix()) {
113 SkString xform;
114 this->appendColorGamutXform(&xform, lookup.c_str(), colorXformHelper);
115 this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(xform)).c_str());
116 } else {
117 this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
118 }
119}
120
121void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
122 const char* srcColor,
123 GrGLSLColorSpaceXformHelper* colorXformHelper) {
124 // Our color is (r, g, b, a), but we want to multiply (r, g, b, 1) by our matrix, then
125 // re-insert the original alpha. The supplied srcColor is likely to be of the form
brianosman51924752016-09-12 08:50:19 -0700126 // "texture(...)", and we don't want to evaluate that twice, so wrap everything in a function.
Brian Salomon99938a82016-11-21 13:41:08 -0500127 static const GrShaderVar gColorGamutXformArgs[] = {
128 GrShaderVar("color", kVec4f_GrSLType),
129 GrShaderVar("xform", kMat44f_GrSLType),
brianosman77320db2016-09-07 08:09:10 -0700130 };
131 SkString functionBody;
Brian Osman0bd783f2017-01-04 12:54:07 -0500132 // Gamut xform, clamp to destination gamut. We only support/have premultiplied textures, so we
133 // always just clamp to alpha.
134 functionBody.append("\tcolor.rgb = clamp((xform * vec4(color.rgb, 1.0)).rgb, 0.0, color.a);\n");
brianosman77320db2016-09-07 08:09:10 -0700135 functionBody.append("\treturn color;");
136 SkString colorGamutXformFuncName;
137 this->emitFunction(kVec4f_GrSLType,
138 "colorGamutXform",
139 SK_ARRAY_COUNT(gColorGamutXformArgs),
140 gColorGamutXformArgs,
141 functionBody.c_str(),
142 &colorGamutXformFuncName);
143
144 out->appendf("%s(%s, %s)", colorGamutXformFuncName.c_str(), srcColor,
145 colorXformHelper->getXformMatrix());
146}
147
148void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
149 GrGLSLColorSpaceXformHelper* colorXformHelper) {
150 SkString xform;
151 this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
152 this->codeAppend(xform.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700153}
154
cdaltonf8a6ce82016-04-11 13:02:05 -0700155void GrGLSLShaderBuilder::appendTexelFetch(SkString* out,
egdaniel09aa1fc2016-04-20 07:09:46 -0700156 SamplerHandle samplerHandle,
cdaltonf8a6ce82016-04-11 13:02:05 -0700157 const char* coordExpr) const {
Brian Salomon99938a82016-11-21 13:41:08 -0500158 const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
Brian Salomon94efbf52016-11-29 13:43:05 -0500159 SkASSERT(fProgramBuilder->shaderCaps()->texelFetchSupport());
Brian Salomon101b8442016-11-18 11:58:54 -0500160 SkASSERT(GrSLTypeIsCombinedSamplerType(sampler.getType()));
cdaltonf8a6ce82016-04-11 13:02:05 -0700161
Brian Salomon101b8442016-11-18 11:58:54 -0500162 out->appendf("texelFetch(%s, %s)", sampler.c_str(), coordExpr);
cdaltonf8a6ce82016-04-11 13:02:05 -0700163
Brian Salomon101b8442016-11-18 11:58:54 -0500164 append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
cdaltonf8a6ce82016-04-11 13:02:05 -0700165}
166
egdaniel09aa1fc2016-04-20 07:09:46 -0700167void GrGLSLShaderBuilder::appendTexelFetch(SamplerHandle samplerHandle, const char* coordExpr) {
168 this->appendTexelFetch(&this->code(), samplerHandle, coordExpr);
cdaltonf8a6ce82016-04-11 13:02:05 -0700169}
170
Brian Salomonf9f45122016-11-29 11:59:17 -0500171void GrGLSLShaderBuilder::appendImageStorageLoad(SkString* out, ImageStorageHandle handle,
172 const char* coordExpr) {
173 const GrShaderVar& imageStorage = fProgramBuilder->imageStorageVariable(handle);
174 out->appendf("imageLoad(%s, %s)", imageStorage.c_str(), coordExpr);
175}
176
177void GrGLSLShaderBuilder::appendImageStorageLoad(ImageStorageHandle handle, const char* coordExpr) {
178 this->appendImageStorageLoad(&this->code(), handle, coordExpr);
179}
180
cdalton33ad7012016-02-22 07:55:44 -0800181bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
182 if (featureBit & fFeaturesAddedMask) {
183 return false;
joshualitt30ba4362014-08-21 20:18:45 -0700184 }
cdalton33ad7012016-02-22 07:55:44 -0800185 this->extensions().appendf("#extension %s: require\n", extensionName);
186 fFeaturesAddedMask |= featureBit;
187 return true;
joshualitt30ba4362014-08-21 20:18:45 -0700188}
189
egdaniel2d721d32015-11-11 13:06:05 -0800190void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
joshualitt47bb3822014-10-07 16:43:25 -0700191 for (int i = 0; i < vars.count(); ++i) {
Brian Salomon94efbf52016-11-29 13:43:05 -0500192 vars[i].appendDecl(fProgramBuilder->shaderCaps(), out);
joshualitt47bb3822014-10-07 16:43:25 -0700193 out->append(";\n");
194 }
195}
196
egdaniel2d721d32015-11-11 13:06:05 -0800197void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
Brian Salomon94efbf52016-11-29 13:43:05 -0500198 SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration ||
199 fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
cdaltone4017d82015-05-06 11:48:56 -0700200 fLayoutParams[interface].push_back() = param;
201}
202
egdaniel2d721d32015-11-11 13:06:05 -0800203void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
cdaltone4017d82015-05-06 11:48:56 -0700204 static const char* interfaceQualifierNames[] = {
csmartdalton276cc412016-11-21 11:55:00 -0700205 "in",
cdaltone4017d82015-05-06 11:48:56 -0700206 "out"
207 };
208
209 for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
210 const SkTArray<SkString>& params = fLayoutParams[interface];
211 if (params.empty()) {
212 continue;
213 }
214 this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
215 for (int i = 1; i < params.count(); ++i) {
216 this->layoutQualifiers().appendf(", %s", params[i].c_str());
217 }
218 this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
219 }
220
csmartdalton276cc412016-11-21 11:55:00 -0700221 GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
222 GR_STATIC_ASSERT(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
cdaltone4017d82015-05-06 11:48:56 -0700223 GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
224}
225
egdaniel2d721d32015-11-11 13:06:05 -0800226void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
joshualitt43466a12015-02-13 17:18:27 -0800227 SkASSERT(!fFinalized);
Brian Salomon94efbf52016-11-29 13:43:05 -0500228 this->versionDecl() = fProgramBuilder->shaderCaps()->versionDeclString();
egdaniel574a4c12015-11-02 06:22:44 -0800229 this->compileAndAppendLayoutQualifiers();
egdanielc8a66eb2015-11-02 07:46:25 -0800230 SkASSERT(visibility);
cdalton5e58cee2016-02-11 12:49:47 -0800231 fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
egdaniel574a4c12015-11-02 06:22:44 -0800232 this->appendDecls(fInputs, &this->inputs());
egdaniel574a4c12015-11-02 06:22:44 -0800233 this->appendDecls(fOutputs, &this->outputs());
234 this->onFinalize();
joshualitt43466a12015-02-13 17:18:27 -0800235 // append the 'footer' to code
236 this->code().append("}");
237
238 for (int i = 0; i <= fCodeIndex; i++) {
239 fCompilerStrings[i] = fShaderStrings[i].c_str();
240 fCompilerStringLengths[i] = (int)fShaderStrings[i].size();
241 }
242
joshualitt43466a12015-02-13 17:18:27 -0800243 fFinalized = true;
joshualitt43466a12015-02-13 17:18:27 -0800244}