Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.1 Module
      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 Program interface
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fProgramInterfaceDefinition.hpp"
     25 #include "gluVarType.hpp"
     26 #include "gluShaderProgram.hpp"
     27 #include "deSTLUtil.hpp"
     28 #include "glwEnums.hpp"
     29 
     30 #include <set>
     31 
     32 namespace deqp
     33 {
     34 namespace gles31
     35 {
     36 namespace Functional
     37 {
     38 namespace ProgramInterfaceDefinition
     39 {
     40 namespace
     41 {
     42 
     43 static const glu::ShaderType s_shaderStageOrder[] =
     44 {
     45 	glu::SHADERTYPE_COMPUTE,
     46 
     47 	glu::SHADERTYPE_VERTEX,
     48 	glu::SHADERTYPE_TESSELLATION_CONTROL,
     49 	glu::SHADERTYPE_TESSELLATION_EVALUATION,
     50 	glu::SHADERTYPE_GEOMETRY,
     51 	glu::SHADERTYPE_FRAGMENT
     52 };
     53 
     54 // s_shaderStageOrder does not contain ShaderType_LAST
     55 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_shaderStageOrder) == glu::SHADERTYPE_LAST);
     56 
     57 static bool containsMatchingSubtype (const glu::VarType& varType, bool (*predicate)(glu::DataType))
     58 {
     59 	if (varType.isBasicType() && predicate(varType.getBasicType()))
     60 		return true;
     61 
     62 	if (varType.isArrayType())
     63 		return containsMatchingSubtype(varType.getElementType(), predicate);
     64 
     65 	if (varType.isStructType())
     66 		for (int memberNdx = 0; memberNdx < varType.getStructPtr()->getNumMembers(); ++memberNdx)
     67 			if (containsMatchingSubtype(varType.getStructPtr()->getMember(memberNdx).getType(), predicate))
     68 				return true;
     69 
     70 	return false;
     71 }
     72 
     73 static bool containsMatchingSubtype (const std::vector<glu::VariableDeclaration>& decls, bool (*predicate)(glu::DataType))
     74 {
     75 	for (int varNdx = 0; varNdx < (int)decls.size(); ++varNdx)
     76 		if (containsMatchingSubtype(decls[varNdx].varType, predicate))
     77 			return true;
     78 	return false;
     79 }
     80 
     81 static bool isOpaqueType (glu::DataType type)
     82 {
     83 	return	glu::isDataTypeAtomicCounter(type)	||
     84 			glu::isDataTypeImage(type)			||
     85 			glu::isDataTypeSampler(type);
     86 }
     87 
     88 static int getShaderStageIndex (glu::ShaderType stage)
     89 {
     90 	const glu::ShaderType* const it = std::find(DE_ARRAY_BEGIN(s_shaderStageOrder), DE_ARRAY_END(s_shaderStageOrder), stage);
     91 
     92 	if (it == DE_ARRAY_END(s_shaderStageOrder))
     93 		return -1;
     94 	else
     95 	{
     96 		const int index = (int)(it - DE_ARRAY_BEGIN(s_shaderStageOrder));
     97 		return index;
     98 	}
     99 }
    100 
    101 } // anonymous
    102 
    103 Shader::Shader (glu::ShaderType type, glu::GLSLVersion version)
    104 	: m_shaderType	(type)
    105 	, m_version		(version)
    106 {
    107 }
    108 
    109 Shader::~Shader (void)
    110 {
    111 }
    112 
    113 static bool isIllegalVertexInput (const glu::VarType& varType)
    114 {
    115 	// booleans, opaque types, arrays, structs are not allowed as inputs
    116 	if (!varType.isBasicType())
    117 		return true;
    118 	if (glu::isDataTypeBoolOrBVec(varType.getBasicType()))
    119 		return true;
    120 	return false;
    121 }
    122 
    123 static bool isIllegalVertexOutput (const glu::VarType& varType, bool insideAStruct = false, bool insideAnArray = false)
    124 {
    125 	// booleans, opaque types, arrays of arrays, arrays of structs, array in struct, struct struct are not allowed as vertex outputs
    126 
    127 	if (varType.isBasicType())
    128 	{
    129 		const bool isOpaqueType = !glu::isDataTypeScalar(varType.getBasicType()) && !glu::isDataTypeVector(varType.getBasicType()) && !glu::isDataTypeMatrix(varType.getBasicType());
    130 
    131 		if (glu::isDataTypeBoolOrBVec(varType.getBasicType()))
    132 			return true;
    133 
    134 		if (isOpaqueType)
    135 			return true;
    136 
    137 		return false;
    138 	}
    139 	else if (varType.isArrayType())
    140 	{
    141 		if (insideAnArray || insideAStruct)
    142 			return true;
    143 
    144 		return isIllegalVertexOutput(varType.getElementType(), insideAStruct, true);
    145 	}
    146 	else if (varType.isStructType())
    147 	{
    148 		if (insideAnArray || insideAStruct)
    149 			return true;
    150 
    151 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
    152 			if (isIllegalVertexOutput(varType.getStructPtr()->getMember(ndx).getType(), true, insideAnArray))
    153 				return true;
    154 
    155 		return false;
    156 	}
    157 	else
    158 	{
    159 		DE_ASSERT(false);
    160 		return true;
    161 	}
    162 }
    163 
    164 static bool isIllegalFragmentInput (const glu::VarType& varType)
    165 {
    166 	return isIllegalVertexOutput(varType);
    167 }
    168 
    169 static bool isIllegalFragmentOutput (const glu::VarType& varType, bool insideAnArray = false)
    170 {
    171 	// booleans, opaque types, matrices, structs, arrays of arrays are not allowed as outputs
    172 
    173 	if (varType.isBasicType())
    174 	{
    175 		const bool isOpaqueType = !glu::isDataTypeScalar(varType.getBasicType()) && !glu::isDataTypeVector(varType.getBasicType()) && !glu::isDataTypeMatrix(varType.getBasicType());
    176 
    177 		if (glu::isDataTypeBoolOrBVec(varType.getBasicType()) || isOpaqueType || glu::isDataTypeMatrix(varType.getBasicType()))
    178 			return true;
    179 		return false;
    180 	}
    181 	else if (varType.isArrayType())
    182 	{
    183 		if (insideAnArray)
    184 			return true;
    185 		return isIllegalFragmentOutput(varType.getElementType(), true);
    186 	}
    187 	else if (varType.isStructType())
    188 		return true;
    189 	else
    190 	{
    191 		DE_ASSERT(false);
    192 		return true;
    193 	}
    194 }
    195 
    196 static bool isTypeIntegerOrContainsIntegers (const glu::VarType& varType)
    197 {
    198 	if (varType.isBasicType())
    199 		return glu::isDataTypeIntOrIVec(varType.getBasicType()) || glu::isDataTypeUintOrUVec(varType.getBasicType());
    200 	else if (varType.isArrayType())
    201 		return isTypeIntegerOrContainsIntegers(varType.getElementType());
    202 	else if (varType.isStructType())
    203 	{
    204 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
    205 			if (isTypeIntegerOrContainsIntegers(varType.getStructPtr()->getMember(ndx).getType()))
    206 				return true;
    207 		return false;
    208 	}
    209 	else
    210 	{
    211 		DE_ASSERT(false);
    212 		return true;
    213 	}
    214 }
    215 
    216 bool Shader::isValid (void) const
    217 {
    218 	// Default block variables
    219 	{
    220 		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
    221 		{
    222 			// atomic declaration in the default block without binding
    223 			if (m_defaultBlock.variables[varNdx].layout.binding == -1 &&
    224 				containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeAtomicCounter))
    225 				return false;
    226 
    227 			// atomic declaration in a struct
    228 			if (m_defaultBlock.variables[varNdx].varType.isStructType() &&
    229 				containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeAtomicCounter))
    230 				return false;
    231 
    232 			// Unsupported layout qualifiers
    233 
    234 			if (m_defaultBlock.variables[varNdx].layout.matrixOrder != glu::MATRIXORDER_LAST)
    235 				return false;
    236 
    237 			if (containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeSampler))
    238 			{
    239 				const glu::Layout layoutWithLocationAndBinding(m_defaultBlock.variables[varNdx].layout.location, m_defaultBlock.variables[varNdx].layout.binding);
    240 
    241 				if (m_defaultBlock.variables[varNdx].layout != layoutWithLocationAndBinding)
    242 					return false;
    243 			}
    244 		}
    245 	}
    246 
    247 	// Interface blocks
    248 	{
    249 		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
    250 		{
    251 			// ES31 disallows interface block array arrays
    252 			if (m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.size() > 1)
    253 				return false;
    254 
    255 			// Interface block arrays must have instance name
    256 			if (!m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty() && m_defaultBlock.interfaceBlocks[interfaceNdx].instanceName.empty())
    257 				return false;
    258 
    259 			// Opaque types in interface block
    260 			if (containsMatchingSubtype(m_defaultBlock.interfaceBlocks[interfaceNdx].variables, isOpaqueType))
    261 				return false;
    262 		}
    263 	}
    264 
    265 	// Shader type specific
    266 
    267 	if (m_shaderType == glu::SHADERTYPE_VERTEX)
    268 	{
    269 		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
    270 		{
    271 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && isIllegalVertexInput(m_defaultBlock.variables[varNdx].varType))
    272 				return false;
    273 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && isIllegalVertexOutput(m_defaultBlock.variables[varNdx].varType))
    274 				return false;
    275 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && m_defaultBlock.variables[varNdx].interpolation != glu::INTERPOLATION_FLAT && isTypeIntegerOrContainsIntegers(m_defaultBlock.variables[varNdx].varType))
    276 				return false;
    277 		}
    278 	}
    279 	else if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
    280 	{
    281 		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
    282 		{
    283 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && isIllegalFragmentInput(m_defaultBlock.variables[varNdx].varType))
    284 				return false;
    285 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && m_defaultBlock.variables[varNdx].interpolation != glu::INTERPOLATION_FLAT && isTypeIntegerOrContainsIntegers(m_defaultBlock.variables[varNdx].varType))
    286 				return false;
    287 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && isIllegalFragmentOutput(m_defaultBlock.variables[varNdx].varType))
    288 				return false;
    289 		}
    290 	}
    291 
    292 	return true;
    293 }
    294 
    295 Program::Program (void)
    296 	: m_separable	(false)
    297 	, m_xfbMode		(0)
    298 {
    299 }
    300 
    301 static void collectStructPtrs (std::set<const glu::StructType*>& dst, const glu::VarType& type)
    302 {
    303 	if (type.isArrayType())
    304 		collectStructPtrs(dst, type.getElementType());
    305 	else if (type.isStructType())
    306 	{
    307 		dst.insert(type.getStructPtr());
    308 
    309 		for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx)
    310 			collectStructPtrs(dst, type.getStructPtr()->getMember(memberNdx).getType());
    311 	}
    312 }
    313 
    314 Program::~Program (void)
    315 {
    316 	// delete shader struct types, need to be done by the program since shaders might share struct types
    317 	{
    318 		std::set<const glu::StructType*> structTypes;
    319 
    320 		for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
    321 		{
    322 			for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.variables.size(); ++varNdx)
    323 				collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.variables[varNdx].varType);
    324 
    325 			for (int interfaceNdx = 0; interfaceNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
    326 				for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
    327 					collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables[varNdx].varType);
    328 		}
    329 
    330 		for (std::set<const glu::StructType*>::iterator it = structTypes.begin(); it != structTypes.end(); ++it)
    331 			delete *it;
    332 	}
    333 
    334 	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
    335 		delete m_shaders[shaderNdx];
    336 	m_shaders.clear();
    337 }
    338 
    339 Shader* Program::addShader (glu::ShaderType type, glu::GLSLVersion version)
    340 {
    341 	Shader* shader;
    342 
    343 	// make sure push_back() cannot throw
    344 	m_shaders.reserve(m_shaders.size() + 1);
    345 
    346 	shader = new Shader(type, version);
    347 	m_shaders.push_back(shader);
    348 
    349 	return shader;
    350 }
    351 
    352 void Program::setSeparable (bool separable)
    353 {
    354 	m_separable = separable;
    355 }
    356 
    357 bool Program::isSeparable (void) const
    358 {
    359 	return m_separable;
    360 }
    361 
    362 const std::vector<Shader*>& Program::getShaders (void) const
    363 {
    364 	return m_shaders;
    365 }
    366 
    367 glu::ShaderType Program::getFirstStage (void) const
    368 {
    369 	const int	nullValue	= DE_LENGTH_OF_ARRAY(s_shaderStageOrder);
    370 	int			firstStage	= nullValue;
    371 
    372 	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
    373 	{
    374 		const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType());
    375 		if (index != -1)
    376 			firstStage = de::min(firstStage, index);
    377 	}
    378 
    379 	if (firstStage == nullValue)
    380 		return glu::SHADERTYPE_LAST;
    381 	else
    382 		return s_shaderStageOrder[firstStage];
    383 }
    384 
    385 glu::ShaderType Program::getLastStage (void) const
    386 {
    387 	const int	nullValue	= -1;
    388 	int			lastStage	= nullValue;
    389 
    390 	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
    391 	{
    392 		const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType());
    393 		if (index != -1)
    394 			lastStage = de::max(lastStage, index);
    395 	}
    396 
    397 	if (lastStage == nullValue)
    398 		return glu::SHADERTYPE_LAST;
    399 	else
    400 		return s_shaderStageOrder[lastStage];
    401 }
    402 
    403 void Program::addTransformFeedbackVarying (const std::string& varName)
    404 {
    405 	m_xfbVaryings.push_back(varName);
    406 }
    407 
    408 const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const
    409 {
    410 	return m_xfbVaryings;
    411 }
    412 
    413 void Program::setTransformFeedbackMode (deUint32 mode)
    414 {
    415 	m_xfbMode = mode;
    416 }
    417 
    418 deUint32 Program::getTransformFeedbackMode (void) const
    419 {
    420 	return m_xfbMode;
    421 }
    422 
    423 bool Program::isValid (void) const
    424 {
    425 	bool computePresent = false;
    426 
    427 	if (m_shaders.empty())
    428 		return false;
    429 
    430 	for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
    431 		if (!m_shaders[ndx]->isValid())
    432 			return false;
    433 
    434 	// same version
    435 	for (int ndx = 1; ndx < (int)m_shaders.size(); ++ndx)
    436 		if (m_shaders[0]->getVersion() != m_shaders[ndx]->getVersion())
    437 			return false;
    438 
    439 	// compute present -> no other stages present
    440 	{
    441 		bool nonComputePresent = false;
    442 
    443 		for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
    444 		{
    445 			if (m_shaders[ndx]->getType() == glu::SHADERTYPE_COMPUTE)
    446 				computePresent = true;
    447 			else
    448 				nonComputePresent = true;
    449 		}
    450 
    451 		if (computePresent && nonComputePresent)
    452 			return false;
    453 	}
    454 
    455 	// must contain both vertex and fragment shaders
    456 	if (!computePresent && !m_separable)
    457 	{
    458 		bool vertexPresent = false;
    459 		bool fragmentPresent = false;
    460 
    461 		for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
    462 		{
    463 			if (m_shaders[ndx]->getType() == glu::SHADERTYPE_VERTEX)
    464 				vertexPresent = true;
    465 			else if (m_shaders[ndx]->getType() == glu::SHADERTYPE_FRAGMENT)
    466 				fragmentPresent = true;
    467 		}
    468 
    469 		if (!vertexPresent || !fragmentPresent)
    470 			return false;
    471 	}
    472 
    473 	// tess.Eval present <=> tess.Control present
    474 	{
    475 		bool tessEvalPresent = false;
    476 		bool tessControlPresent = false;
    477 
    478 		for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
    479 		{
    480 			if (m_shaders[ndx]->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
    481 				tessEvalPresent = true;
    482 			else if (m_shaders[ndx]->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL)
    483 				tessControlPresent = true;
    484 		}
    485 
    486 		if (tessEvalPresent != tessControlPresent)
    487 			return false;
    488 	}
    489 
    490 	return true;
    491 }
    492 
    493 } // ProgramInterfaceDefinition
    494 } // Functional
    495 } // gles31
    496 } // deqp
    497