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
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
214			m_state.getVariableManager().setValue(fragColorVar, valueRange.asAccess());
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.asAccess()); // \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