blob: 28449537e7c68937865f6ec502cd3f4a19e79a17 [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)
bsalomon@google.com777c3aa2012-07-25 20:58:20 +000041 , fUniformManager(uniformManager)
42 , fCurrentStage(kNonStageIdx) {
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000043}
44
tomhudson@google.com52598142012-05-24 17:44:30 +000045void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
46 static const uint32_t kMulByAlphaMask =
47 (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
48 GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
49
50 fSwizzle = "";
51 if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) {
52 GrAssert(!(configFlags &
53 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
54 GrAssert(!(configFlags &
55 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
56 fSwizzle = ".bgra";
57 } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) {
58 GrAssert(!(configFlags & kMulByAlphaMask));
59 GrAssert(!(configFlags &
60 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
61 fSwizzle = ".aaaa";
62 } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) {
63 GrAssert(!(configFlags & kMulByAlphaMask));
64 GrAssert(!(configFlags &
65 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
66 fSwizzle = ".rrrr";
67 }
68}
69
70void GrGLShaderBuilder::computeModulate(const char* fsInColor) {
71 if (NULL != fsInColor) {
72 fModulate.printf(" * %s", fsInColor);
robertphillips@google.come9b3f7d2012-05-30 12:26:39 +000073 } else {
74 fModulate.reset();
tomhudson@google.com52598142012-05-24 17:44:30 +000075 }
76}
77
tomhudson@google.com5440f062012-06-01 15:55:50 +000078void GrGLShaderBuilder::setupTextureAccess(SamplerMode samplerMode,
79 int stageNum) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +000080 SkString retval;
tomhudson@google.com52598142012-05-24 17:44:30 +000081
tomhudson@google.com5440f062012-06-01 15:55:50 +000082 fTexFunc = "texture2D";
83 switch (samplerMode) {
tomhudson@google.com52598142012-05-24 17:44:30 +000084 case kDefault_SamplerMode:
tomhudson@google.com5440f062012-06-01 15:55:50 +000085 GrAssert(fVaryingDims == fCoordDims);
tomhudson@google.com52598142012-05-24 17:44:30 +000086 // Do nothing
87 break;
tomhudson@google.com5440f062012-06-01 15:55:50 +000088 case kProj_SamplerMode:
89 fTexFunc.append("Proj");
90 break;
tomhudson@google.com52598142012-05-24 17:44:30 +000091 case kExplicitDivide_SamplerMode:
92 retval = "inCoord";
tomhudson@google.com5440f062012-06-01 15:55:50 +000093 retval.appendS32(stageNum);
94 fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
tomhudson@google.com52598142012-05-24 17:44:30 +000095 GrGLShaderVar::TypeString
96 (GrSLFloatVectorType(fCoordDims)),
97 retval.c_str(),
98 fSampleCoords.c_str(),
99 GrGLSLVectorNonhomogCoords(fVaryingDims),
100 fSampleCoords.c_str(),
101 GrGLSLVectorHomogCoord(fVaryingDims));
102 fSampleCoords = retval;
103 break;
104 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000105 fComplexCoord = false;
tomhudson@google.com52598142012-05-24 17:44:30 +0000106}
107
108void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
109 const char* coordName) {
110 if (NULL == coordName) {
111 coordName = fSampleCoords.c_str();
112 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000113 fFSCode.appendf("%s(%s, %s)", fTexFunc.c_str(), samplerName, coordName);
tomhudson@google.com52598142012-05-24 17:44:30 +0000114}
115
116void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
117 const char* samplerName) {
118 fFSCode.appendf("\t%s = ", outColor);
119 this->emitTextureLookup(samplerName);
120 fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
121}
122
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000123GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility,
124 GrSLType type,
125 const char* name,
126 int count,
127 const char** outName) {
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.comdbbc4e22012-07-25 17:48:39 +0000133 BuilderUniform& uni = fUniforms.push_back();
bsalomon@google.com032b2212012-07-16 13:36:18 +0000134 UniformHandle h = index_to_handle(fUniforms.count() - 1);
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000135 GR_DEBUGCODE(UniformHandle h2 =)
136 fUniformManager.appendUniform(type, count);
137 // We expect the uniform manager to initially have no uniforms and that all uniforms are added
138 // by this function. Therefore, the handles should match.
139 GrAssert(h2 == h);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000140 uni.fVariable.setType(type);
141 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000142 SkString* uniName = uni.fVariable.accessName();
143 if (kNonStageIdx == fCurrentStage) {
144 uniName->printf("u%s", name);
145 } else {
146 uniName->printf("u%s%d", name, fCurrentStage);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000147 }
bsalomon@google.com032b2212012-07-16 13:36:18 +0000148 uni.fVariable.setArrayCount(count);
149 uni.fVisibility = visibility;
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000150
bsalomon@google.com032b2212012-07-16 13:36:18 +0000151 // If it is visible in both the VS and FS, the precision must match.
152 // We declare a default FS precision, but not a default VS. So set the var
153 // to use the default FS precision.
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000154 if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000155 // the fragment and vertex precisions must match
bsalomon@google.com032b2212012-07-16 13:36:18 +0000156 uni.fVariable.setPrecision(kDefaultFragmentPrecision);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000157 }
158
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000159 if (NULL != outName) {
160 *outName = uni.fVariable.c_str();
161 }
162
bsalomon@google.com032b2212012-07-16 13:36:18 +0000163 return h;
164}
165
166const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const {
167 return fUniforms[handle_to_index(u)].fVariable;
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000168}
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000169
170void GrGLShaderBuilder::addVarying(GrSLType type,
171 const char* name,
172 const char** vsOutName,
173 const char** fsInName) {
174 fVSOutputs.push_back();
175 fVSOutputs.back().setType(type);
176 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
bsalomon@google.com777c3aa2012-07-25 20:58:20 +0000177 if (kNonStageIdx == fCurrentStage) {
178 fVSOutputs.back().accessName()->printf("v%s", name);
179 } else {
180 fVSOutputs.back().accessName()->printf("v%s%d", name, fCurrentStage);
181 }
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000182 if (vsOutName) {
183 *vsOutName = fVSOutputs.back().getName().c_str();
184 }
185 // input to FS comes either from VS or GS
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000186 const SkString* fsName;
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000187 if (fUsesGS) {
188 // if we have a GS take each varying in as an array
189 // and output as non-array.
190 fGSInputs.push_back();
191 fGSInputs.back().setType(type);
192 fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
193 fGSInputs.back().setUnsizedArray();
194 *fGSInputs.back().accessName() = fVSOutputs.back().getName();
195 fGSOutputs.push_back();
196 fGSOutputs.back().setType(type);
197 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
198 fGSOutputs.back().accessName()->printf("g%s", name);
199 fsName = fGSOutputs.back().accessName();
200 } else {
201 fsName = fVSOutputs.back().accessName();
202 }
203 fFSInputs.push_back();
204 fFSInputs.back().setType(type);
205 fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
206 fFSInputs.back().setName(*fsName);
207 if (fsInName) {
208 *fsInName = fsName->c_str();
209 }
210}
211
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000212
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000213namespace {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000214
215inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
216 GrGLBinding binding,
217 SkString* str) {
218 // Desktop GLSL has added precision qualifiers but they don't do anything.
219 if (kES2_GrGLBinding == binding) {
220 switch (p) {
221 case GrGLShaderVar::kHigh_Precision:
222 str->append("precision highp float;\n");
223 break;
224 case GrGLShaderVar::kMedium_Precision:
225 str->append("precision mediump float;\n");
226 break;
227 case GrGLShaderVar::kLow_Precision:
228 str->append("precision lowp float;\n");
229 break;
230 case GrGLShaderVar::kDefault_Precision:
231 GrCrash("Default precision now allowed.");
232 default:
233 GrCrash("Unknown precision value.");
234 }
235 }
236}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000237}
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000238
bsalomon@google.com032b2212012-07-16 13:36:18 +0000239void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000240 for (int i = 0; i < vars.count(); ++i) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000241 vars[i].appendDecl(fContext, out);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000242 }
243}
bsalomon@google.com032b2212012-07-16 13:36:18 +0000244
245void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const {
246 for (int i = 0; i < fUniforms.count(); ++i) {
247 if (fUniforms[i].fVisibility & stype) {
248 fUniforms[i].fVariable.appendDecl(fContext, out);
249 }
250 }
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000251}
252
253void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
254 switch (type) {
255 case kVertex_ShaderType:
256 *shaderStr = fHeader;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000257 this->appendUniformDecls(kVertex_ShaderType, shaderStr);
258 this->appendDecls(fVSAttrs, shaderStr);
259 this->appendDecls(fVSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000260 shaderStr->append(fVSCode);
261 break;
262 case kGeometry_ShaderType:
263 if (fUsesGS) {
264 *shaderStr = fHeader;
265 shaderStr->append(fGSHeader);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000266 this->appendDecls(fGSInputs, shaderStr);
267 this->appendDecls(fGSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000268 shaderStr->append(fGSCode);
269 } else {
270 shaderStr->reset();
271 }
272 break;
273 case kFragment_ShaderType:
274 *shaderStr = fHeader;
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000275 append_default_precision_qualifier(kDefaultFragmentPrecision,
276 fContext.binding(),
277 shaderStr);
bsalomon@google.com032b2212012-07-16 13:36:18 +0000278 this->appendUniformDecls(kFragment_ShaderType, shaderStr);
279 this->appendDecls(fFSInputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000280 // We shouldn't have declared outputs on 1.10
281 GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
bsalomon@google.com032b2212012-07-16 13:36:18 +0000282 this->appendDecls(fFSOutputs, shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000283 shaderStr->append(fFSFunctions);
284 shaderStr->append(fFSCode);
285 break;
286 }
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000287 }
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000288
bsalomon@google.comdbbc4e22012-07-25 17:48:39 +0000289void GrGLShaderBuilder::finished(GrGLuint programID) {
290 fUniformManager.getUniformLocations(programID, fUniforms);
291}