Home | History | Annotate | Download | only in randomshaders
      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 
     39 ShaderGenerator::ShaderGenerator (GeneratorState& state)
     40 	: m_state		(state)
     41 	, m_varManager	(state.getNameAllocator())
     42 {
     43 	state.setVariableManager(m_varManager);
     44 }
     45 
     46 ShaderGenerator::~ShaderGenerator (void)
     47 {
     48 }
     49 
     50 namespace
     51 {
     52 
     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 
     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 
     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 
     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 
    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.
    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 
    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 
    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.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