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