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 utilities
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fProgramInterfaceDefinitionUtil.hpp"
25 #include "es31fProgramInterfaceDefinition.hpp"
26 #include "gluVarType.hpp"
27 #include "gluVarTypeUtil.hpp"
28 #include "gluShaderUtil.hpp"
29 #include "deString.h"
30 #include "deStringUtil.hpp"
31 #include "glwEnums.hpp"
32 
33 #include <set>
34 #include <map>
35 #include <sstream>
36 #include <vector>
37 #include <algorithm>
38 
39 namespace deqp
40 {
41 namespace gles31
42 {
43 namespace Functional
44 {
45 namespace ProgramInterfaceDefinition
46 {
47 
VariableSearchFilter(void)48 VariableSearchFilter::VariableSearchFilter (void)
49 	: m_shaderTypeBits	(0xFFFFFFFFul)
50 	, m_storageBits		(0xFFFFFFFFul)
51 {
52 }
53 
createShaderTypeFilter(glu::ShaderType type)54 VariableSearchFilter VariableSearchFilter::createShaderTypeFilter (glu::ShaderType type)
55 {
56 	DE_ASSERT(type < glu::SHADERTYPE_LAST);
57 
58 	VariableSearchFilter filter;
59 	filter.m_shaderTypeBits = (1u << type);
60 	return filter;
61 }
62 
createStorageFilter(glu::Storage storage)63 VariableSearchFilter VariableSearchFilter::createStorageFilter (glu::Storage storage)
64 {
65 	DE_ASSERT(storage < glu::STORAGE_LAST);
66 
67 	VariableSearchFilter filter;
68 	filter.m_storageBits = (1u << storage);
69 	return filter;
70 }
71 
createShaderTypeStorageFilter(glu::ShaderType type,glu::Storage storage)72 VariableSearchFilter VariableSearchFilter::createShaderTypeStorageFilter (glu::ShaderType type, glu::Storage storage)
73 {
74 	return logicalAnd(createShaderTypeFilter(type), createStorageFilter(storage));
75 }
76 
logicalOr(const VariableSearchFilter & a,const VariableSearchFilter & b)77 VariableSearchFilter VariableSearchFilter::logicalOr (const VariableSearchFilter& a, const VariableSearchFilter& b)
78 {
79 	VariableSearchFilter filter;
80 	filter.m_shaderTypeBits	= a.m_shaderTypeBits | b.m_shaderTypeBits;
81 	filter.m_storageBits	= a.m_storageBits | b.m_storageBits;
82 	return filter;
83 }
84 
logicalAnd(const VariableSearchFilter & a,const VariableSearchFilter & b)85 VariableSearchFilter VariableSearchFilter::logicalAnd (const VariableSearchFilter& a, const VariableSearchFilter& b)
86 {
87 	VariableSearchFilter filter;
88 	filter.m_shaderTypeBits	= a.m_shaderTypeBits & b.m_shaderTypeBits;
89 	filter.m_storageBits	= a.m_storageBits & b.m_storageBits;
90 	return filter;
91 }
92 
matchesFilter(const ProgramInterfaceDefinition::Shader * shader) const93 bool VariableSearchFilter::matchesFilter (const ProgramInterfaceDefinition::Shader* shader) const
94 {
95 	DE_ASSERT(shader->getType() < glu::SHADERTYPE_LAST);
96 	return (m_shaderTypeBits & (1u << shader->getType())) != 0;
97 }
98 
matchesFilter(const glu::VariableDeclaration & variable) const99 bool VariableSearchFilter::matchesFilter (const glu::VariableDeclaration& variable) const
100 {
101 	DE_ASSERT(variable.storage < glu::STORAGE_LAST);
102 	return (m_storageBits & (1u << variable.storage)) != 0;
103 }
104 
matchesFilter(const glu::InterfaceBlock & block) const105 bool VariableSearchFilter::matchesFilter (const glu::InterfaceBlock& block) const
106 {
107 	DE_ASSERT(block.storage < glu::STORAGE_LAST);
108 	return (m_storageBits & (1u << block.storage)) != 0;
109 }
110 
111 } // ProgramInterfaceDefinition
112 
incrementMultiDimensionIndex(std::vector<int> & index,const std::vector<int> & dimensions)113 static bool incrementMultiDimensionIndex (std::vector<int>& index, const std::vector<int>& dimensions)
114 {
115 	int incrementDimensionNdx = (int)(index.size() - 1);
116 
117 	while (incrementDimensionNdx >= 0)
118 	{
119 		if (++index[incrementDimensionNdx] == dimensions[incrementDimensionNdx])
120 			index[incrementDimensionNdx--] = 0;
121 		else
122 			break;
123 	}
124 
125 	return (incrementDimensionNdx != -1);
126 }
127 
programContainsIOBlocks(const ProgramInterfaceDefinition::Program * program)128 bool programContainsIOBlocks (const ProgramInterfaceDefinition::Program* program)
129 {
130 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
131 	{
132 		if (shaderContainsIOBlocks(program->getShaders()[shaderNdx]))
133 			return true;
134 	}
135 
136 	return false;
137 }
138 
shaderContainsIOBlocks(const ProgramInterfaceDefinition::Shader * shader)139 bool shaderContainsIOBlocks (const ProgramInterfaceDefinition::Shader* shader)
140 {
141 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
142 	{
143 		const glu::Storage storage = shader->getDefaultBlock().interfaceBlocks[ndx].storage;
144 		if (storage == glu::STORAGE_IN			||
145 			storage == glu::STORAGE_OUT			||
146 			storage == glu::STORAGE_PATCH_IN	||
147 			storage == glu::STORAGE_PATCH_OUT)
148 		{
149 			return true;
150 		}
151 	}
152 	return false;
153 }
154 
getProgramTransformFeedbackStage(const ProgramInterfaceDefinition::Program * program)155 glu::ShaderType getProgramTransformFeedbackStage (const ProgramInterfaceDefinition::Program* program)
156 {
157 	if (program->hasStage(glu::SHADERTYPE_GEOMETRY))
158 		return glu::SHADERTYPE_GEOMETRY;
159 
160 	if (program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
161 		return glu::SHADERTYPE_TESSELLATION_EVALUATION;
162 
163 	if (program->hasStage(glu::SHADERTYPE_VERTEX))
164 		return glu::SHADERTYPE_VERTEX;
165 
166 	DE_ASSERT(false);
167 	return glu::SHADERTYPE_LAST;
168 }
169 
generateVariableTypeResourceNames(std::vector<std::string> & resources,const std::string & name,const glu::VarType & type,deUint32 resourceNameGenerationFlags)170 void generateVariableTypeResourceNames (std::vector<std::string>& resources, const std::string& name, const glu::VarType& type, deUint32 resourceNameGenerationFlags)
171 {
172 	DE_ASSERT((resourceNameGenerationFlags & (~RESOURCE_NAME_GENERATION_FLAG_MASK)) == 0);
173 
174 	// remove top-level flag from children
175 	const deUint32 childFlags = resourceNameGenerationFlags & ~((deUint32)RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE);
176 
177 	if (type.isBasicType())
178 		resources.push_back(name);
179 	else if (type.isStructType())
180 	{
181 		const glu::StructType* structType = type.getStructPtr();
182 		for (int ndx = 0; ndx < structType->getNumMembers(); ++ndx)
183 			generateVariableTypeResourceNames(resources, name + "." + structType->getMember(ndx).getName(), structType->getMember(ndx).getType(), childFlags);
184 	}
185 	else if (type.isArrayType())
186 	{
187 		// Bottom-level arrays of basic types of a transform feedback variable will produce only the first
188 		// element but without the trailing "[0]"
189 		if (type.getElementType().isBasicType() &&
190 			(resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE) != 0)
191 		{
192 			resources.push_back(name);
193 		}
194 		// Bottom-level arrays of basic types and SSBO top-level arrays of any type procude only first element
195 		else if (type.getElementType().isBasicType() ||
196 				 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) != 0)
197 		{
198 			generateVariableTypeResourceNames(resources, name + "[0]", type.getElementType(), childFlags);
199 		}
200 		// Other arrays of aggregate types are expanded
201 		else
202 		{
203 			for (int ndx = 0; ndx < type.getArraySize(); ++ndx)
204 				generateVariableTypeResourceNames(resources, name + "[" + de::toString(ndx) + "]", type.getElementType(), childFlags);
205 		}
206 	}
207 	else
208 		DE_ASSERT(false);
209 }
210 
211 // Program source generation
212 
213 namespace
214 {
215 
216 using ProgramInterfaceDefinition::VariablePathComponent;
217 using ProgramInterfaceDefinition::VariableSearchFilter;
218 
getShaderExtensionDeclarations(const ProgramInterfaceDefinition::Shader * shader)219 static std::string getShaderExtensionDeclarations (const ProgramInterfaceDefinition::Shader* shader)
220 {
221 	std::vector<std::string>	extensions;
222 	std::ostringstream			buf;
223 
224 	if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
225 	{
226 		extensions.push_back("GL_EXT_geometry_shader");
227 	}
228 	else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL ||
229 			 shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
230 	{
231 		extensions.push_back("GL_EXT_tessellation_shader");
232 	}
233 
234 	if (shaderContainsIOBlocks(shader))
235 		extensions.push_back("GL_EXT_shader_io_blocks");
236 
237 	for (int ndx = 0; ndx < (int)extensions.size(); ++ndx)
238 		buf << "#extension " << extensions[ndx] << " : require\n";
239 	return buf.str();
240 }
241 
getShaderTypeDeclarations(const ProgramInterfaceDefinition::Program * program,glu::ShaderType type)242 static std::string getShaderTypeDeclarations (const ProgramInterfaceDefinition::Program* program, glu::ShaderType type)
243 {
244 	switch (type)
245 	{
246 		case glu::SHADERTYPE_VERTEX:
247 			return "";
248 
249 		case glu::SHADERTYPE_FRAGMENT:
250 			return "";
251 
252 		case glu::SHADERTYPE_GEOMETRY:
253 		{
254 			std::ostringstream buf;
255 			buf <<	"layout(points) in;\n"
256 					"layout(points, max_vertices=" << program->getGeometryNumOutputVertices() << ") out;\n";
257 			return buf.str();
258 		}
259 
260 		case glu::SHADERTYPE_TESSELLATION_CONTROL:
261 		{
262 			std::ostringstream buf;
263 			buf << "layout(vertices=" << program->getTessellationNumOutputPatchVertices() << ") out;\n";
264 			return buf.str();
265 		}
266 
267 		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
268 			return "layout(triangles, point_mode) in;\n";
269 
270 		case glu::SHADERTYPE_COMPUTE:
271 			return "layout(local_size_x=1) in;\n";
272 
273 		default:
274 			DE_ASSERT(false);
275 			return "";
276 	}
277 }
278 
279 class StructNameEqualPredicate
280 {
281 public:
StructNameEqualPredicate(const char * name)282 				StructNameEqualPredicate	(const char* name) : m_name(name) { }
operator ()(const glu::StructType * type)283 	bool		operator()					(const glu::StructType* type) { return type->hasTypeName() && (deStringEqual(m_name, type->getTypeName()) == DE_TRUE); }
284 private:
285 	const char*	m_name;
286 };
287 
collectNamedStructureDefinitions(std::vector<const glu::StructType * > & dst,const glu::VarType & type)288 static void collectNamedStructureDefinitions (std::vector<const glu::StructType*>& dst, const glu::VarType& type)
289 {
290 	if (type.isBasicType())
291 		return;
292 	else if (type.isArrayType())
293 		return collectNamedStructureDefinitions(dst, type.getElementType());
294 	else if (type.isStructType())
295 	{
296 		if (type.getStructPtr()->hasTypeName())
297 		{
298 			// must be unique (may share the the same struct)
299 			std::vector<const glu::StructType*>::iterator where = std::find_if(dst.begin(), dst.end(), StructNameEqualPredicate(type.getStructPtr()->getTypeName()));
300 			if (where != dst.end())
301 			{
302 				DE_ASSERT(**where == *type.getStructPtr());
303 
304 				// identical type has been added already, types of members must be added too
305 				return;
306 			}
307 		}
308 
309 		// Add types of members first
310 		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
311 			collectNamedStructureDefinitions(dst, type.getStructPtr()->getMember(ndx).getType());
312 
313 		dst.push_back(type.getStructPtr());
314 	}
315 	else
316 		DE_ASSERT(false);
317 }
318 
writeStructureDefinitions(std::ostringstream & buf,const ProgramInterfaceDefinition::DefaultBlock & defaultBlock)319 static void writeStructureDefinitions (std::ostringstream& buf, const ProgramInterfaceDefinition::DefaultBlock& defaultBlock)
320 {
321 	std::vector<const glu::StructType*> namedStructs;
322 
323 	// Collect all structs in post order
324 
325 	for (int ndx = 0; ndx < (int)defaultBlock.variables.size(); ++ndx)
326 		collectNamedStructureDefinitions(namedStructs, defaultBlock.variables[ndx].varType);
327 
328 	for (int blockNdx = 0; blockNdx < (int)defaultBlock.interfaceBlocks.size(); ++blockNdx)
329 		for (int ndx = 0; ndx < (int)defaultBlock.interfaceBlocks[blockNdx].variables.size(); ++ndx)
330 			collectNamedStructureDefinitions(namedStructs, defaultBlock.interfaceBlocks[blockNdx].variables[ndx].varType);
331 
332 	// Write
333 
334 	for (int structNdx = 0; structNdx < (int)namedStructs.size(); ++structNdx)
335 	{
336 		buf <<	"struct " << namedStructs[structNdx]->getTypeName() << "\n"
337 				"{\n";
338 
339 		for (int memberNdx = 0; memberNdx < namedStructs[structNdx]->getNumMembers(); ++memberNdx)
340 			buf << glu::indent(1) << glu::declare(namedStructs[structNdx]->getMember(memberNdx).getType(), namedStructs[structNdx]->getMember(memberNdx).getName(), 1) << ";\n";
341 
342 		buf <<	"};\n";
343 	}
344 
345 	if (!namedStructs.empty())
346 		buf << "\n";
347 }
348 
writeInterfaceBlock(std::ostringstream & buf,const glu::InterfaceBlock & interfaceBlock)349 static void writeInterfaceBlock (std::ostringstream& buf, const glu::InterfaceBlock& interfaceBlock)
350 {
351 	buf << interfaceBlock.layout;
352 
353 	if (interfaceBlock.layout != glu::Layout())
354 		buf << " ";
355 
356 	buf	<< glu::getStorageName(interfaceBlock.storage) << " " << interfaceBlock.interfaceName << "\n"
357 		<< "{\n";
358 
359 	for (int ndx = 0; ndx < (int)interfaceBlock.variables.size(); ++ndx)
360 		buf << glu::indent(1) << interfaceBlock.variables[ndx] << ";\n";
361 
362 	buf << "}";
363 
364 	if (!interfaceBlock.instanceName.empty())
365 		buf << " " << interfaceBlock.instanceName;
366 
367 	for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
368 		buf << "[" << interfaceBlock.dimensions[dimensionNdx] << "]";
369 
370 	buf << ";\n\n";
371 }
372 
isReadableInterface(const glu::InterfaceBlock & interface)373 static bool isReadableInterface (const glu::InterfaceBlock& interface)
374 {
375 	return	interface.storage == glu::STORAGE_UNIFORM	||
376 			interface.storage == glu::STORAGE_IN		||
377 			interface.storage == glu::STORAGE_PATCH_IN	||
378 			(interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_WRITEONLY_BIT) == 0);
379 }
380 
isWritableInterface(const glu::InterfaceBlock & interface)381 static bool isWritableInterface (const glu::InterfaceBlock& interface)
382 {
383 	return	interface.storage == glu::STORAGE_OUT		||
384 			interface.storage == glu::STORAGE_PATCH_OUT	||
385 			(interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_READONLY_BIT) == 0);
386 }
387 
388 
writeVariableReadAccumulateExpression(std::ostringstream & buf,const std::string & accumulatorName,const std::string & name,glu::ShaderType shaderType,glu::Storage storage,const ProgramInterfaceDefinition::Program * program,const glu::VarType & varType)389 static void writeVariableReadAccumulateExpression (std::ostringstream&							buf,
390 												   const std::string&							accumulatorName,
391 												   const std::string&							name,
392 												   glu::ShaderType								shaderType,
393 												   glu::Storage									storage,
394 												   const ProgramInterfaceDefinition::Program*	program,
395 												   const glu::VarType&							varType)
396 {
397 	if (varType.isBasicType())
398 	{
399 		buf << "\t" << accumulatorName << " += ";
400 
401 		if (glu::isDataTypeScalar(varType.getBasicType()))
402 			buf << "vec4(float(" << name << "))";
403 		else if (glu::isDataTypeVector(varType.getBasicType()))
404 			buf << "vec4(" << name << ".xyxy)";
405 		else if (glu::isDataTypeMatrix(varType.getBasicType()))
406 			buf << "vec4(float(" << name << "[0][0]))";
407 		else if (glu::isDataTypeSamplerMultisample(varType.getBasicType()))
408 			buf << "vec4(float(textureSize(" << name << ").x))";
409 		else if (glu::isDataTypeSampler(varType.getBasicType()))
410 			buf << "vec4(float(textureSize(" << name << ", 0).x))";
411 		else if (glu::isDataTypeImage(varType.getBasicType()))
412 			buf << "vec4(float(imageSize(" << name << ").x))";
413 		else if (varType.getBasicType() == glu::TYPE_UINT_ATOMIC_COUNTER)
414 			buf << "vec4(float(atomicCounterIncrement(" << name << ")))";
415 		else
416 			DE_ASSERT(false);
417 
418 		buf << ";\n";
419 	}
420 	else if (varType.isStructType())
421 	{
422 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
423 			writeVariableReadAccumulateExpression(buf,
424 												  accumulatorName,
425 												  name + "." + varType.getStructPtr()->getMember(ndx).getName(),
426 												  shaderType,
427 												  storage,
428 												  program,
429 												  varType.getStructPtr()->getMember(ndx).getType());
430 	}
431 	else if (varType.isArrayType())
432 	{
433 		if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
434 		{
435 			for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
436 				writeVariableReadAccumulateExpression(buf,
437 													  accumulatorName,
438 													  name + "[" + de::toString(ndx) + "]",
439 													  shaderType,
440 													  storage,
441 													  program,
442 													  varType.getElementType());
443 		}
444 		else if (storage == glu::STORAGE_BUFFER)
445 		{
446 			// run-time sized array, read arbitrary
447 			writeVariableReadAccumulateExpression(buf,
448 												  accumulatorName,
449 												  name + "[8]",
450 												  shaderType,
451 												  storage,
452 												  program,
453 												  varType.getElementType());
454 		}
455 		else
456 		{
457 			DE_ASSERT(storage == glu::STORAGE_IN);
458 
459 			if (shaderType == glu::SHADERTYPE_GEOMETRY)
460 			{
461 				// implicit sized geometry input array, size = primitive size. Just reading first is enough
462 				writeVariableReadAccumulateExpression(buf,
463 													  accumulatorName,
464 													  name + "[0]",
465 													  shaderType,
466 													  storage,
467 													  program,
468 													  varType.getElementType());
469 			}
470 			else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
471 			{
472 				// implicit sized tessellation input array, size = input patch max size. Just reading current is enough
473 				writeVariableReadAccumulateExpression(buf,
474 													  accumulatorName,
475 													  name + "[gl_InvocationID]",
476 													  shaderType,
477 													  storage,
478 													  program,
479 													  varType.getElementType());
480 			}
481 			else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
482 			{
483 				// implicit sized tessellation input array, size = output patch max size. Read all to prevent optimizations
484 				DE_ASSERT(program->getTessellationNumOutputPatchVertices() > 0);
485 				for (int ndx = 0; ndx < (int)program->getTessellationNumOutputPatchVertices(); ++ndx)
486 				{
487 					writeVariableReadAccumulateExpression(buf,
488 														  accumulatorName,
489 														  name + "[" + de::toString(ndx) + "]",
490 														  shaderType,
491 														  storage,
492 														  program,
493 														  varType.getElementType());
494 				}
495 			}
496 			else
497 				DE_ASSERT(false);
498 		}
499 	}
500 	else
501 		DE_ASSERT(false);
502 }
503 
writeInterfaceReadAccumulateExpression(std::ostringstream & buf,const std::string & accumulatorName,const glu::InterfaceBlock & block,glu::ShaderType shaderType,const ProgramInterfaceDefinition::Program * program)504 static void writeInterfaceReadAccumulateExpression (std::ostringstream&							buf,
505 													const std::string&							accumulatorName,
506 													const glu::InterfaceBlock&					block,
507 													glu::ShaderType								shaderType,
508 													const ProgramInterfaceDefinition::Program*	program)
509 {
510 	if (block.dimensions.empty())
511 	{
512 		const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
513 
514 		for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
515 		{
516 			writeVariableReadAccumulateExpression(buf,
517 												  accumulatorName,
518 												  prefix + block.variables[ndx].name,
519 												  shaderType,
520 												  block.storage,
521 												  program,
522 												  block.variables[ndx].varType);
523 		}
524 	}
525 	else
526 	{
527 		std::vector<int> index(block.dimensions.size(), 0);
528 
529 		for (;;)
530 		{
531 			// access element
532 			{
533 				std::ostringstream name;
534 				name << block.instanceName;
535 
536 				for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
537 					name << "[" << index[dimensionNdx] << "]";
538 
539 				for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
540 				{
541 					writeVariableReadAccumulateExpression(buf,
542 														  accumulatorName,
543 														  name.str() + "." + block.variables[ndx].name,
544 														  shaderType,
545 														  block.storage,
546 														  program,
547 														  block.variables[ndx].varType);
548 				}
549 			}
550 
551 			// increment index
552 			if (!incrementMultiDimensionIndex(index, block.dimensions))
553 				break;
554 		}
555 	}
556 }
557 
writeVariableWriteExpression(std::ostringstream & buf,const std::string & sourceVec4Name,const std::string & name,glu::ShaderType shaderType,glu::Storage storage,const ProgramInterfaceDefinition::Program * program,const glu::VarType & varType)558 static void writeVariableWriteExpression (std::ostringstream&							buf,
559 										  const std::string&							sourceVec4Name,
560 										  const std::string&							name,
561 										  glu::ShaderType								shaderType,
562 										  glu::Storage									storage,
563 										  const ProgramInterfaceDefinition::Program*	program,
564 										  const glu::VarType&							varType)
565 {
566 	if (varType.isBasicType())
567 	{
568 		buf << "\t" << name << " = ";
569 
570 		if (glu::isDataTypeScalar(varType.getBasicType()))
571 			buf << glu::getDataTypeName(varType.getBasicType()) << "(" << sourceVec4Name << ".y)";
572 		else if (glu::isDataTypeVector(varType.getBasicType()) || glu::isDataTypeMatrix(varType.getBasicType()))
573 			buf << glu::getDataTypeName(varType.getBasicType()) << "(" << glu::getDataTypeName(glu::getDataTypeScalarType(varType.getBasicType())) << "(" << sourceVec4Name << ".y))";
574 		else
575 			DE_ASSERT(false);
576 
577 		buf << ";\n";
578 	}
579 	else if (varType.isStructType())
580 	{
581 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
582 			writeVariableWriteExpression(buf,
583 										 sourceVec4Name,
584 										 name + "." + varType.getStructPtr()->getMember(ndx).getName(),
585 										 shaderType,
586 										 storage,
587 										 program,
588 										 varType.getStructPtr()->getMember(ndx).getType());
589 	}
590 	else if (varType.isArrayType())
591 	{
592 		if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
593 		{
594 			for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
595 				writeVariableWriteExpression(buf,
596 											 sourceVec4Name,
597 											 name + "[" + de::toString(ndx) + "]",
598 											 shaderType,
599 											 storage,
600 											 program,
601 											 varType.getElementType());
602 		}
603 		else if (storage == glu::STORAGE_BUFFER)
604 		{
605 			// run-time sized array, write arbitrary
606 			writeVariableWriteExpression(buf,
607 										 sourceVec4Name,
608 										 name + "[9]",
609 										 shaderType,
610 										 storage,
611 										 program,
612 										 varType.getElementType());
613 		}
614 		else
615 		{
616 			DE_ASSERT(storage == glu::STORAGE_OUT);
617 
618 			if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
619 			{
620 				// implicit sized tessellation onput array, size = output patch max size. Can only write to gl_InvocationID
621 				writeVariableWriteExpression(buf,
622 											 sourceVec4Name,
623 											 name + "[gl_InvocationID]",
624 											 shaderType,
625 											 storage,
626 											 program,
627 											 varType.getElementType());
628 			}
629 			else
630 				DE_ASSERT(false);
631 		}
632 	}
633 	else
634 		DE_ASSERT(false);
635 }
636 
writeInterfaceWriteExpression(std::ostringstream & buf,const std::string & sourceVec4Name,const glu::InterfaceBlock & block,glu::ShaderType shaderType,const ProgramInterfaceDefinition::Program * program)637 static void writeInterfaceWriteExpression (std::ostringstream&							buf,
638 										   const std::string&							sourceVec4Name,
639 										   const glu::InterfaceBlock&					block,
640 										   glu::ShaderType								shaderType,
641 										   const ProgramInterfaceDefinition::Program*	program)
642 {
643 	if (block.dimensions.empty())
644 	{
645 		const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
646 
647 		for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
648 		{
649 			writeVariableWriteExpression(buf,
650 										 sourceVec4Name,
651 										 prefix + block.variables[ndx].name,
652 										 shaderType,
653 										 block.storage,
654 										 program,
655 										 block.variables[ndx].varType);
656 		}
657 	}
658 	else
659 	{
660 		std::vector<int> index(block.dimensions.size(), 0);
661 
662 		for (;;)
663 		{
664 			// access element
665 			{
666 				std::ostringstream name;
667 				name << block.instanceName;
668 
669 				for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
670 					name << "[" << index[dimensionNdx] << "]";
671 
672 				for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
673 				{
674 					writeVariableWriteExpression(buf,
675 												 sourceVec4Name,
676 												 name.str() + "." + block.variables[ndx].name,
677 												 shaderType,
678 												 block.storage,
679 												 program,
680 												 block.variables[ndx].varType);
681 				}
682 			}
683 
684 			// increment index
685 			if (!incrementMultiDimensionIndex(index, block.dimensions))
686 				break;
687 		}
688 	}
689 }
690 
traverseVariablePath(std::vector<VariablePathComponent> & typePath,const char * subPath,const glu::VarType & type)691 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const char* subPath, const glu::VarType& type)
692 {
693 	glu::VarTokenizer tokenizer(subPath);
694 
695 	typePath.push_back(VariablePathComponent(&type));
696 
697 	if (tokenizer.getToken() == glu::VarTokenizer::TOKEN_END)
698 		return true;
699 
700 	if (type.isStructType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_PERIOD)
701 	{
702 		tokenizer.advance();
703 
704 		// malformed path
705 		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_IDENTIFIER)
706 			return false;
707 
708 		for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx)
709 			if (type.getStructPtr()->getMember(memberNdx).getName() == tokenizer.getIdentifier())
710 				return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getStructPtr()->getMember(memberNdx).getType());
711 
712 		// malformed path, no such member
713 		return false;
714 	}
715 	else if (type.isArrayType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
716 	{
717 		tokenizer.advance();
718 
719 		// malformed path
720 		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_NUMBER)
721 			return false;
722 
723 		tokenizer.advance();
724 		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_RIGHT_BRACKET)
725 			return false;
726 
727 		return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getElementType());
728 	}
729 
730 	return false;
731 }
732 
traverseVariablePath(std::vector<VariablePathComponent> & typePath,const std::string & path,const glu::VariableDeclaration & var)733 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const std::string& path, const glu::VariableDeclaration& var)
734 {
735 	if (glu::parseVariableName(path.c_str()) != var.name)
736 		return false;
737 
738 	typePath.push_back(VariablePathComponent(&var));
739 	return traverseVariablePath(typePath, path.c_str() + var.name.length(), var.varType);
740 }
741 
traverseShaderVariablePath(std::vector<VariablePathComponent> & typePath,const ProgramInterfaceDefinition::Shader * shader,const std::string & path,const VariableSearchFilter & filter)742 static bool traverseShaderVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Shader* shader, const std::string& path, const VariableSearchFilter& filter)
743 {
744 	// Default block variable?
745 	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
746 		if (filter.matchesFilter(shader->getDefaultBlock().variables[varNdx]))
747 			if (traverseVariablePath(typePath, path, shader->getDefaultBlock().variables[varNdx]))
748 				return true;
749 
750 	// is variable an interface block variable?
751 	{
752 		const std::string blockName = glu::parseVariableName(path.c_str());
753 
754 		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
755 		{
756 			if (!filter.matchesFilter(shader->getDefaultBlock().interfaceBlocks[interfaceNdx]))
757 				continue;
758 
759 			if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName)
760 			{
761 				// resource is a member of a named interface block
762 				// \note there is no array index specifier even if the interface is declared as an array of instances
763 				const std::string blockMemberPath = path.substr(blockName.size() + 1);
764 				const std::string blockMemeberName = glu::parseVariableName(blockMemberPath.c_str());
765 
766 				for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
767 				{
768 					if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
769 					{
770 						typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
771 						return traverseVariablePath(typePath, blockMemberPath, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
772 					}
773 				}
774 
775 				// terminate search
776 				return false;
777 			}
778 			else if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].instanceName.empty())
779 			{
780 				const std::string blockMemeberName = glu::parseVariableName(path.c_str());
781 
782 				// unnamed block contains such variable?
783 				for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
784 				{
785 					if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
786 					{
787 						typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
788 						return traverseVariablePath(typePath, path, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
789 					}
790 				}
791 
792 				// continue search
793 			}
794 		}
795 	}
796 
797 	return false;
798 }
799 
traverseProgramVariablePath(std::vector<VariablePathComponent> & typePath,const ProgramInterfaceDefinition::Program * program,const std::string & path,const VariableSearchFilter & filter)800 static bool traverseProgramVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& path, const VariableSearchFilter& filter)
801 {
802 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
803 	{
804 		const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
805 
806 		if (filter.matchesFilter(shader))
807 		{
808 			// \note modifying output variable even when returning false
809 			typePath.clear();
810 			if (traverseShaderVariablePath(typePath, shader, path, filter))
811 				return true;
812 		}
813 	}
814 
815 	return false;
816 }
817 
containsSubType(const glu::VarType & complexType,glu::DataType basicType)818 static bool containsSubType (const glu::VarType& complexType, glu::DataType basicType)
819 {
820 	if (complexType.isBasicType())
821 	{
822 		return complexType.getBasicType() == basicType;
823 	}
824 	else if (complexType.isArrayType())
825 	{
826 		return containsSubType(complexType.getElementType(), basicType);
827 	}
828 	else if (complexType.isStructType())
829 	{
830 		for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
831 			if (containsSubType(complexType.getStructPtr()->getMember(ndx).getType(), basicType))
832 				return true;
833 		return false;
834 	}
835 	else
836 	{
837 		DE_ASSERT(false);
838 		return false;
839 	}
840 }
841 
getNumShaderBlocks(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage)842 static int getNumShaderBlocks (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
843 {
844 	int retVal = 0;
845 
846 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
847 	{
848 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
849 		{
850 			int numInstances = 1;
851 
852 			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
853 				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
854 
855 			retVal += numInstances;
856 		}
857 	}
858 
859 	return retVal;
860 }
861 
getNumAtomicCounterBuffers(const ProgramInterfaceDefinition::Shader * shader)862 static int getNumAtomicCounterBuffers (const ProgramInterfaceDefinition::Shader* shader)
863 {
864 	std::set<int> buffers;
865 
866 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
867 	{
868 		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
869 		{
870 			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
871 			buffers.insert(shader->getDefaultBlock().variables[ndx].layout.binding);
872 		}
873 	}
874 
875 	return (int)buffers.size();
876 }
877 
878 template <typename DataTypeMap>
accumulateComplexType(const glu::VarType & complexType,const DataTypeMap & dTypeMap)879 static int accumulateComplexType (const glu::VarType& complexType, const DataTypeMap& dTypeMap)
880 {
881 	if (complexType.isBasicType())
882 		return dTypeMap(complexType.getBasicType());
883 	else if (complexType.isArrayType())
884 	{
885 		const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize());
886 		return arraySize * accumulateComplexType(complexType.getElementType(), dTypeMap);
887 	}
888 	else if (complexType.isStructType())
889 	{
890 		int sum = 0;
891 		for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
892 			sum += accumulateComplexType(complexType.getStructPtr()->getMember(ndx).getType(), dTypeMap);
893 		return sum;
894 	}
895 	else
896 	{
897 		DE_ASSERT(false);
898 		return false;
899 	}
900 }
901 
902 template <typename InterfaceBlockFilter, typename VarDeclFilter, typename DataTypeMap>
accumulateShader(const ProgramInterfaceDefinition::Shader * shader,const InterfaceBlockFilter & ibFilter,const VarDeclFilter & vdFilter,const DataTypeMap & dMap)903 static int accumulateShader (const ProgramInterfaceDefinition::Shader* shader,
904 							 const InterfaceBlockFilter& ibFilter,
905 							 const VarDeclFilter& vdFilter,
906 							 const DataTypeMap& dMap)
907 {
908 	int retVal = 0;
909 
910 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
911 	{
912 		if (ibFilter(shader->getDefaultBlock().interfaceBlocks[ndx]))
913 		{
914 			int numInstances = 1;
915 
916 			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
917 				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
918 
919 			for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx)
920 				retVal += numInstances * accumulateComplexType(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, dMap);
921 		}
922 	}
923 
924 	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
925 		if (vdFilter(shader->getDefaultBlock().variables[varNdx]))
926 			retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, dMap);
927 
928 	return retVal;
929 }
930 
dummyTrueConstantTypeFilter(glu::DataType d)931 static bool dummyTrueConstantTypeFilter (glu::DataType d)
932 {
933 	DE_UNREF(d);
934 	return true;
935 }
936 
937 class InstanceCounter
938 {
939 public:
InstanceCounter(bool (* predicate)(glu::DataType))940 	InstanceCounter (bool (*predicate)(glu::DataType))
941 		: m_predicate(predicate)
942 	{
943 	}
944 
operator ()(glu::DataType t) const945 	int operator() (glu::DataType t) const
946 	{
947 		return (m_predicate(t)) ? (1) : (0);
948 	}
949 
950 private:
951 	bool (*const m_predicate)(glu::DataType);
952 };
953 
954 class InterfaceBlockStorageFilter
955 {
956 public:
InterfaceBlockStorageFilter(glu::Storage storage)957 	InterfaceBlockStorageFilter (glu::Storage storage)
958 		: m_storage(storage)
959 	{
960 	}
961 
operator ()(const glu::InterfaceBlock & b) const962 	bool operator() (const glu::InterfaceBlock& b) const
963 	{
964 		return m_storage == b.storage;
965 	}
966 
967 private:
968 	const glu::Storage m_storage;
969 };
970 
971 class VariableDeclarationStorageFilter
972 {
973 public:
VariableDeclarationStorageFilter(glu::Storage storage)974 	VariableDeclarationStorageFilter (glu::Storage storage)
975 		: m_storage(storage)
976 	{
977 	}
978 
operator ()(const glu::VariableDeclaration & d) const979 	bool operator() (const glu::VariableDeclaration& d) const
980 	{
981 		return m_storage == d.storage;
982 	}
983 
984 private:
985 	const glu::Storage m_storage;
986 };
987 
getNumTypeInstances(const glu::VarType & complexType,bool (* predicate)(glu::DataType))988 static int getNumTypeInstances (const glu::VarType& complexType, bool (*predicate)(glu::DataType))
989 {
990 	return accumulateComplexType(complexType, InstanceCounter(predicate));
991 }
992 
getNumTypeInstances(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage,bool (* predicate)(glu::DataType))993 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, bool (*predicate)(glu::DataType))
994 {
995 	return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), InstanceCounter(predicate));
996 }
997 
getNumTypeInstances(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage)998 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
999 {
1000 	return getNumTypeInstances(shader, storage, dummyTrueConstantTypeFilter);
1001 }
1002 
accumulateShaderStorage(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage,int (* typeMap)(glu::DataType))1003 static int accumulateShaderStorage (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, int (*typeMap)(glu::DataType))
1004 {
1005 	return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), typeMap);
1006 }
1007 
getNumDataTypeComponents(glu::DataType type)1008 static int getNumDataTypeComponents (glu::DataType type)
1009 {
1010 	if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type))
1011 		return glu::getDataTypeScalarSize(type);
1012 	else
1013 		return 0;
1014 }
1015 
getNumDataTypeVectors(glu::DataType type)1016 static int getNumDataTypeVectors (glu::DataType type)
1017 {
1018 	if (glu::isDataTypeScalar(type))
1019 		return 1;
1020 	else if (glu::isDataTypeVector(type))
1021 		return 1;
1022 	else if (glu::isDataTypeMatrix(type))
1023 		return glu::getDataTypeMatrixNumColumns(type);
1024 	else
1025 		return 0;
1026 }
1027 
getNumComponents(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage)1028 static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1029 {
1030 	return accumulateShaderStorage(shader, storage, getNumDataTypeComponents);
1031 }
1032 
getNumVectors(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage)1033 static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1034 {
1035 	return accumulateShaderStorage(shader, storage, getNumDataTypeVectors);
1036 }
1037 
getNumDefaultBlockComponents(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage)1038 static int getNumDefaultBlockComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1039 {
1040 	int retVal = 0;
1041 
1042 	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
1043 		if (shader->getDefaultBlock().variables[varNdx].storage == storage)
1044 			retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, getNumDataTypeComponents);
1045 
1046 	return retVal;
1047 }
1048 
getMaxBufferBinding(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage)1049 static int getMaxBufferBinding (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1050 {
1051 	int maxBinding = -1;
1052 
1053 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1054 	{
1055 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
1056 		{
1057 			const int	binding			= (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding);
1058 			int			numInstances	= 1;
1059 
1060 			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
1061 				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
1062 
1063 			maxBinding = de::max(maxBinding, binding + numInstances - 1);
1064 		}
1065 	}
1066 
1067 	return (int)maxBinding;
1068 }
1069 
getBufferTypeSize(glu::DataType type,glu::MatrixOrder order)1070 static int getBufferTypeSize (glu::DataType type, glu::MatrixOrder order)
1071 {
1072 	// assume vec4 alignments, should produce values greater than or equal to the actual resource usage
1073 	int numVectors = 0;
1074 
1075 	if (glu::isDataTypeScalarOrVector(type))
1076 		numVectors = 1;
1077 	else if (glu::isDataTypeMatrix(type) && order == glu::MATRIXORDER_ROW_MAJOR)
1078 		numVectors = glu::getDataTypeMatrixNumRows(type);
1079 	else if (glu::isDataTypeMatrix(type) && order != glu::MATRIXORDER_ROW_MAJOR)
1080 		numVectors = glu::getDataTypeMatrixNumColumns(type);
1081 	else
1082 		DE_ASSERT(false);
1083 
1084 	return 4 * numVectors;
1085 }
1086 
getBufferVariableSize(const glu::VarType & type,glu::MatrixOrder order)1087 static int getBufferVariableSize (const glu::VarType& type, glu::MatrixOrder order)
1088 {
1089 	if (type.isBasicType())
1090 		return getBufferTypeSize(type.getBasicType(), order);
1091 	else if (type.isArrayType())
1092 	{
1093 		const int arraySize = (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (type.getArraySize());
1094 		return arraySize * getBufferVariableSize(type.getElementType(), order);
1095 	}
1096 	else if (type.isStructType())
1097 	{
1098 		int sum = 0;
1099 		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
1100 			sum += getBufferVariableSize(type.getStructPtr()->getMember(ndx).getType(), order);
1101 		return sum;
1102 	}
1103 	else
1104 	{
1105 		DE_ASSERT(false);
1106 		return false;
1107 	}
1108 }
1109 
getBufferSize(const glu::InterfaceBlock & block,glu::MatrixOrder blockOrder)1110 static int getBufferSize (const glu::InterfaceBlock& block, glu::MatrixOrder blockOrder)
1111 {
1112 	int size = 0;
1113 
1114 	for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
1115 		size += getBufferVariableSize(block.variables[ndx].varType, (block.variables[ndx].layout.matrixOrder == glu::MATRIXORDER_LAST) ? (blockOrder) : (block.variables[ndx].layout.matrixOrder));
1116 
1117 	return size;
1118 }
1119 
getBufferMaxSize(const ProgramInterfaceDefinition::Shader * shader,glu::Storage storage)1120 static int getBufferMaxSize (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1121 {
1122 	int maxSize = 0;
1123 
1124 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1125 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
1126 			maxSize = de::max(maxSize, getBufferSize(shader->getDefaultBlock().interfaceBlocks[ndx], shader->getDefaultBlock().interfaceBlocks[ndx].layout.matrixOrder));
1127 
1128 	return (int)maxSize;
1129 }
1130 
getAtomicCounterMaxBinding(const ProgramInterfaceDefinition::Shader * shader)1131 static int getAtomicCounterMaxBinding (const ProgramInterfaceDefinition::Shader* shader)
1132 {
1133 	int maxBinding = -1;
1134 
1135 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1136 	{
1137 		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
1138 		{
1139 			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
1140 			maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding);
1141 		}
1142 	}
1143 
1144 	return (int)maxBinding;
1145 }
1146 
getUniformMaxBinding(const ProgramInterfaceDefinition::Shader * shader,bool (* predicate)(glu::DataType))1147 static int getUniformMaxBinding (const ProgramInterfaceDefinition::Shader* shader, bool (*predicate)(glu::DataType))
1148 {
1149 	int maxBinding = -1;
1150 
1151 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1152 	{
1153 		const int binding		= (shader->getDefaultBlock().variables[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.binding);
1154 		const int numInstances	= getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, predicate);
1155 
1156 		maxBinding = de::max(maxBinding, binding + numInstances - 1);
1157 	}
1158 
1159 	return maxBinding;
1160 }
1161 
getAtomicCounterMaxBufferSize(const ProgramInterfaceDefinition::Shader * shader)1162 static int getAtomicCounterMaxBufferSize (const ProgramInterfaceDefinition::Shader* shader)
1163 {
1164 	std::map<int, int>	bufferSizes;
1165 	int					maxSize			= 0;
1166 
1167 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1168 	{
1169 		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
1170 		{
1171 			const int bufferBinding	= shader->getDefaultBlock().variables[ndx].layout.binding;
1172 			const int offset		= (shader->getDefaultBlock().variables[ndx].layout.offset == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.offset);
1173 			const int size			= offset + 4 * getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, glu::isDataTypeAtomicCounter);
1174 
1175 			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
1176 
1177 			if (bufferSizes.find(bufferBinding) == bufferSizes.end())
1178 				bufferSizes[bufferBinding] = size;
1179 			else
1180 				bufferSizes[bufferBinding] = de::max<int>(bufferSizes[bufferBinding], size);
1181 		}
1182 	}
1183 
1184 	for (std::map<int, int>::iterator it = bufferSizes.begin(); it != bufferSizes.end(); ++it)
1185 		maxSize = de::max<int>(maxSize, it->second);
1186 
1187 	return maxSize;
1188 }
1189 
getNumFeedbackVaryingComponents(const ProgramInterfaceDefinition::Program * program,const std::string & name)1190 static int getNumFeedbackVaryingComponents (const ProgramInterfaceDefinition::Program* program, const std::string& name)
1191 {
1192 	std::vector<VariablePathComponent> path;
1193 
1194 	if (name == "gl_Position")
1195 		return 4;
1196 
1197 	DE_ASSERT(deStringBeginsWith(name.c_str(), "gl_") == DE_FALSE);
1198 
1199 	if (!traverseProgramVariablePath(path, program, name, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1200 		DE_ASSERT(false); // Program failed validate, invalid operation
1201 
1202 	return accumulateComplexType(*path.back().getVariableType(), getNumDataTypeComponents);
1203 }
1204 
getNumXFBComponents(const ProgramInterfaceDefinition::Program * program)1205 static int getNumXFBComponents (const ProgramInterfaceDefinition::Program* program)
1206 {
1207 	int numComponents = 0;
1208 
1209 	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1210 		numComponents += getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]);
1211 
1212 	return numComponents;
1213 }
1214 
getNumMaxXFBOutputComponents(const ProgramInterfaceDefinition::Program * program)1215 static int getNumMaxXFBOutputComponents (const ProgramInterfaceDefinition::Program* program)
1216 {
1217 	int numComponents = 0;
1218 
1219 	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1220 		numComponents = de::max(numComponents, getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]));
1221 
1222 	return numComponents;
1223 }
1224 
getFragmentOutputMaxLocation(const ProgramInterfaceDefinition::Shader * shader)1225 static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader)
1226 {
1227 	DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT);
1228 
1229 	int maxOutputLocation = -1;
1230 
1231 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1232 	{
1233 		if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT)
1234 		{
1235 			// missing location qualifier means location == 0
1236 			const int outputLocation		= (shader->getDefaultBlock().variables[ndx].layout.location == -1)
1237 												? (0)
1238 												: (shader->getDefaultBlock().variables[ndx].layout.location);
1239 
1240 			// only basic types or arrays of basic types possible
1241 			DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType());
1242 
1243 			const int locationSlotsTaken	= (shader->getDefaultBlock().variables[ndx].varType.isArrayType())
1244 												? (shader->getDefaultBlock().variables[ndx].varType.getArraySize())
1245 												: (1);
1246 
1247 			maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1);
1248 		}
1249 	}
1250 
1251 	return maxOutputLocation;
1252 }
1253 
1254 } // anonymous
1255 
getProgramInterfaceBlockMemberResourceList(const glu::InterfaceBlock & interfaceBlock)1256 std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock)
1257 {
1258 	const std::string			namePrefix					= (!interfaceBlock.instanceName.empty()) ? (interfaceBlock.interfaceName + ".") : ("");
1259 	const bool					isTopLevelBufferVariable	= (interfaceBlock.storage == glu::STORAGE_BUFFER);
1260 	std::vector<std::string>	resources;
1261 
1262 	// \note this is defined in the GLSL spec, not in the GL spec
1263 	for (int variableNdx = 0; variableNdx < (int)interfaceBlock.variables.size(); ++variableNdx)
1264 		generateVariableTypeResourceNames(resources,
1265 										  namePrefix + interfaceBlock.variables[variableNdx].name,
1266 										  interfaceBlock.variables[variableNdx].varType,
1267 										  (isTopLevelBufferVariable) ?
1268 											(RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) :
1269 											(RESOURCE_NAME_GENERATION_FLAG_DEFAULT));
1270 
1271 	return resources;
1272 }
1273 
getProgramInterfaceResourceList(const ProgramInterfaceDefinition::Program * program,ProgramInterface interface)1274 std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface)
1275 {
1276 	// The same {uniform (block), buffer (variable)} can exist in multiple shaders, remove duplicates but keep order
1277 	const bool					removeDuplicated	= (interface == PROGRAMINTERFACE_UNIFORM)			||
1278 													  (interface == PROGRAMINTERFACE_UNIFORM_BLOCK)		||
1279 													  (interface == PROGRAMINTERFACE_BUFFER_VARIABLE)	||
1280 													  (interface == PROGRAMINTERFACE_SHADER_STORAGE_BLOCK);
1281 	std::vector<std::string>	resources;
1282 
1283 	switch (interface)
1284 	{
1285 		case PROGRAMINTERFACE_UNIFORM:
1286 		case PROGRAMINTERFACE_BUFFER_VARIABLE:
1287 		{
1288 			const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
1289 
1290 			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1291 			{
1292 				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1293 
1294 				for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx)
1295 					if (shader->getDefaultBlock().variables[variableNdx].storage == storage)
1296 						generateVariableTypeResourceNames(resources,
1297 														  shader->getDefaultBlock().variables[variableNdx].name,
1298 														  shader->getDefaultBlock().variables[variableNdx].varType,
1299 														  RESOURCE_NAME_GENERATION_FLAG_DEFAULT);
1300 
1301 				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1302 				{
1303 					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1304 					if (interfaceBlock.storage == storage)
1305 					{
1306 						const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
1307 						resources.insert(resources.end(), blockResources.begin(), blockResources.end());
1308 					}
1309 				}
1310 			}
1311 			break;
1312 		}
1313 
1314 		case PROGRAMINTERFACE_UNIFORM_BLOCK:
1315 		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1316 		{
1317 			const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
1318 
1319 			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1320 			{
1321 				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1322 				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1323 				{
1324 					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1325 					if (interfaceBlock.storage == storage)
1326 					{
1327 						std::vector<int> index(interfaceBlock.dimensions.size(), 0);
1328 
1329 						for (;;)
1330 						{
1331 							// add resource string for each element
1332 							{
1333 								std::ostringstream name;
1334 								name << interfaceBlock.interfaceName;
1335 
1336 								for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
1337 									name << "[" << index[dimensionNdx] << "]";
1338 
1339 								resources.push_back(name.str());
1340 							}
1341 
1342 							// increment index
1343 							if (!incrementMultiDimensionIndex(index, interfaceBlock.dimensions))
1344 								break;
1345 						}
1346 					}
1347 				}
1348 			}
1349 			break;
1350 		}
1351 
1352 		case PROGRAMINTERFACE_PROGRAM_INPUT:
1353 		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1354 		{
1355 			const glu::Storage		queryStorage		= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
1356 			const glu::Storage		queryPatchStorage	= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT);
1357 			const glu::ShaderType	shaderType			= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (program->getFirstStage()) : (program->getLastStage());
1358 
1359 			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1360 			{
1361 				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1362 
1363 				if (shader->getType() != shaderType)
1364 					continue;
1365 
1366 				for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx)
1367 				{
1368 					const glu::Storage variableStorage = shader->getDefaultBlock().variables[variableNdx].storage;
1369 					if (variableStorage == queryStorage || variableStorage == queryPatchStorage)
1370 						generateVariableTypeResourceNames(resources,
1371 														  shader->getDefaultBlock().variables[variableNdx].name,
1372 														  shader->getDefaultBlock().variables[variableNdx].varType,
1373 														  RESOURCE_NAME_GENERATION_FLAG_DEFAULT);
1374 				}
1375 
1376 				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1377 				{
1378 					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1379 					if (interfaceBlock.storage == queryStorage || interfaceBlock.storage == queryPatchStorage)
1380 					{
1381 						const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
1382 						resources.insert(resources.end(), blockResources.begin(), blockResources.end());
1383 					}
1384 				}
1385 			}
1386 
1387 			// built-ins
1388 			if (interface == PROGRAMINTERFACE_PROGRAM_INPUT)
1389 			{
1390 				if (shaderType == glu::SHADERTYPE_VERTEX && resources.empty())
1391 					resources.push_back("gl_VertexID"); // only read from when there are no other inputs
1392 				else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
1393 					resources.push_back("gl_FragCoord"); // only read from when there are no other inputs
1394 				else if (shaderType == glu::SHADERTYPE_GEOMETRY)
1395 					resources.push_back("gl_PerVertex.gl_Position");
1396 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
1397 				{
1398 					resources.push_back("gl_InvocationID");
1399 					resources.push_back("gl_PerVertex.gl_Position");
1400 				}
1401 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1402 					resources.push_back("gl_PerVertex.gl_Position");
1403 				else if (shaderType == glu::SHADERTYPE_COMPUTE && resources.empty())
1404 					resources.push_back("gl_NumWorkGroups"); // only read from when there are no other inputs
1405 			}
1406 			else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT)
1407 			{
1408 				if (shaderType == glu::SHADERTYPE_VERTEX)
1409 					resources.push_back("gl_Position");
1410 				else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
1411 					resources.push_back("gl_FragDepth"); // only written to when there are no other outputs
1412 				else if (shaderType == glu::SHADERTYPE_GEOMETRY)
1413 					resources.push_back("gl_Position");
1414 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
1415 				{
1416 					resources.push_back("gl_PerVertex.gl_Position");
1417 					resources.push_back("gl_TessLevelOuter[0]");
1418 					resources.push_back("gl_TessLevelInner[0]");
1419 				}
1420 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1421 					resources.push_back("gl_Position");
1422 			}
1423 
1424 			break;
1425 		}
1426 
1427 		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1428 		{
1429 			const glu::ShaderType xfbStage = getProgramTransformFeedbackStage(program);
1430 
1431 			for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1432 			{
1433 				const std::string& varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
1434 
1435 				if (deStringBeginsWith(varyingName.c_str(), "gl_"))
1436 					resources.push_back(varyingName); // builtin
1437 				else
1438 				{
1439 					std::vector<VariablePathComponent> path;
1440 
1441 					if (!traverseProgramVariablePath(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(xfbStage, glu::STORAGE_OUT)))
1442 						DE_ASSERT(false); // Program failed validate, invalid operation
1443 
1444 					generateVariableTypeResourceNames(resources,
1445 													  varyingName,
1446 													  *path.back().getVariableType(),
1447 													  RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
1448 				}
1449 			}
1450 
1451 			break;
1452 		}
1453 
1454 		default:
1455 			DE_ASSERT(false);
1456 	}
1457 
1458 	if (removeDuplicated)
1459 	{
1460 		std::set<std::string>		addedVariables;
1461 		std::vector<std::string>	uniqueResouces;
1462 
1463 		for (int ndx = 0; ndx < (int)resources.size(); ++ndx)
1464 		{
1465 			if (addedVariables.find(resources[ndx]) == addedVariables.end())
1466 			{
1467 				addedVariables.insert(resources[ndx]);
1468 				uniqueResouces.push_back(resources[ndx]);
1469 			}
1470 		}
1471 
1472 		uniqueResouces.swap(resources);
1473 	}
1474 
1475 	return resources;
1476 }
1477 
1478 /**
1479  * Name of the dummy uniform added by generateProgramInterfaceProgramSources
1480  *
1481  * A uniform named "dummyZero" is added by
1482  * generateProgramInterfaceProgramSources.  It is used in expressions to
1483  * prevent various program resources from being eliminated by the GLSL
1484  * compiler's optimizer.
1485  *
1486  * \sa deqp::gles31::Functional::ProgramInterfaceDefinition::generateProgramInterfaceProgramSources
1487  */
getDummyZeroUniformName()1488 const char* getDummyZeroUniformName()
1489 {
1490 	return "dummyZero";
1491 }
1492 
generateProgramInterfaceProgramSources(const ProgramInterfaceDefinition::Program * program)1493 glu::ProgramSources generateProgramInterfaceProgramSources (const ProgramInterfaceDefinition::Program* program)
1494 {
1495 	glu::ProgramSources sources;
1496 
1497 	DE_ASSERT(program->isValid());
1498 
1499 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1500 	{
1501 		const ProgramInterfaceDefinition::Shader*	shader						= program->getShaders()[shaderNdx];
1502 		bool										containsUserDefinedOutputs	= false;
1503 		bool										containsUserDefinedInputs	= false;
1504 		std::ostringstream							sourceBuf;
1505 		std::ostringstream							usageBuf;
1506 
1507 		sourceBuf	<< glu::getGLSLVersionDeclaration(shader->getVersion()) << "\n"
1508 					<< getShaderExtensionDeclarations(shader)
1509 					<< getShaderTypeDeclarations(program, shader->getType())
1510 					<< "\n";
1511 
1512 		// Struct definitions
1513 
1514 		writeStructureDefinitions(sourceBuf, shader->getDefaultBlock());
1515 
1516 		// variables in the default scope
1517 
1518 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1519 			sourceBuf << shader->getDefaultBlock().variables[ndx] << ";\n";
1520 
1521 		if (!shader->getDefaultBlock().variables.empty())
1522 			sourceBuf << "\n";
1523 
1524 		// Interface blocks
1525 
1526 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1527 			writeInterfaceBlock(sourceBuf, shader->getDefaultBlock().interfaceBlocks[ndx]);
1528 
1529 		// Use inputs and outputs so that they won't be removed by the optimizer
1530 
1531 		usageBuf <<	"highp uniform vec4 " << getDummyZeroUniformName() << "; // Default value is vec4(0.0).\n"
1532 					"highp vec4 readInputs()\n"
1533 					"{\n"
1534 					"	highp vec4 retValue = " << getDummyZeroUniformName() << ";\n";
1535 
1536 		// User-defined inputs
1537 
1538 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1539 		{
1540 			if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_IN			||
1541 				shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_IN	||
1542 				shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_UNIFORM)
1543 			{
1544 				writeVariableReadAccumulateExpression(usageBuf,
1545 													  "retValue",
1546 													  shader->getDefaultBlock().variables[ndx].name,
1547 													  shader->getType(),
1548 													  shader->getDefaultBlock().variables[ndx].storage,
1549 													  program,
1550 													  shader->getDefaultBlock().variables[ndx].varType);
1551 				containsUserDefinedInputs = true;
1552 			}
1553 		}
1554 
1555 		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1556 		{
1557 			const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1558 			if (isReadableInterface(interface))
1559 			{
1560 				writeInterfaceReadAccumulateExpression(usageBuf,
1561 													   "retValue",
1562 													   interface,
1563 													   shader->getType(),
1564 													   program);
1565 				containsUserDefinedInputs = true;
1566 			}
1567 		}
1568 
1569 		// Built-in-inputs
1570 
1571 		switch (shader->getType())
1572 		{
1573 			case glu::SHADERTYPE_VERTEX:
1574 				// make readInputs to never be compile time constant
1575 				if (!containsUserDefinedInputs)
1576 					usageBuf << "	retValue += vec4(float(gl_VertexID));\n";
1577 				break;
1578 
1579 			case glu::SHADERTYPE_FRAGMENT:
1580 				// make readInputs to never be compile time constant
1581 				if (!containsUserDefinedInputs)
1582 					usageBuf << "	retValue += gl_FragCoord;\n";
1583 				break;
1584 			case glu::SHADERTYPE_GEOMETRY:
1585 				// always use previous stage's output values so that previous stage won't be optimized out
1586 				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
1587 				break;
1588 			case glu::SHADERTYPE_TESSELLATION_CONTROL:
1589 				// always use previous stage's output values so that previous stage won't be optimized out
1590 				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
1591 				break;
1592 			case glu::SHADERTYPE_TESSELLATION_EVALUATION:
1593 				// always use previous stage's output values so that previous stage won't be optimized out
1594 				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
1595 				break;
1596 
1597 			case glu::SHADERTYPE_COMPUTE:
1598 				// make readInputs to never be compile time constant
1599 				if (!containsUserDefinedInputs)
1600 					usageBuf << "	retValue += vec4(float(gl_NumWorkGroups.x));\n";
1601 				break;
1602 			default:
1603 				DE_ASSERT(false);
1604 		}
1605 
1606 		usageBuf <<	"	return retValue;\n"
1607 					"}\n\n";
1608 
1609 		usageBuf <<	"void writeOutputs(in highp vec4 dummyValue)\n"
1610 					"{\n";
1611 
1612 		// User-defined outputs
1613 
1614 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1615 		{
1616 			if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT ||
1617 				shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_OUT)
1618 			{
1619 				writeVariableWriteExpression(usageBuf,
1620 											 "dummyValue",
1621 											 shader->getDefaultBlock().variables[ndx].name,
1622 											 shader->getType(),
1623 											 shader->getDefaultBlock().variables[ndx].storage,
1624 											 program,
1625 											 shader->getDefaultBlock().variables[ndx].varType);
1626 				containsUserDefinedOutputs = true;
1627 			}
1628 		}
1629 
1630 		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1631 		{
1632 			const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1633 			if (isWritableInterface(interface))
1634 			{
1635 				writeInterfaceWriteExpression(usageBuf, "dummyValue", interface, shader->getType(), program);
1636 				containsUserDefinedOutputs = true;
1637 			}
1638 		}
1639 
1640 		// Builtin-outputs that must be written to
1641 
1642 		if (shader->getType() == glu::SHADERTYPE_VERTEX)
1643 			usageBuf << "	gl_Position = dummyValue;\n";
1644 		else if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
1645 			usageBuf << "	gl_Position = dummyValue;\n"
1646 						 "	EmitVertex();\n";
1647 		else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL)
1648 			usageBuf << "	gl_out[gl_InvocationID].gl_Position = dummyValue;\n"
1649 						"	gl_TessLevelOuter[0] = 2.8;\n"
1650 						"	gl_TessLevelOuter[1] = 2.8;\n"
1651 						"	gl_TessLevelOuter[2] = 2.8;\n"
1652 						"	gl_TessLevelOuter[3] = 2.8;\n"
1653 						"	gl_TessLevelInner[0] = 2.8;\n"
1654 						"	gl_TessLevelInner[1] = 2.8;\n";
1655 		else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1656 			usageBuf << "	gl_Position = dummyValue;\n";
1657 
1658 		// Output to sink input data to
1659 
1660 		if (!containsUserDefinedOutputs)
1661 		{
1662 			if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1663 				usageBuf << "	gl_FragDepth = dot(dummyValue.xy, dummyValue.xw);\n";
1664 			else if (shader->getType() == glu::SHADERTYPE_COMPUTE)
1665 				usageBuf << "	dummyOutputBlock.dummyValue = dummyValue;\n";
1666 		}
1667 
1668 		usageBuf <<	"}\n\n"
1669 					"void main()\n"
1670 					"{\n"
1671 					"	writeOutputs(readInputs());\n"
1672 					"}\n";
1673 
1674 		// Interface for dummy output
1675 
1676 		if (shader->getType() == glu::SHADERTYPE_COMPUTE && !containsUserDefinedOutputs)
1677 		{
1678 			sourceBuf	<< "writeonly buffer DummyOutputInterface\n"
1679 						<< "{\n"
1680 						<< "	highp vec4 dummyValue;\n"
1681 						<< "} dummyOutputBlock;\n\n";
1682 		}
1683 
1684 		sources << glu::ShaderSource(shader->getType(), sourceBuf.str() + usageBuf.str());
1685 	}
1686 
1687 	if (program->isSeparable())
1688 		sources << glu::ProgramSeparable(true);
1689 
1690 	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1691 		sources << glu::TransformFeedbackVarying(program->getTransformFeedbackVaryings()[ndx]);
1692 
1693 	if (program->getTransformFeedbackMode())
1694 		sources << glu::TransformFeedbackMode(program->getTransformFeedbackMode());
1695 
1696 	return sources;
1697 }
1698 
findProgramVariablePathByPathName(std::vector<VariablePathComponent> & typePath,const ProgramInterfaceDefinition::Program * program,const std::string & pathName,const VariableSearchFilter & filter)1699 bool findProgramVariablePathByPathName (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& pathName, const VariableSearchFilter& filter)
1700 {
1701 	std::vector<VariablePathComponent> modifiedPath;
1702 
1703 	if (!traverseProgramVariablePath(modifiedPath, program, pathName, filter))
1704 		return false;
1705 
1706 	// modify param only on success
1707 	typePath.swap(modifiedPath);
1708 	return true;
1709 }
1710 
getShaderResourceUsage(const ProgramInterfaceDefinition::Program * program,const ProgramInterfaceDefinition::Shader * shader)1711 ProgramInterfaceDefinition::ShaderResourceUsage getShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader)
1712 {
1713 	ProgramInterfaceDefinition::ShaderResourceUsage retVal;
1714 
1715 	retVal.numInputs						= getNumTypeInstances(shader, glu::STORAGE_IN);
1716 	retVal.numInputVectors					= getNumVectors(shader, glu::STORAGE_IN);
1717 	retVal.numInputComponents				= getNumComponents(shader, glu::STORAGE_IN);
1718 
1719 	retVal.numOutputs						= getNumTypeInstances(shader, glu::STORAGE_OUT);
1720 	retVal.numOutputVectors					= getNumVectors(shader, glu::STORAGE_OUT);
1721 	retVal.numOutputComponents				= getNumComponents(shader, glu::STORAGE_OUT);
1722 
1723 	retVal.numPatchInputComponents			= getNumComponents(shader, glu::STORAGE_PATCH_IN);
1724 	retVal.numPatchOutputComponents			= getNumComponents(shader, glu::STORAGE_PATCH_OUT);
1725 
1726 	retVal.numDefaultBlockUniformComponents	= getNumDefaultBlockComponents(shader, glu::STORAGE_UNIFORM);
1727 	retVal.numCombinedUniformComponents		= getNumComponents(shader, glu::STORAGE_UNIFORM);
1728 	retVal.numUniformVectors				= getNumVectors(shader, glu::STORAGE_UNIFORM);
1729 
1730 	retVal.numSamplers						= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
1731 	retVal.numImages						= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1732 
1733 	retVal.numAtomicCounterBuffers			= getNumAtomicCounterBuffers(shader);
1734 	retVal.numAtomicCounters				= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter);
1735 
1736 	retVal.numUniformBlocks					= getNumShaderBlocks(shader, glu::STORAGE_UNIFORM);
1737 	retVal.numShaderStorageBlocks			= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1738 
1739 	// add builtins
1740 	switch (shader->getType())
1741 	{
1742 		case glu::SHADERTYPE_VERTEX:
1743 			// gl_Position is not counted
1744 			break;
1745 
1746 		case glu::SHADERTYPE_FRAGMENT:
1747 			// nada
1748 			break;
1749 
1750 		case glu::SHADERTYPE_GEOMETRY:
1751 			// gl_Position in (point mode => size 1)
1752 			retVal.numInputs			+= 1;
1753 			retVal.numInputVectors		+= 1;
1754 			retVal.numInputComponents	+= 4;
1755 
1756 			// gl_Position out
1757 			retVal.numOutputs			+= 1;
1758 			retVal.numOutputVectors		+= 1;
1759 			retVal.numOutputComponents	+= 4;
1760 			break;
1761 
1762 		case glu::SHADERTYPE_TESSELLATION_CONTROL:
1763 			// gl_Position in is read up to gl_InstanceID
1764 			retVal.numInputs			+= 1 * program->getTessellationNumOutputPatchVertices();
1765 			retVal.numInputVectors		+= 1 * program->getTessellationNumOutputPatchVertices();
1766 			retVal.numInputComponents	+= 4 * program->getTessellationNumOutputPatchVertices();
1767 
1768 			// gl_Position out, size = num patch out vertices
1769 			retVal.numOutputs			+= 1 * program->getTessellationNumOutputPatchVertices();
1770 			retVal.numOutputVectors		+= 1 * program->getTessellationNumOutputPatchVertices();
1771 			retVal.numOutputComponents	+= 4 * program->getTessellationNumOutputPatchVertices();
1772 			break;
1773 
1774 		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
1775 			// gl_Position in is read up to gl_InstanceID
1776 			retVal.numInputs			+= 1 * program->getTessellationNumOutputPatchVertices();
1777 			retVal.numInputVectors		+= 1 * program->getTessellationNumOutputPatchVertices();
1778 			retVal.numInputComponents	+= 4 * program->getTessellationNumOutputPatchVertices();
1779 
1780 			// gl_Position out
1781 			retVal.numOutputs			+= 1;
1782 			retVal.numOutputVectors		+= 1;
1783 			retVal.numOutputComponents	+= 4;
1784 			break;
1785 
1786 		case glu::SHADERTYPE_COMPUTE:
1787 			// nada
1788 			break;
1789 
1790 		default:
1791 			DE_ASSERT(false);
1792 			break;
1793 	}
1794 	return retVal;
1795 }
1796 
getCombinedProgramResourceUsage(const ProgramInterfaceDefinition::Program * program)1797 ProgramInterfaceDefinition::ProgramResourceUsage getCombinedProgramResourceUsage (const ProgramInterfaceDefinition::Program* program)
1798 {
1799 	ProgramInterfaceDefinition::ProgramResourceUsage	retVal;
1800 	int													numVertexOutputComponents	= 0;
1801 	int													numFragmentInputComponents	= 0;
1802 	int													numVertexOutputVectors		= 0;
1803 	int													numFragmentInputVectors		= 0;
1804 
1805 	retVal.uniformBufferMaxBinding					= -1; // max binding is inclusive upper bound. Allow 0 bindings by using negative value
1806 	retVal.uniformBufferMaxSize						= 0;
1807 	retVal.numUniformBlocks							= 0;
1808 	retVal.numCombinedVertexUniformComponents		= 0;
1809 	retVal.numCombinedFragmentUniformComponents		= 0;
1810 	retVal.numCombinedGeometryUniformComponents		= 0;
1811 	retVal.numCombinedTessControlUniformComponents	= 0;
1812 	retVal.numCombinedTessEvalUniformComponents		= 0;
1813 	retVal.shaderStorageBufferMaxBinding			= -1; // see above
1814 	retVal.shaderStorageBufferMaxSize				= 0;
1815 	retVal.numShaderStorageBlocks					= 0;
1816 	retVal.numVaryingComponents						= 0;
1817 	retVal.numVaryingVectors						= 0;
1818 	retVal.numCombinedSamplers						= 0;
1819 	retVal.atomicCounterBufferMaxBinding			= -1; // see above
1820 	retVal.atomicCounterBufferMaxSize				= 0;
1821 	retVal.numAtomicCounterBuffers					= 0;
1822 	retVal.numAtomicCounters						= 0;
1823 	retVal.maxImageBinding							= -1; // see above
1824 	retVal.numCombinedImages						= 0;
1825 	retVal.numCombinedOutputResources				= 0;
1826 	retVal.numXFBInterleavedComponents				= 0;
1827 	retVal.numXFBSeparateAttribs					= 0;
1828 	retVal.numXFBSeparateComponents					= 0;
1829 	retVal.fragmentOutputMaxBinding					= -1; // see above
1830 
1831 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1832 	{
1833 		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1834 
1835 		retVal.uniformBufferMaxBinding		= de::max(retVal.uniformBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_UNIFORM));
1836 		retVal.uniformBufferMaxSize			= de::max(retVal.uniformBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_UNIFORM));
1837 		retVal.numUniformBlocks				+= getNumShaderBlocks(shader, glu::STORAGE_UNIFORM);
1838 
1839 		switch (shader->getType())
1840 		{
1841 			case glu::SHADERTYPE_VERTEX:					retVal.numCombinedVertexUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1842 			case glu::SHADERTYPE_FRAGMENT:					retVal.numCombinedFragmentUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1843 			case glu::SHADERTYPE_GEOMETRY:					retVal.numCombinedGeometryUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1844 			case glu::SHADERTYPE_TESSELLATION_CONTROL:		retVal.numCombinedTessControlUniformComponents	+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1845 			case glu::SHADERTYPE_TESSELLATION_EVALUATION:	retVal.numCombinedTessEvalUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1846 			default: break;
1847 		}
1848 
1849 		retVal.shaderStorageBufferMaxBinding	= de::max(retVal.shaderStorageBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_BUFFER));
1850 		retVal.shaderStorageBufferMaxSize		= de::max(retVal.shaderStorageBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_BUFFER));
1851 		retVal.numShaderStorageBlocks			+= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1852 
1853 		if (shader->getType() == glu::SHADERTYPE_VERTEX)
1854 		{
1855 			numVertexOutputComponents	+= getNumComponents(shader, glu::STORAGE_OUT);
1856 			numVertexOutputVectors		+= getNumVectors(shader, glu::STORAGE_OUT);
1857 		}
1858 		else if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1859 		{
1860 			numFragmentInputComponents	+= getNumComponents(shader, glu::STORAGE_IN);
1861 			numFragmentInputVectors		+= getNumVectors(shader, glu::STORAGE_IN);
1862 		}
1863 
1864 		retVal.numCombinedSamplers	+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
1865 
1866 		retVal.atomicCounterBufferMaxBinding	= de::max(retVal.atomicCounterBufferMaxBinding, getAtomicCounterMaxBinding(shader));
1867 		retVal.atomicCounterBufferMaxSize		= de::max(retVal.atomicCounterBufferMaxSize, getAtomicCounterMaxBufferSize(shader));
1868 		retVal.numAtomicCounterBuffers			+= getNumAtomicCounterBuffers(shader);
1869 		retVal.numAtomicCounters				+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter);
1870 		retVal.maxImageBinding					= de::max(retVal.maxImageBinding, getUniformMaxBinding(shader, glu::isDataTypeImage));
1871 		retVal.numCombinedImages				+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1872 
1873 		retVal.numCombinedOutputResources		+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1874 		retVal.numCombinedOutputResources		+= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1875 
1876 		if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1877 		{
1878 			retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT);
1879 			retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader));
1880 		}
1881 	}
1882 
1883 	if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS)
1884 		retVal.numXFBInterleavedComponents = getNumXFBComponents(program);
1885 	else if (program->getTransformFeedbackMode() == GL_SEPARATE_ATTRIBS)
1886 	{
1887 		retVal.numXFBSeparateAttribs	= (int)program->getTransformFeedbackVaryings().size();
1888 		retVal.numXFBSeparateComponents	= getNumMaxXFBOutputComponents(program);
1889 	}
1890 
1891 	// legacy limits
1892 	retVal.numVaryingComponents	= de::max(numVertexOutputComponents, numFragmentInputComponents);
1893 	retVal.numVaryingVectors	= de::max(numVertexOutputVectors, numFragmentInputVectors);
1894 
1895 	return retVal;
1896 }
1897 
1898 } // Functional
1899 } // gles31
1900 } // deqp
1901