blob: f56f102855c030304781bed2e0007927c01101cc [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"
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000010#include "gl/GrGLUniformHandle.h"
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000011
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000012// number of each input/output type in a single allocation block
bsalomon@google.comeb715c82012-07-11 15:03:31 +000013static const int kVarsPerBlock = 8;
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000014
15// except FS outputs where we expect 2 at most.
bsalomon@google.comeb715c82012-07-11 15:03:31 +000016static const int kMaxFSOutputs = 2;
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000017
bsalomon@google.comd7727ce2012-07-12 16:40:03 +000018// ES2 FS only guarantees mediump and lowp support
19static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
20
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000021typedef GrGLUniformManager::UniformHandle UniformHandle;
22///////////////////////////////////////////////////////////////////////////////
23
tomhudson@google.com9c639a42012-05-14 19:58:06 +000024// Architectural assumption: always 2-d input coords.
25// Likely to become non-constant and non-static, perhaps even
26// varying by stage, if we use 1D textures for gradients!
27//const int GrGLShaderBuilder::fCoordDims = 2;
28
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000029GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx, GrGLUniformManager& uniformManager)
bsalomon@google.com032b2212012-07-16 13:36:18 +000030 : fUniforms(kVarsPerBlock)
bsalomon@google.comeb715c82012-07-11 15:03:31 +000031 , fVSAttrs(kVarsPerBlock)
32 , fVSOutputs(kVarsPerBlock)
33 , fGSInputs(kVarsPerBlock)
34 , fGSOutputs(kVarsPerBlock)
35 , fFSInputs(kVarsPerBlock)
bsalomon@google.comeb715c82012-07-11 15:03:31 +000036 , fFSOutputs(kMaxFSOutputs)
tomhudson@google.com040c41a2012-05-18 14:57:40 +000037 , fUsesGS(false)
tomhudson@google.com9c639a42012-05-14 19:58:06 +000038 , fVaryingDims(0)
bsalomon@google.comad5e9372012-07-11 18:11:27 +000039 , fComplexCoord(false)
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +000040 , fContext(ctx)
41 , fUniformManager(uniformManager) {
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000042}
43
tomhudson@google.com52598142012-05-24 17:44:30 +000044void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
45 static const uint32_t kMulByAlphaMask =
46 (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
47 GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
48
49 fSwizzle = "";
50 if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) {
51 GrAssert(!(configFlags &
52 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
53 GrAssert(!(configFlags &
54 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
55 fSwizzle = ".bgra";
56 } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) {
57 GrAssert(!(configFlags & kMulByAlphaMask));
58 GrAssert(!(configFlags &
59 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
60 fSwizzle = ".aaaa";
61 } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) {
62 GrAssert(!(configFlags & kMulByAlphaMask));
63 GrAssert(!(configFlags &
64 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
65 fSwizzle = ".rrrr";
66 }
67}
68
69void GrGLShaderBuilder::computeModulate(const char* fsInColor) {
70 if (NULL != fsInColor) {
71 fModulate.printf(" * %s", fsInColor);
robertphillips@google.come9b3f7d2012-05-30 12:26:39 +000072 } else {
73 fModulate.reset();
tomhudson@google.com52598142012-05-24 17:44:30 +000074 }
75}
76
tomhudson@google.com5440f062012-06-01 15:55:50 +000077void GrGLShaderBuilder::setupTextureAccess(SamplerMode samplerMode,
78 int stageNum) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +000079 SkString retval;
tomhudson@google.com52598142012-05-24 17:44:30 +000080
tomhudson@google.com5440f062012-06-01 15:55:50 +000081 fTexFunc = "texture2D";
82 switch (samplerMode) {
tomhudson@google.com52598142012-05-24 17:44:30 +000083 case kDefault_SamplerMode:
tomhudson@google.com5440f062012-06-01 15:55:50 +000084 GrAssert(fVaryingDims == fCoordDims);
tomhudson@google.com52598142012-05-24 17:44:30 +000085 // Do nothing
86 break;
tomhudson@google.com5440f062012-06-01 15:55:50 +000087 case kProj_SamplerMode:
88 fTexFunc.append("Proj");
89 break;
tomhudson@google.com52598142012-05-24 17:44:30 +000090 case kExplicitDivide_SamplerMode:
91 retval = "inCoord";
tomhudson@google.com5440f062012-06-01 15:55:50 +000092 retval.appendS32(stageNum);
93 fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
tomhudson@google.com52598142012-05-24 17:44:30 +000094 GrGLShaderVar::TypeString
95 (GrSLFloatVectorType(fCoordDims)),
96 retval.c_str(),
97 fSampleCoords.c_str(),
98 GrGLSLVectorNonhomogCoords(fVaryingDims),
99 fSampleCoords.c_str(),
100 GrGLSLVectorHomogCoord(fVaryingDims));
101 fSampleCoords = retval;
102 break;
103 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000104 fComplexCoord = false;
tomhudson@google.com52598142012-05-24 17:44:30 +0000105}
106
107void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
108 const char* coordName) {
109 if (NULL == coordName) {
110 coordName = fSampleCoords.c_str();
111 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000112 fFSCode.appendf("%s(%s, %s)", fTexFunc.c_str(), samplerName, coordName);
tomhudson@google.com52598142012-05-24 17:44:30 +0000113}
114
115void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
116 const char* samplerName) {
117 fFSCode.appendf("\t%s = ", outColor);
118 this->emitTextureLookup(samplerName);
119 fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
120}
121
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000122GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniform(uint32_t visibility,
123 GrSLType type,
124 const char* name,
125 int stageNum,
126 int count) {
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000127 GrAssert(name && strlen(name));
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000128 static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType;
129 GrAssert(0 == (~kVisibilityMask & visibility));
130 GrAssert(0 != visibility);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000131
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000132 BuilderUniform& uni = fUniforms.push_back();
bsalomon@google.com032b2212012-07-16 13:36:18 +0000133 UniformHandle h = index_to_handle(fUniforms.count() - 1);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000134 GR_DEBUGCODE(UniformHandle h2 =)
135 fUniformManager.appendUniform(type, count);
136 // We expect the uniform manager to initially have no uniforms and that all uniforms are added
137 // by this function. Therefore, the handles should match.
138 GrAssert(h2 == h);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000139 uni.fVariable.setType(type);
140 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
141 uni.fVariable.setName(name);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000142 if (stageNum >= 0) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000143 uni.fVariable.accessName()->appendS32(stageNum);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000144 }
bsalomon@google.com032b2212012-07-16 13:36:18 +0000145 uni.fVariable.setArrayCount(count);
146 uni.fVisibility = visibility;
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000147
bsalomon@google.com032b2212012-07-16 13:36:18 +0000148 // If it is visible in both the VS and FS, the precision must match.
149 // We declare a default FS precision, but not a default VS. So set the var
150 // to use the default FS precision.
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000151 if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000152 // the fragment and vertex precisions must match
bsalomon@google.com032b2212012-07-16 13:36:18 +0000153 uni.fVariable.setPrecision(kDefaultFragmentPrecision);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000154 }
155
bsalomon@google.com032b2212012-07-16 13:36:18 +0000156 return h;
157}
158
159const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const {
160 return fUniforms[handle_to_index(u)].fVariable;
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000161}
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000162
163void GrGLShaderBuilder::addVarying(GrSLType type,
164 const char* name,
165 const char** vsOutName,
166 const char** fsInName) {
167 fVSOutputs.push_back();
168 fVSOutputs.back().setType(type);
169 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
170 fVSOutputs.back().accessName()->printf("v%s", name);
171 if (vsOutName) {
172 *vsOutName = fVSOutputs.back().getName().c_str();
173 }
174 // input to FS comes either from VS or GS
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000175 const SkString* fsName;
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000176 if (fUsesGS) {
177 // if we have a GS take each varying in as an array
178 // and output as non-array.
179 fGSInputs.push_back();
180 fGSInputs.back().setType(type);
181 fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
182 fGSInputs.back().setUnsizedArray();
183 *fGSInputs.back().accessName() = fVSOutputs.back().getName();
184 fGSOutputs.push_back();
185 fGSOutputs.back().setType(type);
186 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
187 fGSOutputs.back().accessName()->printf("g%s", name);
188 fsName = fGSOutputs.back().accessName();
189 } else {
190 fsName = fVSOutputs.back().accessName();
191 }
192 fFSInputs.push_back();
193 fFSInputs.back().setType(type);
194 fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
195 fFSInputs.back().setName(*fsName);
196 if (fsInName) {
197 *fsInName = fsName->c_str();
198 }
199}
200
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000201void GrGLShaderBuilder::addVarying(GrSLType type,
202 const char* name,
203 int stageNum,
204 const char** vsOutName,
205 const char** fsInName) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000206 SkString nameWithStage(name);
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000207 nameWithStage.appendS32(stageNum);
208 this->addVarying(type, nameWithStage.c_str(), vsOutName, fsInName);
209}
210
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000211namespace {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000212
213inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
214 GrGLBinding binding,
215 SkString* str) {
216 // Desktop GLSL has added precision qualifiers but they don't do anything.
217 if (kES2_GrGLBinding == binding) {
218 switch (p) {
219 case GrGLShaderVar::kHigh_Precision:
220 str->append("precision highp float;\n");
221 break;
222 case GrGLShaderVar::kMedium_Precision:
223 str->append("precision mediump float;\n");
224 break;
225 case GrGLShaderVar::kLow_Precision:
226 str->append("precision lowp float;\n");
227 break;
228 case GrGLShaderVar::kDefault_Precision:
229 GrCrash("Default precision now allowed.");
230 default:
231 GrCrash("Unknown precision value.");
232 }
233 }
234}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000235}
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000236
bsalomon@google.com032b2212012-07-16 13:36:18 +0000237void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000238 for (int i = 0; i < vars.count(); ++i) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000239 vars[i].appendDecl(fContext, out);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000240 }
241}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000242
243void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const {
244 for (int i = 0; i < fUniforms.count(); ++i) {
245 if (fUniforms[i].fVisibility & stype) {
246 fUniforms[i].fVariable.appendDecl(fContext, out);
247 }
248 }
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000249}
250
251void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
252 switch (type) {
253 case kVertex_ShaderType:
254 *shaderStr = fHeader;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000255 this->appendUniformDecls(kVertex_ShaderType, shaderStr);
256 this->appendDecls(fVSAttrs, shaderStr);
257 this->appendDecls(fVSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000258 shaderStr->append(fVSCode);
259 break;
260 case kGeometry_ShaderType:
261 if (fUsesGS) {
262 *shaderStr = fHeader;
263 shaderStr->append(fGSHeader);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000264 this->appendDecls(fGSInputs, shaderStr);
265 this->appendDecls(fGSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000266 shaderStr->append(fGSCode);
267 } else {
268 shaderStr->reset();
269 }
270 break;
271 case kFragment_ShaderType:
272 *shaderStr = fHeader;
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000273 append_default_precision_qualifier(kDefaultFragmentPrecision,
274 fContext.binding(),
275 shaderStr);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000276 this->appendUniformDecls(kFragment_ShaderType, shaderStr);
277 this->appendDecls(fFSInputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000278 // We shouldn't have declared outputs on 1.10
279 GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
bsalomon@google.com032b2212012-07-16 13:36:18 +0000280 this->appendDecls(fFSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000281 shaderStr->append(fFSFunctions);
282 shaderStr->append(fFSCode);
283 break;
284 }
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000285 }
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000286
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000287void GrGLShaderBuilder::finished(GrGLuint programID) {
288 fUniformManager.getUniformLocations(programID, fUniforms);
289}