blob: e0e862212b139cf6b3aee73c5193b63d2a970738 [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.com52598142012-05-24 17:44:30 +000037 , fSamplerMode(kDefault_SamplerMode)
tomhudson@google.com040c41a2012-05-18 14:57:40 +000038 , fComplexCoord(false) {
tomhudson@google.comf9ad8862012-05-11 20:38:48 +000039
40}
41
tomhudson@google.com52598142012-05-24 17:44:30 +000042void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
43 static const uint32_t kMulByAlphaMask =
44 (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
45 GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
46
47 fSwizzle = "";
48 if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) {
49 GrAssert(!(configFlags &
50 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
51 GrAssert(!(configFlags &
52 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
53 fSwizzle = ".bgra";
54 } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) {
55 GrAssert(!(configFlags & kMulByAlphaMask));
56 GrAssert(!(configFlags &
57 GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
58 fSwizzle = ".aaaa";
59 } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) {
60 GrAssert(!(configFlags & kMulByAlphaMask));
61 GrAssert(!(configFlags &
62 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
63 fSwizzle = ".rrrr";
64 }
65}
66
67void GrGLShaderBuilder::computeModulate(const char* fsInColor) {
68 if (NULL != fsInColor) {
69 fModulate.printf(" * %s", fsInColor);
robertphillips@google.come9b3f7d2012-05-30 12:26:39 +000070 } else {
71 fModulate.reset();
tomhudson@google.com52598142012-05-24 17:44:30 +000072 }
73}
74
75void GrGLShaderBuilder::emitTextureSetup() {
76 GrStringBuilder retval;
77
78 switch (fSamplerMode) {
79 case kDefault_SamplerMode:
80 // Fall through
81 case kProj_SamplerMode:
82 // Do nothing
83 break;
84 case kExplicitDivide_SamplerMode:
85 retval = "inCoord";
86 fFSCode.appendf("\t %s %s = %s%s / %s%s\n",
87 GrGLShaderVar::TypeString
88 (GrSLFloatVectorType(fCoordDims)),
89 retval.c_str(),
90 fSampleCoords.c_str(),
91 GrGLSLVectorNonhomogCoords(fVaryingDims),
92 fSampleCoords.c_str(),
93 GrGLSLVectorHomogCoord(fVaryingDims));
94 fSampleCoords = retval;
95 break;
96 }
97}
98
99void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
100 const char* coordName) {
101 if (NULL == coordName) {
102 coordName = fSampleCoords.c_str();
103 }
104 switch (fSamplerMode) {
105 default:
106 SkDEBUGFAIL("Unknown sampler mode");
107 // Fall through
108 case kDefault_SamplerMode:
109 // Fall through
110 case kExplicitDivide_SamplerMode:
111 fFSCode.appendf("texture2D(%s, %s)", samplerName, coordName);
112 break;
113 case kProj_SamplerMode:
114 fFSCode.appendf("texture2DProj(%s, %s)", samplerName, coordName);
115 break;
116 }
117
118}
119
120void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
121 const char* samplerName) {
122 fFSCode.appendf("\t%s = ", outColor);
123 this->emitTextureLookup(samplerName);
124 fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
125}
126
tomhudson@google.com242ed6f2012-05-30 17:38:57 +0000127const GrGLShaderVar& GrGLShaderBuilder::addUniform(VariableLifetime lifetime,
128 GrSLType type,
129 const char* name,
130 int stageNum,
131 int count) {
132 GrAssert(name && strlen(name));
133
134 GrGLShaderVar* var = NULL;
135 if (kVertex_VariableLifetime & lifetime) {
136 var = &fVSUnis.push_back();
137 } else {
138 GrAssert(kFragment_VariableLifetime & lifetime);
139 var = &fFSUnis.push_back();
140 }
141 var->setType(type);
142 var->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
143 var->setName(name);
144 if (stageNum >= 0) {
145 var->accessName()->appendS32(stageNum);
146 }
147 var->setArrayCount(count);
148
149 if ((kVertex_VariableLifetime |
150 kFragment_VariableLifetime) == lifetime) {
151 fFSUnis.push_back(*var);
152 // If it's shared between VS and FS, VS must override
153 // default highp and specify mediump.
154 var->setEmitPrecision(true);
155 }
156
157 return *var;
158}
tomhudson@google.com23cb2292012-05-30 18:26:03 +0000159
160void GrGLShaderBuilder::addVarying(GrSLType type,
161 const char* name,
162 const char** vsOutName,
163 const char** fsInName) {
164 fVSOutputs.push_back();
165 fVSOutputs.back().setType(type);
166 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
167 fVSOutputs.back().accessName()->printf("v%s", name);
168 if (vsOutName) {
169 *vsOutName = fVSOutputs.back().getName().c_str();
170 }
171 // input to FS comes either from VS or GS
172 const GrStringBuilder* fsName;
173 if (fUsesGS) {
174 // if we have a GS take each varying in as an array
175 // and output as non-array.
176 fGSInputs.push_back();
177 fGSInputs.back().setType(type);
178 fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
179 fGSInputs.back().setUnsizedArray();
180 *fGSInputs.back().accessName() = fVSOutputs.back().getName();
181 fGSOutputs.push_back();
182 fGSOutputs.back().setType(type);
183 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
184 fGSOutputs.back().accessName()->printf("g%s", name);
185 fsName = fGSOutputs.back().accessName();
186 } else {
187 fsName = fVSOutputs.back().accessName();
188 }
189 fFSInputs.push_back();
190 fFSInputs.back().setType(type);
191 fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
192 fFSInputs.back().setName(*fsName);
193 if (fsInName) {
194 *fsInName = fsName->c_str();
195 }
196}
197
198
199void GrGLShaderBuilder::addVarying(GrSLType type,
200 const char* name,
201 int stageNum,
202 const char** vsOutName,
203 const char** fsInName) {
204 GrStringBuilder nameWithStage(name);
205 nameWithStage.appendS32(stageNum);
206 this->addVarying(type, nameWithStage.c_str(), vsOutName, fsInName);
207}
208