• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
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 
33 using std::string;
34 using std::vector;
35 
36 namespace rsg
37 {
38 
ShaderGenerator(GeneratorState & state)39 ShaderGenerator::ShaderGenerator (GeneratorState& state)
40 	: m_state		(state)
41 	, m_varManager	(state.getNameAllocator())
42 {
43 	state.setVariableManager(m_varManager);
44 }
45 
~ShaderGenerator(void)46 ShaderGenerator::~ShaderGenerator (void)
47 {
48 }
49 
50 namespace
51 {
52 
getFragColorName(const GeneratorState & state)53 const 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 
createAssignment(BlockStatement & block,const Variable * dstVar,const Variable * srcVar)65 void 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 
findByName(VariableManager & varManager,const char * name)79 const 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 
genVertexPassthrough(GeneratorState & state,Shader & shader)92 void 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 
genFragmentPassthrough(GeneratorState & state,Shader & shader)124 void 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.
fillUndefinedComponents(ValueRangeAccess valueRange)137 void 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 
fillUndefinedShaderInputs(vector<ShaderInput * > & inputs)162 void 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 
generate(const ShaderParameters & shaderParams,Shader & shader,const vector<ShaderInput * > & outputs)173 void 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 
214 			m_state.getVariableManager().setValue(fragColorVar, valueRange);
215 		}
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 
262 			m_state.getVariableManager().setValue(qpPosVariable, valueRange); // \todo [2011-05-24 pyry] No expression should be able to use gl_Position or dEQP_Position..
263 
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
358