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