blob: 6d77bdbf9a5c32cd3b70ed2dc481cc1d0a08d341 [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
bsalomoncdee0092016-01-08 13:20:12 -08008#include "GrSwizzle.h"
egdaniel2d721d32015-11-11 13:06:05 -08009#include "glsl/GrGLSLShaderBuilder.h"
jvanverthcba99b82015-06-24 06:59:57 -070010#include "glsl/GrGLSLCaps.h"
brianosman77320db2016-09-07 08:09:10 -070011#include "glsl/GrGLSLColorSpaceXformHelper.h"
egdaniel0d3f0612015-10-21 10:45:48 -070012#include "glsl/GrGLSLShaderVar.h"
cdalton3f6f76f2016-04-11 12:18:09 -070013#include "glsl/GrGLSLSampler.h"
egdaniel8dcdedc2015-11-11 06:27:20 -080014#include "glsl/GrGLSLProgramBuilder.h"
joshualitt30ba4362014-08-21 20:18:45 -070015
egdaniel2d721d32015-11-11 13:06:05 -080016GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
joshualitt30ba4362014-08-21 20:18:45 -070017 : fProgramBuilder(program)
egdaniel8dcdedc2015-11-11 06:27:20 -080018 , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
19 , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
joshualitt43466a12015-02-13 17:18:27 -080020 , fFeaturesAddedMask(0)
21 , fCodeIndex(kCode)
22 , fFinalized(false) {
23 // We push back some dummy pointers which will later become our header
24 for (int i = 0; i <= kCode; i++) {
25 fShaderStrings.push_back();
halcanary96fcdcc2015-08-27 07:41:13 -070026 fCompilerStrings.push_back(nullptr);
joshualitt43466a12015-02-13 17:18:27 -080027 fCompilerStringLengths.push_back(0);
28 }
29
30 this->main() = "void main() {";
joshualitt30ba4362014-08-21 20:18:45 -070031}
32
egdaniel2d721d32015-11-11 13:06:05 -080033void GrGLSLShaderBuilder::declAppend(const GrGLSLShaderVar& var) {
egdanielb2f94d12014-08-29 10:08:36 -070034 SkString tempDecl;
egdanielf5294392015-10-21 07:14:17 -070035 var.appendDecl(fProgramBuilder->glslCaps(), &tempDecl);
egdanielb2f94d12014-08-29 10:08:36 -070036 this->codeAppendf("%s;", tempDecl.c_str());
37}
38
cdalton1f50acf2016-04-11 11:30:50 -070039void GrGLSLShaderBuilder::appendPrecisionModifier(GrSLPrecision precision) {
40 if (fProgramBuilder->glslCaps()->usesPrecisionModifiers()) {
41 this->codeAppendf("%s ", GrGLSLPrecisionString(precision));
42 }
43}
44
egdaniel2d721d32015-11-11 13:06:05 -080045void GrGLSLShaderBuilder::emitFunction(GrSLType returnType,
46 const char* name,
47 int argCnt,
48 const GrGLSLShaderVar* args,
49 const char* body,
50 SkString* outName) {
joshualitt43466a12015-02-13 17:18:27 -080051 this->functions().append(GrGLSLTypeString(returnType));
joshualitt30ba4362014-08-21 20:18:45 -070052 fProgramBuilder->nameVariable(outName, '\0', name);
joshualitt43466a12015-02-13 17:18:27 -080053 this->functions().appendf(" %s", outName->c_str());
54 this->functions().append("(");
joshualitt30ba4362014-08-21 20:18:45 -070055 for (int i = 0; i < argCnt; ++i) {
egdanielf5294392015-10-21 07:14:17 -070056 args[i].appendDecl(fProgramBuilder->glslCaps(), &this->functions());
joshualitt30ba4362014-08-21 20:18:45 -070057 if (i < argCnt - 1) {
joshualitt43466a12015-02-13 17:18:27 -080058 this->functions().append(", ");
joshualitt30ba4362014-08-21 20:18:45 -070059 }
60 }
joshualitt43466a12015-02-13 17:18:27 -080061 this->functions().append(") {\n");
62 this->functions().append(body);
63 this->functions().append("}\n\n");
joshualitt30ba4362014-08-21 20:18:45 -070064}
65
egdaniel2d721d32015-11-11 13:06:05 -080066void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
egdaniel09aa1fc2016-04-20 07:09:46 -070067 SamplerHandle samplerHandle,
egdaniel2d721d32015-11-11 13:06:05 -080068 const char* coordName,
69 GrSLType varyingType) const {
bsalomoncdee0092016-01-08 13:20:12 -080070 const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
egdaniel09aa1fc2016-04-20 07:09:46 -070071 const GrGLSLSampler& sampler = fProgramBuilder->getSampler(samplerHandle);
72 GrSLType samplerType = sampler.type();
egdaniel990dbc82016-07-13 14:09:30 -070073 if (samplerType == kTexture2DRectSampler_GrSLType) {
bsalomone179a912016-01-20 06:18:10 -080074 if (varyingType == kVec2f_GrSLType) {
75 out->appendf("%s(%s, textureSize(%s) * %s)",
76 GrGLSLTexture2DFunctionName(varyingType, samplerType,
77 glslCaps->generation()),
egdaniel09aa1fc2016-04-20 07:09:46 -070078 sampler.getSamplerNameForTexture2D(),
79 sampler.getSamplerNameForTexture2D(),
bsalomone179a912016-01-20 06:18:10 -080080 coordName);
81 } else {
82 out->appendf("%s(%s, vec3(textureSize(%s) * %s.xy, %s.z))",
83 GrGLSLTexture2DFunctionName(varyingType, samplerType,
84 glslCaps->generation()),
egdaniel09aa1fc2016-04-20 07:09:46 -070085 sampler.getSamplerNameForTexture2D(),
86 sampler.getSamplerNameForTexture2D(),
bsalomone179a912016-01-20 06:18:10 -080087 coordName,
88 coordName);
89 }
90 } else {
91 out->appendf("%s(%s, %s)",
92 GrGLSLTexture2DFunctionName(varyingType, samplerType, glslCaps->generation()),
egdaniel09aa1fc2016-04-20 07:09:46 -070093 sampler.getSamplerNameForTexture2D(),
bsalomone179a912016-01-20 06:18:10 -080094 coordName);
95 }
bsalomoncdee0092016-01-08 13:20:12 -080096
cdaltonf8a6ce82016-04-11 13:02:05 -070097 this->appendTextureSwizzle(out, sampler.config());
joshualitt30ba4362014-08-21 20:18:45 -070098}
99
egdaniel09aa1fc2016-04-20 07:09:46 -0700100void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
egdaniel2d721d32015-11-11 13:06:05 -0800101 const char* coordName,
brianosman77320db2016-09-07 08:09:10 -0700102 GrSLType varyingType,
103 GrGLSLColorSpaceXformHelper* colorXformHelper) {
104 if (colorXformHelper && colorXformHelper->getXformMatrix()) {
105 // With a color gamut transform, we need to wrap the lookup in another function call
106 SkString lookup;
107 this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
108 this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
109 } else {
110 this->appendTextureLookup(&this->code(), samplerHandle, coordName, varyingType);
111 }
joshualitt30ba4362014-08-21 20:18:45 -0700112}
113
brianosman77320db2016-09-07 08:09:10 -0700114void GrGLSLShaderBuilder::appendTextureLookupAndModulate(
115 const char* modulation,
116 SamplerHandle samplerHandle,
117 const char* coordName,
118 GrSLType varyingType,
119 GrGLSLColorSpaceXformHelper* colorXformHelper) {
joshualitt30ba4362014-08-21 20:18:45 -0700120 SkString lookup;
egdaniel09aa1fc2016-04-20 07:09:46 -0700121 this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
brianosman77320db2016-09-07 08:09:10 -0700122 if (colorXformHelper && colorXformHelper->getXformMatrix()) {
123 SkString xform;
124 this->appendColorGamutXform(&xform, lookup.c_str(), colorXformHelper);
125 this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(xform)).c_str());
126 } else {
127 this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
128 }
129}
130
131void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
132 const char* srcColor,
133 GrGLSLColorSpaceXformHelper* colorXformHelper) {
134 // Our color is (r, g, b, a), but we want to multiply (r, g, b, 1) by our matrix, then
135 // re-insert the original alpha. The supplied srcColor is likely to be of the form
brianosman51924752016-09-12 08:50:19 -0700136 // "texture(...)", and we don't want to evaluate that twice, so wrap everything in a function.
brianosman77320db2016-09-07 08:09:10 -0700137 static const GrGLSLShaderVar gColorGamutXformArgs[] = {
138 GrGLSLShaderVar("color", kVec4f_GrSLType),
139 GrGLSLShaderVar("xform", kMat44f_GrSLType),
140 };
141 SkString functionBody;
brianosman77320db2016-09-07 08:09:10 -0700142 // Gamut xform, clamp to destination gamut
brianosman8d914902016-09-09 11:30:55 -0700143 functionBody.append("\tcolor.rgb = clamp((xform * vec4(color.rgb, 1.0)).rgb, 0.0, 1.0);\n");
brianosman77320db2016-09-07 08:09:10 -0700144 functionBody.append("\treturn color;");
145 SkString colorGamutXformFuncName;
146 this->emitFunction(kVec4f_GrSLType,
147 "colorGamutXform",
148 SK_ARRAY_COUNT(gColorGamutXformArgs),
149 gColorGamutXformArgs,
150 functionBody.c_str(),
151 &colorGamutXformFuncName);
152
153 out->appendf("%s(%s, %s)", colorGamutXformFuncName.c_str(), srcColor,
154 colorXformHelper->getXformMatrix());
155}
156
157void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
158 GrGLSLColorSpaceXformHelper* colorXformHelper) {
159 SkString xform;
160 this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
161 this->codeAppend(xform.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700162}
163
cdaltonf8a6ce82016-04-11 13:02:05 -0700164void GrGLSLShaderBuilder::appendTexelFetch(SkString* out,
egdaniel09aa1fc2016-04-20 07:09:46 -0700165 SamplerHandle samplerHandle,
cdaltonf8a6ce82016-04-11 13:02:05 -0700166 const char* coordExpr) const {
egdaniel09aa1fc2016-04-20 07:09:46 -0700167 const GrGLSLSampler& sampler = fProgramBuilder->getSampler(samplerHandle);
cdaltonf8a6ce82016-04-11 13:02:05 -0700168 SkASSERT(fProgramBuilder->glslCaps()->texelFetchSupport());
egdaniel990dbc82016-07-13 14:09:30 -0700169 SkASSERT(GrSLTypeIsCombinedSamplerType(sampler.type()));
cdaltonf8a6ce82016-04-11 13:02:05 -0700170
egdaniel09aa1fc2016-04-20 07:09:46 -0700171 out->appendf("texelFetch(%s, %s)", sampler.getSamplerNameForTexelFetch(), coordExpr);
cdaltonf8a6ce82016-04-11 13:02:05 -0700172
173 this->appendTextureSwizzle(out, sampler.config());
174}
175
egdaniel09aa1fc2016-04-20 07:09:46 -0700176void GrGLSLShaderBuilder::appendTexelFetch(SamplerHandle samplerHandle, const char* coordExpr) {
177 this->appendTexelFetch(&this->code(), samplerHandle, coordExpr);
cdaltonf8a6ce82016-04-11 13:02:05 -0700178}
179
180void GrGLSLShaderBuilder::appendTextureSwizzle(SkString* out, GrPixelConfig config) const {
181 const GrSwizzle& configSwizzle = fProgramBuilder->glslCaps()->configTextureSwizzle(config);
182
183 if (configSwizzle != GrSwizzle::RGBA()) {
184 out->appendf(".%s", configSwizzle.c_str());
185 }
186}
187
cdalton33ad7012016-02-22 07:55:44 -0800188bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
189 if (featureBit & fFeaturesAddedMask) {
190 return false;
joshualitt30ba4362014-08-21 20:18:45 -0700191 }
cdalton33ad7012016-02-22 07:55:44 -0800192 this->extensions().appendf("#extension %s: require\n", extensionName);
193 fFeaturesAddedMask |= featureBit;
194 return true;
joshualitt30ba4362014-08-21 20:18:45 -0700195}
196
egdaniel2d721d32015-11-11 13:06:05 -0800197void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
joshualitt47bb3822014-10-07 16:43:25 -0700198 for (int i = 0; i < vars.count(); ++i) {
egdanielf5294392015-10-21 07:14:17 -0700199 vars[i].appendDecl(fProgramBuilder->glslCaps(), out);
joshualitt47bb3822014-10-07 16:43:25 -0700200 out->append(";\n");
201 }
202}
203
egdaniel2d721d32015-11-11 13:06:05 -0800204void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
egdaniel574a4c12015-11-02 06:22:44 -0800205 SkASSERT(fProgramBuilder->glslCaps()->generation() >= k330_GrGLSLGeneration ||
206 fProgramBuilder->glslCaps()->mustEnableAdvBlendEqs());
cdaltone4017d82015-05-06 11:48:56 -0700207 fLayoutParams[interface].push_back() = param;
208}
209
egdaniel2d721d32015-11-11 13:06:05 -0800210void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
cdaltone4017d82015-05-06 11:48:56 -0700211 static const char* interfaceQualifierNames[] = {
212 "out"
213 };
214
215 for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
216 const SkTArray<SkString>& params = fLayoutParams[interface];
217 if (params.empty()) {
218 continue;
219 }
220 this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
221 for (int i = 1; i < params.count(); ++i) {
222 this->layoutQualifiers().appendf(", %s", params[i].c_str());
223 }
224 this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
225 }
226
egdaniel2d721d32015-11-11 13:06:05 -0800227 GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
cdaltone4017d82015-05-06 11:48:56 -0700228 GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
229}
230
egdaniel2d721d32015-11-11 13:06:05 -0800231void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
joshualitt43466a12015-02-13 17:18:27 -0800232 SkASSERT(!fFinalized);
egdaniel574a4c12015-11-02 06:22:44 -0800233 this->versionDecl() = fProgramBuilder->glslCaps()->versionDeclString();
234 this->compileAndAppendLayoutQualifiers();
egdanielc8a66eb2015-11-02 07:46:25 -0800235 SkASSERT(visibility);
cdalton5e58cee2016-02-11 12:49:47 -0800236 fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
egdaniel574a4c12015-11-02 06:22:44 -0800237 this->appendDecls(fInputs, &this->inputs());
egdaniel574a4c12015-11-02 06:22:44 -0800238 this->appendDecls(fOutputs, &this->outputs());
239 this->onFinalize();
joshualitt43466a12015-02-13 17:18:27 -0800240 // append the 'footer' to code
241 this->code().append("}");
242
243 for (int i = 0; i <= fCodeIndex; i++) {
244 fCompilerStrings[i] = fShaderStrings[i].c_str();
245 fCompilerStringLengths[i] = (int)fShaderStrings[i].size();
246 }
247
joshualitt43466a12015-02-13 17:18:27 -0800248 fFinalized = true;
joshualitt43466a12015-02-13 17:18:27 -0800249}