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 "GrShaderVar.h"
9 #include "GrShaderCaps.h"
10 #include "GrSwizzle.h"
11 #include "glsl/GrGLSLShaderBuilder.h"
12 #include "glsl/GrGLSLColorSpaceXformHelper.h"
13 #include "glsl/GrGLSLProgramBuilder.h"
14
GrGLSLShaderBuilder(GrGLSLProgramBuilder * program)15 GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
16 : fProgramBuilder(program)
17 , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
18 , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
19 , 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();
25 fCompilerStrings.push_back(nullptr);
26 fCompilerStringLengths.push_back(0);
27 }
28
29 this->main() = "void main() {";
30 }
31
declAppend(const GrShaderVar & var)32 void GrGLSLShaderBuilder::declAppend(const GrShaderVar& var) {
33 SkString tempDecl;
34 var.appendDecl(fProgramBuilder->shaderCaps(), &tempDecl);
35 this->codeAppendf("%s;", tempDecl.c_str());
36 }
37
declareGlobal(const GrShaderVar & v)38 void GrGLSLShaderBuilder::declareGlobal(const GrShaderVar& v) {
39 v.appendDecl(this->getProgramBuilder()->shaderCaps(), &this->definitions());
40 this->definitions().append(";");
41 }
42
emitFunction(GrSLType returnType,const char * name,int argCnt,const GrShaderVar * args,const char * body,SkString * outName)43 void GrGLSLShaderBuilder::emitFunction(GrSLType returnType,
44 const char* name,
45 int argCnt,
46 const GrShaderVar* args,
47 const char* body,
48 SkString* outName) {
49 this->functions().append(GrGLSLTypeString(returnType));
50 fProgramBuilder->nameVariable(outName, '\0', name);
51 this->functions().appendf(" %s", outName->c_str());
52 this->functions().append("(");
53 for (int i = 0; i < argCnt; ++i) {
54 args[i].appendDecl(fProgramBuilder->shaderCaps(), &this->functions());
55 if (i < argCnt - 1) {
56 this->functions().append(", ");
57 }
58 }
59 this->functions().append(") {\n");
60 this->functions().append(body);
61 this->functions().append("}\n\n");
62 }
63
append_texture_swizzle(SkString * out,GrSwizzle swizzle)64 static inline void append_texture_swizzle(SkString* out, GrSwizzle swizzle) {
65 if (swizzle != GrSwizzle::RGBA()) {
66 out->appendf(".%s", swizzle.c_str());
67 }
68 }
69
appendTextureLookup(SkString * out,SamplerHandle samplerHandle,const char * coordName,GrSLType varyingType) const70 void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
71 SamplerHandle samplerHandle,
72 const char* coordName,
73 GrSLType varyingType) const {
74 const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
75 GrSLType samplerType = sampler.getType();
76 if (samplerType == kTexture2DRectSampler_GrSLType) {
77 if (varyingType == kVec2f_GrSLType) {
78 out->appendf("texture(%s, textureSize(%s) * %s)",
79 sampler.c_str(), sampler.c_str(), coordName);
80 } else {
81 out->appendf("texture(%s, vec3(textureSize(%s) * %s.xy, %s.z))",
82 sampler.c_str(), sampler.c_str(), coordName, coordName);
83 }
84 } else {
85 out->appendf("texture(%s, %s)", sampler.c_str(), coordName);
86 }
87 append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
88 }
89
appendTextureLookup(SamplerHandle samplerHandle,const char * coordName,GrSLType varyingType,GrGLSLColorSpaceXformHelper * colorXformHelper)90 void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
91 const char* coordName,
92 GrSLType varyingType,
93 GrGLSLColorSpaceXformHelper* colorXformHelper) {
94 if (colorXformHelper && colorXformHelper->isValid()) {
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 }
102 }
103
appendTextureLookupAndModulate(const char * modulation,SamplerHandle samplerHandle,const char * coordName,GrSLType varyingType,GrGLSLColorSpaceXformHelper * colorXformHelper)104 void GrGLSLShaderBuilder::appendTextureLookupAndModulate(
105 const char* modulation,
106 SamplerHandle samplerHandle,
107 const char* coordName,
108 GrSLType varyingType,
109 GrGLSLColorSpaceXformHelper* colorXformHelper) {
110 SkString lookup;
111 this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
112 if (colorXformHelper && colorXformHelper->isValid()) {
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
appendColorGamutXform(SkString * out,const char * srcColor,GrGLSLColorSpaceXformHelper * colorXformHelper)121 void 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
126 // "texture(...)", and we don't want to evaluate that twice, so wrap everything in a function.
127 static const GrShaderVar gColorGamutXformArgs[] = {
128 GrShaderVar("color", kVec4f_GrSLType),
129 GrShaderVar("xform", kMat44f_GrSLType),
130 };
131 SkString functionBody;
132 // 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");
135 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 GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
145 out->appendf("%s(%s, %s)", colorGamutXformFuncName.c_str(), srcColor,
146 uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform()));
147 }
148
appendColorGamutXform(const char * srcColor,GrGLSLColorSpaceXformHelper * colorXformHelper)149 void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
150 GrGLSLColorSpaceXformHelper* colorXformHelper) {
151 SkString xform;
152 this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
153 this->codeAppend(xform.c_str());
154 }
155
appendTexelFetch(SkString * out,SamplerHandle samplerHandle,const char * coordExpr) const156 void GrGLSLShaderBuilder::appendTexelFetch(SkString* out,
157 SamplerHandle samplerHandle,
158 const char* coordExpr) const {
159 const GrShaderVar& sampler = fProgramBuilder->samplerVariable(samplerHandle);
160 SkASSERT(fProgramBuilder->shaderCaps()->texelFetchSupport());
161 SkASSERT(GrSLTypeIsCombinedSamplerType(sampler.getType()));
162
163 out->appendf("texelFetch(%s, %s)", sampler.c_str(), coordExpr);
164
165 append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
166 }
167
appendTexelFetch(SamplerHandle samplerHandle,const char * coordExpr)168 void GrGLSLShaderBuilder::appendTexelFetch(SamplerHandle samplerHandle, const char* coordExpr) {
169 this->appendTexelFetch(&this->code(), samplerHandle, coordExpr);
170 }
171
appendImageStorageLoad(SkString * out,ImageStorageHandle handle,const char * coordExpr)172 void GrGLSLShaderBuilder::appendImageStorageLoad(SkString* out, ImageStorageHandle handle,
173 const char* coordExpr) {
174 const GrShaderVar& imageStorage = fProgramBuilder->imageStorageVariable(handle);
175 out->appendf("imageLoad(%s, %s)", imageStorage.c_str(), coordExpr);
176 }
177
appendImageStorageLoad(ImageStorageHandle handle,const char * coordExpr)178 void GrGLSLShaderBuilder::appendImageStorageLoad(ImageStorageHandle handle, const char* coordExpr) {
179 this->appendImageStorageLoad(&this->code(), handle, coordExpr);
180 }
181
addFeature(uint32_t featureBit,const char * extensionName)182 bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
183 if (featureBit & fFeaturesAddedMask) {
184 return false;
185 }
186 this->extensions().appendf("#extension %s: require\n", extensionName);
187 fFeaturesAddedMask |= featureBit;
188 return true;
189 }
190
appendDecls(const VarArray & vars,SkString * out) const191 void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
192 for (int i = 0; i < vars.count(); ++i) {
193 vars[i].appendDecl(fProgramBuilder->shaderCaps(), out);
194 out->append(";\n");
195 }
196 }
197
addLayoutQualifier(const char * param,InterfaceQualifier interface)198 void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
199 SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration ||
200 fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
201 fLayoutParams[interface].push_back() = param;
202 }
203
compileAndAppendLayoutQualifiers()204 void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
205 static const char* interfaceQualifierNames[] = {
206 "in",
207 "out"
208 };
209
210 for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
211 const SkTArray<SkString>& params = fLayoutParams[interface];
212 if (params.empty()) {
213 continue;
214 }
215 this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
216 for (int i = 1; i < params.count(); ++i) {
217 this->layoutQualifiers().appendf(", %s", params[i].c_str());
218 }
219 this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
220 }
221
222 GR_STATIC_ASSERT(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
223 GR_STATIC_ASSERT(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
224 GR_STATIC_ASSERT(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
225 }
226
finalize(uint32_t visibility)227 void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
228 SkASSERT(!fFinalized);
229 this->versionDecl() = fProgramBuilder->shaderCaps()->versionDeclString();
230 this->compileAndAppendLayoutQualifiers();
231 SkASSERT(visibility);
232 fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
233 this->appendDecls(fInputs, &this->inputs());
234 this->appendDecls(fOutputs, &this->outputs());
235 this->onFinalize();
236 // append the 'footer' to code
237 this->code().append("}");
238
239 for (int i = 0; i <= fCodeIndex; i++) {
240 fCompilerStrings[i] = fShaderStrings[i].c_str();
241 fCompilerStringLengths[i] = (int)fShaderStrings[i].size();
242 }
243
244 fFinalized = true;
245 }
246