blob: 7af96232aae7d2da2e1855a61528212de10391f8 [file] [log] [blame]
Jarkko Poyry3c827362014-09-02 11:48:52 +03001/*-------------------------------------------------------------------------
2 * drawElements Quality Program Random Shader Generator
3 * ----------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Shader generator.
22 *//*--------------------------------------------------------------------*/
23
24#include "rsgShaderGenerator.hpp"
25#include "rsgFunctionGenerator.hpp"
26#include "rsgToken.hpp"
27#include "rsgPrettyPrinter.hpp"
28#include "rsgUtils.hpp"
29#include "deString.h"
30
31#include <iterator>
32
33using std::string;
34using std::vector;
35
36namespace rsg
37{
38
39ShaderGenerator::ShaderGenerator (GeneratorState& state)
40 : m_state (state)
41 , m_varManager (state.getNameAllocator())
42{
43 state.setVariableManager(m_varManager);
44}
45
46ShaderGenerator::~ShaderGenerator (void)
47{
48}
49
50namespace
51{
52
53const char* getFragColorName (const GeneratorState& state)
54{
55 switch (state.getProgramParameters().version)
56 {
57 case VERSION_100: return "gl_FragColor";
58 case VERSION_300: return "dEQP_FragColor";
59 default:
60 DE_ASSERT(DE_FALSE);
61 return DE_NULL;
62 }
63}
64
65void createAssignment (BlockStatement& block, const Variable* dstVar, const Variable* srcVar)
66{
67 VariableRead* varRead = new VariableRead(srcVar);
68 try
69 {
70 block.addChild(new AssignStatement( dstVar, varRead));
71 }
72 catch (const std::exception&)
73 {
74 delete varRead;
75 throw;
76 }
77}
78
79const ValueEntry* findByName (VariableManager& varManager, const char* name)
80{
81 AnyEntry::Iterator iter = varManager.getBegin<AnyEntry>();
82 AnyEntry::Iterator end = varManager.getEnd<AnyEntry>();
83 for (; iter != end; iter++)
84 {
85 const ValueEntry* entry = *iter;
86 if (deStringEqual(entry->getVariable()->getName(), name))
87 return entry;
88 }
89 return DE_NULL;
90}
91
92void genVertexPassthrough (GeneratorState& state, Shader& shader)
93{
94 // Create copies from shader inputs to outputs
95 vector<const ValueEntry*> entries;
96 std::copy(state.getVariableManager().getBegin<AnyEntry>(), state.getVariableManager().getEnd<AnyEntry>(), std::inserter(entries, entries.begin()));
97
98 for (vector<const ValueEntry*>::const_iterator i = entries.begin(); i != entries.end(); i++)
99 {
100 const ValueEntry* entry = *i;
101 const Variable* outVar = entry->getVariable();
102 std::string inVarName;
103
104 if (outVar->getStorage() != Variable::STORAGE_SHADER_OUT)
105 continue;
106
107 // Name: a_[name], remove v_ -prefix if such exists
108 inVarName = "a_";
109 if (deStringBeginsWith(outVar->getName(), "v_"))
110 inVarName += (outVar->getName()+2);
111 else
112 inVarName += outVar->getName();
113
114 Variable* inVar = state.getVariableManager().allocate(outVar->getType(), Variable::STORAGE_SHADER_IN, inVarName.c_str());
115
116 // Update value range. This will be stored into shader input info.
117 state.getVariableManager().setValue(inVar, entry->getValueRange());
118
119 // Add assignment from input to output into main() body
120 createAssignment(shader.getMain().getBody(), entry->getVariable(), inVar);
121 }
122}
123
124void genFragmentPassthrough (GeneratorState& state, Shader& shader)
125{
126 // Add simple gl_FragColor = v_color; assignment
127 const ValueEntry* fragColorEntry = findByName(state.getVariableManager(), getFragColorName(state));
128 TCU_CHECK(fragColorEntry);
129
130 Variable* inColorVariable = state.getVariableManager().allocate(fragColorEntry->getVariable()->getType(), Variable::STORAGE_SHADER_IN, "v_color");
131
132 state.getVariableManager().setValue(inColorVariable, fragColorEntry->getValueRange());
133 createAssignment(shader.getMain().getBody(), fragColorEntry->getVariable(), inColorVariable);
134}
135
136// Sets undefined (-inf..inf) components to some meaningful values. Used for sanitizing final shader input value ranges.
137void fillUndefinedComponents (ValueRangeAccess valueRange)
138{
139 VariableType::Type baseType = valueRange.getType().getBaseType();
140 TCU_CHECK(baseType == VariableType::TYPE_FLOAT ||
141 baseType == VariableType::TYPE_INT ||
142 baseType == VariableType::TYPE_BOOL);
143
144 for (int elemNdx = 0; elemNdx < valueRange.getType().getNumElements(); elemNdx++)
145 {
146 if (isUndefinedValueRange(valueRange.component(elemNdx)))
147 {
148 ValueAccess min = valueRange.component(elemNdx).getMin();
149 ValueAccess max = valueRange.component(elemNdx).getMax();
150
151 switch (baseType)
152 {
153 case VariableType::TYPE_FLOAT: min = 0.0f; max = 1.0f; break;
154 case VariableType::TYPE_INT: min = 0; max = 1; break;
155 case VariableType::TYPE_BOOL: min = false; max = true; break;
156 default: DE_ASSERT(DE_FALSE);
157 }
158 }
159 }
160}
161
162void fillUndefinedShaderInputs (vector<ShaderInput*>& inputs)
163{
164 for (vector<ShaderInput*>::iterator i = inputs.begin(); i != inputs.end(); i++)
165 {
166 if (!(*i)->getVariable()->getType().isSampler()) // Samplers are assigned at program-level.
167 fillUndefinedComponents((*i)->getValueRange());
168 }
169}
170
171} // anonymous
172
173void ShaderGenerator::generate (const ShaderParameters& shaderParams, Shader& shader, const vector<ShaderInput*>& outputs)
174{
175 // Global scopes
176 VariableScope& globalVariableScope = shader.getGlobalScope();
177 ValueScope globalValueScope;
178
179 // Init state
180 m_state.setShader(shaderParams, shader);
181 DE_ASSERT(m_state.getExpressionFlags() == 0);
182
183 // Reserve some scalars for gl_Position & dEQP_Position
184 ReservedScalars reservedScalars;
185 if (shader.getType() == Shader::TYPE_VERTEX)
186 m_state.getVariableManager().reserve(reservedScalars, 4*2);
187
188 // Push global scopes
189 m_varManager.pushVariableScope(globalVariableScope);
190 m_varManager.pushValueScope(globalValueScope);
191
192 // Init shader outputs.
193 {
194 for (vector<ShaderInput*>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
195 {
196 const ShaderInput* input = *i;
197 Variable* variable = m_state.getVariableManager().allocate(input->getVariable()->getType(), Variable::STORAGE_SHADER_OUT, input->getVariable()->getName());
198
199 m_state.getVariableManager().setValue(variable, input->getValueRange());
200 }
201
202 if (shader.getType() == Shader::TYPE_FRAGMENT)
203 {
204 // gl_FragColor
205 // \todo [2011-11-22 pyry] Multiple outputs from fragment shader!
206 Variable* fragColorVar = m_state.getVariableManager().allocate(VariableType(VariableType::TYPE_FLOAT, 4), Variable::STORAGE_SHADER_OUT, getFragColorName(m_state));
207 ValueRange valueRange(fragColorVar->getType());
208
209 valueRange.getMin() = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
210 valueRange.getMax() = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
211
212 fragColorVar->setLayoutLocation(0); // Bind color output to location 0 (applies to GLSL ES 3.0 onwards).
213
Jarkko Pöyryba84b6d2015-05-19 17:44:29 -0700214 m_state.getVariableManager().setValue(fragColorVar, valueRange.asAccess());
Jarkko Poyry3c827362014-09-02 11:48:52 +0300215 }
216 }
217
218 // Construct shader code.
219 {
220 Function& main = shader.getMain();
221 main.setReturnType(VariableType(VariableType::TYPE_VOID));
222
223 if (shaderParams.randomize)
224 {
225 FunctionGenerator funcGen(m_state, main);
226
227 // Mandate assignment into to all shader outputs in main()
228 const vector<Variable*>& liveVars = globalVariableScope.getLiveVariables();
229 for (vector<Variable*>::const_iterator i = liveVars.begin(); i != liveVars.end(); i++)
230 {
231 Variable* variable = *i;
232 if (variable->getStorage() == Variable::STORAGE_SHADER_OUT)
233 funcGen.requireAssignment(variable);
234 }
235
236 funcGen.generate();
237 }
238 else
239 {
240 if (shader.getType() == Shader::TYPE_VERTEX)
241 genVertexPassthrough(m_state, shader);
242 else
243 {
244 DE_ASSERT(shader.getType() == Shader::TYPE_FRAGMENT);
245 genFragmentPassthrough(m_state, shader);
246 }
247 }
248
249 if (shader.getType() == Shader::TYPE_VERTEX)
250 {
251 // Add gl_Position = dEQP_Position;
252 m_state.getVariableManager().release(reservedScalars);
253
254 Variable* glPosVariable = m_state.getVariableManager().allocate(VariableType(VariableType::TYPE_FLOAT, 4), Variable::STORAGE_SHADER_OUT, "gl_Position");
255 Variable* qpPosVariable = m_state.getVariableManager().allocate(VariableType(VariableType::TYPE_FLOAT, 4), Variable::STORAGE_SHADER_IN, "dEQP_Position");
256
257 ValueRange valueRange(glPosVariable->getType());
258
259 valueRange.getMin() = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f);
260 valueRange.getMax() = tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f);
261
Jarkko Pöyryba84b6d2015-05-19 17:44:29 -0700262 m_state.getVariableManager().setValue(qpPosVariable, valueRange.asAccess()); // \todo [2011-05-24 pyry] No expression should be able to use gl_Position or dEQP_Position..
Jarkko Poyry3c827362014-09-02 11:48:52 +0300263
264 createAssignment(main.getBody(), glPosVariable, qpPosVariable);
265 }
266 }
267
268 // Declare live global variables.
269 {
270 vector<Variable*> liveVariables;
271 std::copy(globalVariableScope.getLiveVariables().begin(), globalVariableScope.getLiveVariables().end(), std::inserter(liveVariables, liveVariables.begin()));
272
273 vector<Variable*> createDeclarationStatementVars;
274
275 for (vector<Variable*>::iterator i = liveVariables.begin(); i != liveVariables.end(); i++)
276 {
277 Variable* variable = *i;
278 const char* name = variable->getName();
279 bool declare = !deStringBeginsWith(name, "gl_"); // Do not declare built-in types.
280
281 // Create input entries (store value range) if necessary
282 vector<ShaderInput*>& inputs = shader.getInputs();
283 vector<ShaderInput*>& uniforms = shader.getUniforms();
284
285 switch (variable->getStorage())
286 {
287 case Variable::STORAGE_SHADER_IN:
288 {
289 const ValueEntry* value = m_state.getVariableManager().getValue(variable);
290
291 inputs.reserve(inputs.size()+1);
292 inputs.push_back(new ShaderInput(variable, value->getValueRange()));
293 break;
294 }
295
296 case Variable::STORAGE_UNIFORM:
297 {
298 const ValueEntry* value = m_state.getVariableManager().getValue(variable);
299
300 uniforms.reserve(uniforms.size()+1);
301 uniforms.push_back(new ShaderInput(variable, value->getValueRange()));
302 break;
303 }
304
305 default:
306 break;
307 }
308
309 if (declare)
310 createDeclarationStatementVars.push_back(variable);
311 else
312 {
313 // Just move to global scope without declaration statement.
314 m_state.getVariableManager().declareVariable(variable);
315 }
316 }
317
318 // All global initializers must be constant expressions, no variable allocation is allowed
319 DE_ASSERT(m_state.getExpressionFlags() == 0);
320 m_state.pushExpressionFlags(CONST_EXPR|NO_VAR_ALLOCATION);
321
322 // Create declaration statements
323 for (vector<Variable*>::iterator i = createDeclarationStatementVars.begin(); i != createDeclarationStatementVars.end(); i++)
324 {
325 shader.getGlobalStatements().reserve(shader.getGlobalStatements().size());
326 shader.getGlobalStatements().push_back(new DeclarationStatement(m_state, *i));
327 }
328
329 m_state.popExpressionFlags();
330 }
331
332 // Pop global scopes
333 m_varManager.popVariableScope();
334 m_varManager.popValueScope();
335
336 // Fill undefined (unused) components in inputs with dummy values
337 fillUndefinedShaderInputs(shader.getInputs());
338 fillUndefinedShaderInputs(shader.getUniforms());
339
340 // Tokenize shader and write source
341 {
342 TokenStream tokenStr;
343 shader.tokenize(m_state, tokenStr);
344
345 std::ostringstream str;
346 PrettyPrinter printer(str);
347
348 // Append #version if necessary.
349 if (m_state.getProgramParameters().version == VERSION_300)
350 str << "#version 300 es\n";
351
352 printer.append(tokenStr);
353 shader.setSource(str.str().c_str());
354 }
355}
356
357} // rsg