blob: 0f9331c507b903af4b5bd8a56b266e08adfb6b08 [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
11namespace {
12
13// number of each input/output type in a single allocation block
14static const int sVarsPerBlock = 8;
15
16// except FS outputs where we expect 2 at most.
17static const int sMaxFSOutputs = 2;
18
19}
20
tomhudson@google.com9c639a42012-05-14 19:58:06 +000021// Architectural assumption: always 2-d input coords.
22// Likely to become non-constant and non-static, perhaps even
23// varying by stage, if we use 1D textures for gradients!
24//const int GrGLShaderBuilder::fCoordDims = 2;
25
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000026GrGLShaderBuilder::GrGLShaderBuilder()
27 : fVSUnis(sVarsPerBlock)
28 , fVSAttrs(sVarsPerBlock)
29 , fVSOutputs(sVarsPerBlock)
30 , fGSInputs(sVarsPerBlock)
31 , fGSOutputs(sVarsPerBlock)
32 , fFSInputs(sVarsPerBlock)
33 , fFSUnis(sVarsPerBlock)
34 , fFSOutputs(sMaxFSOutputs)
tomhudson@google.com040c41a2012-05-18 14:57:40 +000035 , fUsesGS(false)
tomhudson@google.com9c639a42012-05-14 19:58:06 +000036 , fVaryingDims(0)
tomhudson@google.com040c41a2012-05-18 14:57:40 +000037 , fComplexCoord(false) {
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) {
tomhudson@google.com52598142012-05-24 17:44:30 +000076 GrStringBuilder retval;
77
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
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000119const GrGLShaderVar& GrGLShaderBuilder::addUniform(VariableLifetime lifetime,
120 GrSLType type,
121 const char* name,
122 int stageNum,
123 int count) {
124 GrAssert(name && strlen(name));
125
126 GrGLShaderVar* var = NULL;
127 if (kVertex_VariableLifetime & lifetime) {
128 var = &fVSUnis.push_back();
129 } else {
130 GrAssert(kFragment_VariableLifetime & lifetime);
131 var = &fFSUnis.push_back();
132 }
133 var->setType(type);
134 var->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
135 var->setName(name);
136 if (stageNum >= 0) {
137 var->accessName()->appendS32(stageNum);
138 }
139 var->setArrayCount(count);
140
141 if ((kVertex_VariableLifetime |
142 kFragment_VariableLifetime) == lifetime) {
143 fFSUnis.push_back(*var);
144 // If it's shared between VS and FS, VS must override
145 // default highp and specify mediump.
146 var->setEmitPrecision(true);
147 }
148
149 return *var;
150}
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000151
152void GrGLShaderBuilder::addVarying(GrSLType type,
153 const char* name,
154 const char** vsOutName,
155 const char** fsInName) {
156 fVSOutputs.push_back();
157 fVSOutputs.back().setType(type);
158 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
159 fVSOutputs.back().accessName()->printf("v%s", name);
160 if (vsOutName) {
161 *vsOutName = fVSOutputs.back().getName().c_str();
162 }
163 // input to FS comes either from VS or GS
164 const GrStringBuilder* fsName;
165 if (fUsesGS) {
166 // if we have a GS take each varying in as an array
167 // and output as non-array.
168 fGSInputs.push_back();
169 fGSInputs.back().setType(type);
170 fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
171 fGSInputs.back().setUnsizedArray();
172 *fGSInputs.back().accessName() = fVSOutputs.back().getName();
173 fGSOutputs.push_back();
174 fGSOutputs.back().setType(type);
175 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
176 fGSOutputs.back().accessName()->printf("g%s", name);
177 fsName = fGSOutputs.back().accessName();
178 } else {
179 fsName = fVSOutputs.back().accessName();
180 }
181 fFSInputs.push_back();
182 fFSInputs.back().setType(type);
183 fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
184 fFSInputs.back().setName(*fsName);
185 if (fsInName) {
186 *fsInName = fsName->c_str();
187 }
188}
189
190
191void GrGLShaderBuilder::addVarying(GrSLType type,
192 const char* name,
193 int stageNum,
194 const char** vsOutName,
195 const char** fsInName) {
196 GrStringBuilder nameWithStage(name);
197 nameWithStage.appendS32(stageNum);
198 this->addVarying(type, nameWithStage.c_str(), vsOutName, fsInName);
199}
200