blob: 7fa804a7e53716406492212663463d2bd3bb55d5 [file] [log] [blame]
tomhudson@google.comf9ad8862012-05-11 20:38:48 +00001/*
2 * Copyright 2012 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 "gl/GrGLShaderBuilder.h"
tomhudson@google.com52598142012-05-24 17:44:30 +00009#include "gl/GrGLProgram.h"
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000010
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000011// number of each input/output type in a single allocation block
bsalomon@google.comeb715c82012-07-11 15:03:31 +000012static const int kVarsPerBlock = 8;
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000013
14// except FS outputs where we expect 2 at most.
bsalomon@google.comeb715c82012-07-11 15:03:31 +000015static const int kMaxFSOutputs = 2;
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000016
bsalomon@google.comd7727ce2012-07-12 16:40:03 +000017// ES2 FS only guarantees mediump and lowp support
18static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
19
tomhudson@google.com9c639a42012-05-14 19:58:06 +000020// Architectural assumption: always 2-d input coords.
21// Likely to become non-constant and non-static, perhaps even
22// varying by stage, if we use 1D textures for gradients!
23//const int GrGLShaderBuilder::fCoordDims = 2;
24
bsalomon@google.comad5e9372012-07-11 18:11:27 +000025GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx)
bsalomon@google.com032b2212012-07-16 13:36:18 +000026 : fUniforms(kVarsPerBlock)
bsalomon@google.comeb715c82012-07-11 15:03:31 +000027 , fVSAttrs(kVarsPerBlock)
28 , fVSOutputs(kVarsPerBlock)
29 , fGSInputs(kVarsPerBlock)
30 , fGSOutputs(kVarsPerBlock)
31 , fFSInputs(kVarsPerBlock)
bsalomon@google.comeb715c82012-07-11 15:03:31 +000032 , fFSOutputs(kMaxFSOutputs)
tomhudson@google.com040c41a2012-05-18 14:57:40 +000033 , fUsesGS(false)
tomhudson@google.com9c639a42012-05-14 19:58:06 +000034 , fVaryingDims(0)
bsalomon@google.comad5e9372012-07-11 18:11:27 +000035 , fComplexCoord(false)
36 , fContext(ctx) {
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000037
38}
39
tomhudson@google.com52598142012-05-24 17:44:30 +000040void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
41 static const uint32_t kMulByAlphaMask =
42 (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
43 GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
44
45 fSwizzle = "";
46 if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) {
47 GrAssert(!(configFlags &
48 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
49 GrAssert(!(configFlags &
50 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
51 fSwizzle = ".bgra";
52 } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) {
53 GrAssert(!(configFlags & kMulByAlphaMask));
54 GrAssert(!(configFlags &
55 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
56 fSwizzle = ".aaaa";
57 } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) {
58 GrAssert(!(configFlags & kMulByAlphaMask));
59 GrAssert(!(configFlags &
60 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
61 fSwizzle = ".rrrr";
62 }
63}
64
65void GrGLShaderBuilder::computeModulate(const char* fsInColor) {
66 if (NULL != fsInColor) {
67 fModulate.printf(" * %s", fsInColor);
robertphillips@google.come9b3f7d2012-05-30 12:26:39 +000068 } else {
69 fModulate.reset();
tomhudson@google.com52598142012-05-24 17:44:30 +000070 }
71}
72
tomhudson@google.com5440f062012-06-01 15:55:50 +000073void GrGLShaderBuilder::setupTextureAccess(SamplerMode samplerMode,
74 int stageNum) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +000075 SkString retval;
tomhudson@google.com52598142012-05-24 17:44:30 +000076
tomhudson@google.com5440f062012-06-01 15:55:50 +000077 fTexFunc = "texture2D";
78 switch (samplerMode) {
tomhudson@google.com52598142012-05-24 17:44:30 +000079 case kDefault_SamplerMode:
tomhudson@google.com5440f062012-06-01 15:55:50 +000080 GrAssert(fVaryingDims == fCoordDims);
tomhudson@google.com52598142012-05-24 17:44:30 +000081 // Do nothing
82 break;
tomhudson@google.com5440f062012-06-01 15:55:50 +000083 case kProj_SamplerMode:
84 fTexFunc.append("Proj");
85 break;
tomhudson@google.com52598142012-05-24 17:44:30 +000086 case kExplicitDivide_SamplerMode:
87 retval = "inCoord";
tomhudson@google.com5440f062012-06-01 15:55:50 +000088 retval.appendS32(stageNum);
89 fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
tomhudson@google.com52598142012-05-24 17:44:30 +000090 GrGLShaderVar::TypeString
91 (GrSLFloatVectorType(fCoordDims)),
92 retval.c_str(),
93 fSampleCoords.c_str(),
94 GrGLSLVectorNonhomogCoords(fVaryingDims),
95 fSampleCoords.c_str(),
96 GrGLSLVectorHomogCoord(fVaryingDims));
97 fSampleCoords = retval;
98 break;
99 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000100 fComplexCoord = false;
tomhudson@google.com52598142012-05-24 17:44:30 +0000101}
102
103void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
104 const char* coordName) {
105 if (NULL == coordName) {
106 coordName = fSampleCoords.c_str();
107 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000108 fFSCode.appendf("%s(%s, %s)", fTexFunc.c_str(), samplerName, coordName);
tomhudson@google.com52598142012-05-24 17:44:30 +0000109}
110
111void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
112 const char* samplerName) {
113 fFSCode.appendf("\t%s = ", outColor);
114 this->emitTextureLookup(samplerName);
115 fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
116}
117
bsalomon@google.com032b2212012-07-16 13:36:18 +0000118namespace {
119inline int handle_to_index(GrGLShaderBuilder::UniformHandle h) { return ~h; }
120inline GrGLShaderBuilder::UniformHandle index_to_handle(int i) { return ~i; }
121}
122
123GrGLShaderBuilder::UniformHandle GrGLShaderBuilder::addUniform(uint32_t visibility,
124 GrSLType type,
125 const char* name,
126 int stageNum,
127 int count) {
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000128 GrAssert(name && strlen(name));
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000129 static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType;
130 GrAssert(0 == (~kVisibilityMask & visibility));
131 GrAssert(0 != visibility);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000132
bsalomon@google.com032b2212012-07-16 13:36:18 +0000133 Uniform& uni = fUniforms.push_back();
134 UniformHandle h = index_to_handle(fUniforms.count() - 1);
135 uni.fVariable.setType(type);
136 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
137 uni.fVariable.setName(name);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000138 if (stageNum >= 0) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000139 uni.fVariable.accessName()->appendS32(stageNum);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000140 }
bsalomon@google.com032b2212012-07-16 13:36:18 +0000141 uni.fVariable.setArrayCount(count);
142 uni.fVisibility = visibility;
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000143
bsalomon@google.com032b2212012-07-16 13:36:18 +0000144 // If it is visible in both the VS and FS, the precision must match.
145 // We declare a default FS precision, but not a default VS. So set the var
146 // to use the default FS precision.
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000147 if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000148 // the fragment and vertex precisions must match
bsalomon@google.com032b2212012-07-16 13:36:18 +0000149 uni.fVariable.setPrecision(kDefaultFragmentPrecision);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000150 }
151
bsalomon@google.com032b2212012-07-16 13:36:18 +0000152 return h;
153}
154
155const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const {
156 return fUniforms[handle_to_index(u)].fVariable;
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000157}
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000158
159void GrGLShaderBuilder::addVarying(GrSLType type,
160 const char* name,
161 const char** vsOutName,
162 const char** fsInName) {
163 fVSOutputs.push_back();
164 fVSOutputs.back().setType(type);
165 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
166 fVSOutputs.back().accessName()->printf("v%s", name);
167 if (vsOutName) {
168 *vsOutName = fVSOutputs.back().getName().c_str();
169 }
170 // input to FS comes either from VS or GS
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000171 const SkString* fsName;
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000172 if (fUsesGS) {
173 // if we have a GS take each varying in as an array
174 // and output as non-array.
175 fGSInputs.push_back();
176 fGSInputs.back().setType(type);
177 fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
178 fGSInputs.back().setUnsizedArray();
179 *fGSInputs.back().accessName() = fVSOutputs.back().getName();
180 fGSOutputs.push_back();
181 fGSOutputs.back().setType(type);
182 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
183 fGSOutputs.back().accessName()->printf("g%s", name);
184 fsName = fGSOutputs.back().accessName();
185 } else {
186 fsName = fVSOutputs.back().accessName();
187 }
188 fFSInputs.push_back();
189 fFSInputs.back().setType(type);
190 fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
191 fFSInputs.back().setName(*fsName);
192 if (fsInName) {
193 *fsInName = fsName->c_str();
194 }
195}
196
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000197void GrGLShaderBuilder::addVarying(GrSLType type,
198 const char* name,
199 int stageNum,
200 const char** vsOutName,
201 const char** fsInName) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000202 SkString nameWithStage(name);
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000203 nameWithStage.appendS32(stageNum);
204 this->addVarying(type, nameWithStage.c_str(), vsOutName, fsInName);
205}
206
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000207namespace {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000208
209inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
210 GrGLBinding binding,
211 SkString* str) {
212 // Desktop GLSL has added precision qualifiers but they don't do anything.
213 if (kES2_GrGLBinding == binding) {
214 switch (p) {
215 case GrGLShaderVar::kHigh_Precision:
216 str->append("precision highp float;\n");
217 break;
218 case GrGLShaderVar::kMedium_Precision:
219 str->append("precision mediump float;\n");
220 break;
221 case GrGLShaderVar::kLow_Precision:
222 str->append("precision lowp float;\n");
223 break;
224 case GrGLShaderVar::kDefault_Precision:
225 GrCrash("Default precision now allowed.");
226 default:
227 GrCrash("Unknown precision value.");
228 }
229 }
230}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000231}
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000232
bsalomon@google.com032b2212012-07-16 13:36:18 +0000233void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000234 for (int i = 0; i < vars.count(); ++i) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000235 vars[i].appendDecl(fContext, out);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000236 }
237}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000238
239void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const {
240 for (int i = 0; i < fUniforms.count(); ++i) {
241 if (fUniforms[i].fVisibility & stype) {
242 fUniforms[i].fVariable.appendDecl(fContext, out);
243 }
244 }
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000245}
246
247void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
248 switch (type) {
249 case kVertex_ShaderType:
250 *shaderStr = fHeader;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000251 this->appendUniformDecls(kVertex_ShaderType, shaderStr);
252 this->appendDecls(fVSAttrs, shaderStr);
253 this->appendDecls(fVSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000254 shaderStr->append(fVSCode);
255 break;
256 case kGeometry_ShaderType:
257 if (fUsesGS) {
258 *shaderStr = fHeader;
259 shaderStr->append(fGSHeader);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000260 this->appendDecls(fGSInputs, shaderStr);
261 this->appendDecls(fGSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000262 shaderStr->append(fGSCode);
263 } else {
264 shaderStr->reset();
265 }
266 break;
267 case kFragment_ShaderType:
268 *shaderStr = fHeader;
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000269 append_default_precision_qualifier(kDefaultFragmentPrecision,
270 fContext.binding(),
271 shaderStr);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000272 this->appendUniformDecls(kFragment_ShaderType, shaderStr);
273 this->appendDecls(fFSInputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000274 // We shouldn't have declared outputs on 1.10
275 GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
bsalomon@google.com032b2212012-07-16 13:36:18 +0000276 this->appendDecls(fFSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000277 shaderStr->append(fFSFunctions);
278 shaderStr->append(fFSCode);
279 break;
280 }
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000281 }
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000282