blob: 3303bf2729254bf7c25e587dec0bae5ad67e1f14 [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.comeb715c82012-07-11 15:03:31 +000026 : fVSUnis(kVarsPerBlock)
27 , fVSAttrs(kVarsPerBlock)
28 , fVSOutputs(kVarsPerBlock)
29 , fGSInputs(kVarsPerBlock)
30 , fGSOutputs(kVarsPerBlock)
31 , fFSInputs(kVarsPerBlock)
32 , fFSUnis(kVarsPerBlock)
33 , fFSOutputs(kMaxFSOutputs)
tomhudson@google.com040c41a2012-05-18 14:57:40 +000034 , fUsesGS(false)
tomhudson@google.com9c639a42012-05-14 19:58:06 +000035 , fVaryingDims(0)
bsalomon@google.comad5e9372012-07-11 18:11:27 +000036 , fComplexCoord(false)
37 , fContext(ctx) {
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000038
39}
40
tomhudson@google.com52598142012-05-24 17:44:30 +000041void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
42 static const uint32_t kMulByAlphaMask =
43 (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
44 GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
45
46 fSwizzle = "";
47 if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) {
48 GrAssert(!(configFlags &
49 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
50 GrAssert(!(configFlags &
51 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
52 fSwizzle = ".bgra";
53 } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) {
54 GrAssert(!(configFlags & kMulByAlphaMask));
55 GrAssert(!(configFlags &
56 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
57 fSwizzle = ".aaaa";
58 } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) {
59 GrAssert(!(configFlags & kMulByAlphaMask));
60 GrAssert(!(configFlags &
61 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
62 fSwizzle = ".rrrr";
63 }
64}
65
66void GrGLShaderBuilder::computeModulate(const char* fsInColor) {
67 if (NULL != fsInColor) {
68 fModulate.printf(" * %s", fsInColor);
robertphillips@google.come9b3f7d2012-05-30 12:26:39 +000069 } else {
70 fModulate.reset();
tomhudson@google.com52598142012-05-24 17:44:30 +000071 }
72}
73
tomhudson@google.com5440f062012-06-01 15:55:50 +000074void GrGLShaderBuilder::setupTextureAccess(SamplerMode samplerMode,
75 int stageNum) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +000076 SkString retval;
tomhudson@google.com52598142012-05-24 17:44:30 +000077
tomhudson@google.com5440f062012-06-01 15:55:50 +000078 fTexFunc = "texture2D";
79 switch (samplerMode) {
tomhudson@google.com52598142012-05-24 17:44:30 +000080 case kDefault_SamplerMode:
tomhudson@google.com5440f062012-06-01 15:55:50 +000081 GrAssert(fVaryingDims == fCoordDims);
tomhudson@google.com52598142012-05-24 17:44:30 +000082 // Do nothing
83 break;
tomhudson@google.com5440f062012-06-01 15:55:50 +000084 case kProj_SamplerMode:
85 fTexFunc.append("Proj");
86 break;
tomhudson@google.com52598142012-05-24 17:44:30 +000087 case kExplicitDivide_SamplerMode:
88 retval = "inCoord";
tomhudson@google.com5440f062012-06-01 15:55:50 +000089 retval.appendS32(stageNum);
90 fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
tomhudson@google.com52598142012-05-24 17:44:30 +000091 GrGLShaderVar::TypeString
92 (GrSLFloatVectorType(fCoordDims)),
93 retval.c_str(),
94 fSampleCoords.c_str(),
95 GrGLSLVectorNonhomogCoords(fVaryingDims),
96 fSampleCoords.c_str(),
97 GrGLSLVectorHomogCoord(fVaryingDims));
98 fSampleCoords = retval;
99 break;
100 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000101 fComplexCoord = false;
tomhudson@google.com52598142012-05-24 17:44:30 +0000102}
103
104void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
105 const char* coordName) {
106 if (NULL == coordName) {
107 coordName = fSampleCoords.c_str();
108 }
tomhudson@google.com5440f062012-06-01 15:55:50 +0000109 fFSCode.appendf("%s(%s, %s)", fTexFunc.c_str(), samplerName, coordName);
tomhudson@google.com52598142012-05-24 17:44:30 +0000110}
111
112void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
113 const char* samplerName) {
114 fFSCode.appendf("\t%s = ", outColor);
115 this->emitTextureLookup(samplerName);
116 fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
117}
118
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000119const GrGLShaderVar& GrGLShaderBuilder::addUniform(uint32_t visibility,
120 GrSLType type,
121 const char* name,
122 int stageNum,
123 int count) {
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000124 GrAssert(name && strlen(name));
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000125 static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType;
126 GrAssert(0 == (~kVisibilityMask & visibility));
127 GrAssert(0 != visibility);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000128
129 GrGLShaderVar* var = NULL;
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000130 if (kVertex_ShaderType & visibility) {
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000131 var = &fVSUnis.push_back();
132 } else {
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000133 GrAssert(kFragment_ShaderType & visibility);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000134 var = &fFSUnis.push_back();
135 }
136 var->setType(type);
137 var->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
138 var->setName(name);
139 if (stageNum >= 0) {
140 var->accessName()->appendS32(stageNum);
141 }
142 var->setArrayCount(count);
143
bsalomon@google.comeb715c82012-07-11 15:03:31 +0000144 if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000145 // the fragment and vertex precisions must match
146 var->setPrecision(kDefaultFragmentPrecision);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000147 fFSUnis.push_back(*var);
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000148 }
149
150 return *var;
151}
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000152
153void GrGLShaderBuilder::addVarying(GrSLType type,
154 const char* name,
155 const char** vsOutName,
156 const char** fsInName) {
157 fVSOutputs.push_back();
158 fVSOutputs.back().setType(type);
159 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
160 fVSOutputs.back().accessName()->printf("v%s", name);
161 if (vsOutName) {
162 *vsOutName = fVSOutputs.back().getName().c_str();
163 }
164 // input to FS comes either from VS or GS
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000165 const SkString* fsName;
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000166 if (fUsesGS) {
167 // if we have a GS take each varying in as an array
168 // and output as non-array.
169 fGSInputs.push_back();
170 fGSInputs.back().setType(type);
171 fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
172 fGSInputs.back().setUnsizedArray();
173 *fGSInputs.back().accessName() = fVSOutputs.back().getName();
174 fGSOutputs.push_back();
175 fGSOutputs.back().setType(type);
176 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
177 fGSOutputs.back().accessName()->printf("g%s", name);
178 fsName = fGSOutputs.back().accessName();
179 } else {
180 fsName = fVSOutputs.back().accessName();
181 }
182 fFSInputs.push_back();
183 fFSInputs.back().setType(type);
184 fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
185 fFSInputs.back().setName(*fsName);
186 if (fsInName) {
187 *fsInName = fsName->c_str();
188 }
189}
190
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000191void GrGLShaderBuilder::addVarying(GrSLType type,
192 const char* name,
193 int stageNum,
194 const char** vsOutName,
195 const char** fsInName) {
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000196 SkString nameWithStage(name);
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000197 nameWithStage.appendS32(stageNum);
198 this->addVarying(type, nameWithStage.c_str(), vsOutName, fsInName);
199}
200
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000201namespace {
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000202
203inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
204 GrGLBinding binding,
205 SkString* str) {
206 // Desktop GLSL has added precision qualifiers but they don't do anything.
207 if (kES2_GrGLBinding == binding) {
208 switch (p) {
209 case GrGLShaderVar::kHigh_Precision:
210 str->append("precision highp float;\n");
211 break;
212 case GrGLShaderVar::kMedium_Precision:
213 str->append("precision mediump float;\n");
214 break;
215 case GrGLShaderVar::kLow_Precision:
216 str->append("precision lowp float;\n");
217 break;
218 case GrGLShaderVar::kDefault_Precision:
219 GrCrash("Default precision now allowed.");
220 default:
221 GrCrash("Unknown precision value.");
222 }
223 }
224}
225
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000226void append_decls(const GrGLShaderBuilder::VarArray& vars,
227 const GrGLContextInfo& ctx,
228 SkString* string) {
229 for (int i = 0; i < vars.count(); ++i) {
230 vars[i].appendDecl(ctx, string);
231 }
232}
233}
234
235void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
236 switch (type) {
237 case kVertex_ShaderType:
238 *shaderStr = fHeader;
239 append_decls(fVSUnis, fContext, shaderStr);
240 append_decls(fVSAttrs, fContext, shaderStr);
241 append_decls(fVSOutputs, fContext, shaderStr);
242 shaderStr->append(fVSCode);
243 break;
244 case kGeometry_ShaderType:
245 if (fUsesGS) {
246 *shaderStr = fHeader;
247 shaderStr->append(fGSHeader);
248 append_decls(fGSInputs, fContext, shaderStr);
249 append_decls(fGSOutputs, fContext, shaderStr);
250 shaderStr->append(fGSCode);
251 } else {
252 shaderStr->reset();
253 }
254 break;
255 case kFragment_ShaderType:
256 *shaderStr = fHeader;
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000257 append_default_precision_qualifier(kDefaultFragmentPrecision,
258 fContext.binding(),
259 shaderStr);
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000260 append_decls(fFSUnis, fContext, shaderStr);
261 append_decls(fFSInputs, fContext, shaderStr);
262 // We shouldn't have declared outputs on 1.10
263 GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
264 append_decls(fFSOutputs, fContext, shaderStr);
265 shaderStr->append(fFSFunctions);
266 shaderStr->append(fFSCode);
267 break;
268 }
bsalomon@google.comad5e9372012-07-11 18:11:27 +0000269 }
bsalomon@google.comd7727ce2012-07-12 16:40:03 +0000270