1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Program interface utilities
22 *//*--------------------------------------------------------------------*/
24 #include "es31fProgramInterfaceDefinitionUtil.hpp"
25 #include "es31fProgramInterfaceDefinition.hpp"
26 #include "gluVarType.hpp"
27 #include "gluVarTypeUtil.hpp"
28 #include "gluShaderUtil.hpp"
30 #include "deStringUtil.hpp"
31 #include "glwEnums.hpp"
45 namespace ProgramInterfaceDefinition
48 VariableSearchFilter::VariableSearchFilter (void)
49 : m_shaderTypeBits (0xFFFFFFFFul)
50 , m_storageBits (0xFFFFFFFFul)
54 VariableSearchFilter VariableSearchFilter::createShaderTypeFilter (glu::ShaderType type)
56 DE_ASSERT(type < glu::SHADERTYPE_LAST);
58 VariableSearchFilter filter;
59 filter.m_shaderTypeBits = (1u << type);
63 VariableSearchFilter VariableSearchFilter::createStorageFilter (glu::Storage storage)
65 DE_ASSERT(storage < glu::STORAGE_LAST);
67 VariableSearchFilter filter;
68 filter.m_storageBits = (1u << storage);
72 VariableSearchFilter VariableSearchFilter::createShaderTypeStorageFilter (glu::ShaderType type, glu::Storage storage)
74 return logicalAnd(createShaderTypeFilter(type), createStorageFilter(storage));
77 VariableSearchFilter VariableSearchFilter::logicalOr (const VariableSearchFilter& a, const VariableSearchFilter& b)
79 VariableSearchFilter filter;
80 filter.m_shaderTypeBits = a.m_shaderTypeBits | b.m_shaderTypeBits;
81 filter.m_storageBits = a.m_storageBits | b.m_storageBits;
85 VariableSearchFilter VariableSearchFilter::logicalAnd (const VariableSearchFilter& a, const VariableSearchFilter& b)
87 VariableSearchFilter filter;
88 filter.m_shaderTypeBits = a.m_shaderTypeBits & b.m_shaderTypeBits;
89 filter.m_storageBits = a.m_storageBits & b.m_storageBits;
93 bool VariableSearchFilter::matchesFilter (const ProgramInterfaceDefinition::Shader* shader) const
95 DE_ASSERT(shader->getType() < glu::SHADERTYPE_LAST);
96 return (m_shaderTypeBits & (1u << shader->getType())) != 0;
99 bool VariableSearchFilter::matchesFilter (const glu::VariableDeclaration& variable) const
101 DE_ASSERT(variable.storage < glu::STORAGE_LAST);
102 return (m_storageBits & (1u << variable.storage)) != 0;
105 bool VariableSearchFilter::matchesFilter (const glu::InterfaceBlock& block) const
107 DE_ASSERT(block.storage < glu::STORAGE_LAST);
108 return (m_storageBits & (1u << block.storage)) != 0;
111 } // ProgramInterfaceDefinition
113 static bool incrementMultiDimensionIndex (std::vector<int>& index, const std::vector<int>& dimensions)
115 int incrementDimensionNdx = (int)(index.size() - 1);
117 while (incrementDimensionNdx >= 0)
119 if (++index[incrementDimensionNdx] == dimensions[incrementDimensionNdx])
120 index[incrementDimensionNdx--] = 0;
125 return (incrementDimensionNdx != -1);
128 bool programContainsIOBlocks (const ProgramInterfaceDefinition::Program* program)
130 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
132 if (shaderContainsIOBlocks(program->getShaders()[shaderNdx]))
139 bool shaderContainsIOBlocks (const ProgramInterfaceDefinition::Shader* shader)
141 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
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)
155 glu::ShaderType getProgramTransformFeedbackStage (const ProgramInterfaceDefinition::Program* program)
157 if (program->hasStage(glu::SHADERTYPE_GEOMETRY))
158 return glu::SHADERTYPE_GEOMETRY;
160 if (program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
161 return glu::SHADERTYPE_TESSELLATION_EVALUATION;
163 if (program->hasStage(glu::SHADERTYPE_VERTEX))
164 return glu::SHADERTYPE_VERTEX;
167 return glu::SHADERTYPE_LAST;
170 void generateVariableTypeResourceNames (std::vector<std::string>& resources, const std::string& name, const glu::VarType& type, deUint32 resourceNameGenerationFlags)
172 DE_ASSERT((resourceNameGenerationFlags & (~RESOURCE_NAME_GENERATION_FLAG_MASK)) == 0);
174 // remove top-level flag from children
175 const deUint32 childFlags = resourceNameGenerationFlags & ~((deUint32)RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE);
177 if (type.isBasicType())
178 resources.push_back(name);
179 else if (type.isStructType())
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);
185 else if (type.isArrayType())
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)
192 resources.push_back(name);
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)
198 generateVariableTypeResourceNames(resources, name + "[0]", type.getElementType(), childFlags);
200 // Other arrays of aggregate types are expanded
203 for (int ndx = 0; ndx < type.getArraySize(); ++ndx)
204 generateVariableTypeResourceNames(resources, name + "[" + de::toString(ndx) + "]", type.getElementType(), childFlags);
211 // Program source generation
216 using ProgramInterfaceDefinition::VariablePathComponent;
217 using ProgramInterfaceDefinition::VariableSearchFilter;
219 static std::string getShaderExtensionDeclarations (const ProgramInterfaceDefinition::Shader* shader)
221 if (shader->getVersion() > glu::GLSL_VERSION_440)
224 std::vector<std::string> extensions;
225 std::ostringstream buf;
227 if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
229 extensions.push_back("GL_EXT_geometry_shader");
231 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL ||
232 shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
234 extensions.push_back("GL_EXT_tessellation_shader");
237 if (shaderContainsIOBlocks(shader))
238 extensions.push_back("GL_EXT_shader_io_blocks");
240 for (int ndx = 0; ndx < (int)extensions.size(); ++ndx)
241 buf << "#extension " << extensions[ndx] << " : require\n";
245 static std::string getShaderTypeDeclarations (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader)
247 glu::ShaderType type = shader->getType();
248 auto isCoreGL = (shader->getVersion() > glu::GLSL_VERSION_440);
252 case glu::SHADERTYPE_VERTEX:
254 return "out gl_PerVertex { vec4 gl_Position; };\n";
257 case glu::SHADERTYPE_FRAGMENT:
260 case glu::SHADERTYPE_GEOMETRY:
262 std::ostringstream buf;
263 buf << "layout(points) in;\n"
264 "layout(points, max_vertices=" << program->getGeometryNumOutputVertices() << ") out;\n";
267 buf << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
268 "out gl_PerVertex { vec4 gl_Position; };\n";
273 case glu::SHADERTYPE_TESSELLATION_CONTROL:
275 std::ostringstream buf;
276 buf << "layout(vertices=" << program->getTessellationNumOutputPatchVertices() << ") out;\n";
279 buf << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
280 "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
285 case glu::SHADERTYPE_TESSELLATION_EVALUATION:
287 std::ostringstream buf;
290 buf << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
291 "out gl_PerVertex { vec4 gl_Position; };\n";
293 buf << "layout(triangles, point_mode) in;\n";
297 case glu::SHADERTYPE_COMPUTE:
298 return "layout(local_size_x=1) in;\n";
306 class StructNameEqualPredicate
309 StructNameEqualPredicate (const char* name) : m_name(name) { }
310 bool operator() (const glu::StructType* type) { return type->hasTypeName() && (deStringEqual(m_name, type->getTypeName()) == DE_TRUE); }
315 static void collectNamedStructureDefinitions (std::vector<const glu::StructType*>& dst, const glu::VarType& type)
317 if (type.isBasicType())
319 else if (type.isArrayType())
320 return collectNamedStructureDefinitions(dst, type.getElementType());
321 else if (type.isStructType())
323 if (type.getStructPtr()->hasTypeName())
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())
329 DE_ASSERT(**where == *type.getStructPtr());
331 // identical type has been added already, types of members must be added too
336 // Add types of members first
337 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
338 collectNamedStructureDefinitions(dst, type.getStructPtr()->getMember(ndx).getType());
340 dst.push_back(type.getStructPtr());
346 static void writeStructureDefinitions (std::ostringstream& buf, const ProgramInterfaceDefinition::DefaultBlock& defaultBlock)
348 std::vector<const glu::StructType*> namedStructs;
350 // Collect all structs in post order
352 for (int ndx = 0; ndx < (int)defaultBlock.variables.size(); ++ndx)
353 collectNamedStructureDefinitions(namedStructs, defaultBlock.variables[ndx].varType);
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);
361 for (int structNdx = 0; structNdx < (int)namedStructs.size(); ++structNdx)
363 buf << "struct " << namedStructs[structNdx]->getTypeName() << "\n"
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";
372 if (!namedStructs.empty())
376 static void writeInterfaceBlock (std::ostringstream& buf, const glu::InterfaceBlock& interfaceBlock)
378 buf << interfaceBlock.layout;
380 if (interfaceBlock.layout != glu::Layout())
383 buf << glu::getStorageName(interfaceBlock.storage) << " " << interfaceBlock.interfaceName << "\n"
386 for (int ndx = 0; ndx < (int)interfaceBlock.variables.size(); ++ndx)
387 buf << glu::indent(1) << interfaceBlock.variables[ndx] << ";\n";
391 if (!interfaceBlock.instanceName.empty())
392 buf << " " << interfaceBlock.instanceName;
394 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
395 buf << "[" << interfaceBlock.dimensions[dimensionNdx] << "]";
400 static bool isReadableInterface (const glu::InterfaceBlock& interface)
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);
408 static bool isWritableInterface (const glu::InterfaceBlock& interface)
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);
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)
424 if (varType.isBasicType())
426 buf << "\t" << accumulatorName << " += ";
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 << ")))";
447 else if (varType.isStructType())
449 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
450 writeVariableReadAccumulateExpression(buf,
452 name + "." + varType.getStructPtr()->getMember(ndx).getName(),
456 varType.getStructPtr()->getMember(ndx).getType());
458 else if (varType.isArrayType())
460 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
462 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
463 writeVariableReadAccumulateExpression(buf,
465 name + "[" + de::toString(ndx) + "]",
469 varType.getElementType());
471 else if (storage == glu::STORAGE_BUFFER)
473 // run-time sized array, read arbitrary
474 writeVariableReadAccumulateExpression(buf,
480 varType.getElementType());
484 DE_ASSERT(storage == glu::STORAGE_IN);
486 if (shaderType == glu::SHADERTYPE_GEOMETRY)
488 // implicit sized geometry input array, size = primitive size. Just reading first is enough
489 writeVariableReadAccumulateExpression(buf,
495 varType.getElementType());
497 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
499 // implicit sized tessellation input array, size = input patch max size. Just reading current is enough
500 writeVariableReadAccumulateExpression(buf,
502 name + "[gl_InvocationID]",
506 varType.getElementType());
508 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
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)
514 writeVariableReadAccumulateExpression(buf,
516 name + "[" + de::toString(ndx) + "]",
520 varType.getElementType());
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)
537 if (block.dimensions.empty())
539 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
541 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
543 writeVariableReadAccumulateExpression(buf,
545 prefix + block.variables[ndx].name,
549 block.variables[ndx].varType);
554 std::vector<int> index(block.dimensions.size(), 0);
560 std::ostringstream name;
561 name << block.instanceName;
563 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
564 name << "[" << index[dimensionNdx] << "]";
566 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
568 writeVariableReadAccumulateExpression(buf,
570 name.str() + "." + block.variables[ndx].name,
574 block.variables[ndx].varType);
579 if (!incrementMultiDimensionIndex(index, block.dimensions))
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)
593 if (varType.isBasicType())
595 buf << "\t" << name << " = ";
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))";
606 else if (varType.isStructType())
608 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
609 writeVariableWriteExpression(buf,
611 name + "." + varType.getStructPtr()->getMember(ndx).getName(),
615 varType.getStructPtr()->getMember(ndx).getType());
617 else if (varType.isArrayType())
619 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
621 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
622 writeVariableWriteExpression(buf,
624 name + "[" + de::toString(ndx) + "]",
628 varType.getElementType());
630 else if (storage == glu::STORAGE_BUFFER)
632 // run-time sized array, write arbitrary
633 writeVariableWriteExpression(buf,
639 varType.getElementType());
643 DE_ASSERT(storage == glu::STORAGE_OUT);
645 if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
647 // implicit sized tessellation onput array, size = output patch max size. Can only write to gl_InvocationID
648 writeVariableWriteExpression(buf,
650 name + "[gl_InvocationID]",
654 varType.getElementType());
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)
670 if (block.dimensions.empty())
672 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
674 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
676 writeVariableWriteExpression(buf,
678 prefix + block.variables[ndx].name,
682 block.variables[ndx].varType);
687 std::vector<int> index(block.dimensions.size(), 0);
693 std::ostringstream name;
694 name << block.instanceName;
696 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
697 name << "[" << index[dimensionNdx] << "]";
699 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
701 writeVariableWriteExpression(buf,
703 name.str() + "." + block.variables[ndx].name,
707 block.variables[ndx].varType);
712 if (!incrementMultiDimensionIndex(index, block.dimensions))
718 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const char* subPath, const glu::VarType& type)
720 glu::VarTokenizer tokenizer(subPath);
722 typePath.push_back(VariablePathComponent(&type));
724 if (tokenizer.getToken() == glu::VarTokenizer::TOKEN_END)
727 if (type.isStructType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_PERIOD)
732 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_IDENTIFIER)
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());
739 // malformed path, no such member
742 else if (type.isArrayType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
747 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_NUMBER)
751 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_RIGHT_BRACKET)
754 return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getElementType());
760 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const std::string& path, const glu::VariableDeclaration& var)
762 if (glu::parseVariableName(path.c_str()) != var.name)
765 typePath.push_back(VariablePathComponent(&var));
766 return traverseVariablePath(typePath, path.c_str() + var.name.length(), var.varType);
769 static bool traverseShaderVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Shader* shader, const std::string& path, const VariableSearchFilter& filter)
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]))
777 // is variable an interface block variable?
779 const std::string blockName = glu::parseVariableName(path.c_str());
781 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
783 if (!filter.matchesFilter(shader->getDefaultBlock().interfaceBlocks[interfaceNdx]))
786 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName)
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());
793 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
795 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
797 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
798 return traverseVariablePath(typePath, blockMemberPath, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
805 else if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].instanceName.empty())
807 const std::string blockMemeberName = glu::parseVariableName(path.c_str());
809 // unnamed block contains such variable?
810 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
812 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
814 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
815 return traverseVariablePath(typePath, path, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
827 static bool traverseProgramVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& path, const VariableSearchFilter& filter)
829 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
831 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
833 if (filter.matchesFilter(shader))
835 // \note modifying output variable even when returning false
837 if (traverseShaderVariablePath(typePath, shader, path, filter))
845 static bool containsSubType (const glu::VarType& complexType, glu::DataType basicType)
847 if (complexType.isBasicType())
849 return complexType.getBasicType() == basicType;
851 else if (complexType.isArrayType())
853 return containsSubType(complexType.getElementType(), basicType);
855 else if (complexType.isStructType())
857 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
858 if (containsSubType(complexType.getStructPtr()->getMember(ndx).getType(), basicType))
869 static int getNumShaderBlocks (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
873 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
875 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
877 int numInstances = 1;
879 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
880 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
882 retVal += numInstances;
889 static int getNumAtomicCounterBuffers (const ProgramInterfaceDefinition::Shader* shader)
891 std::set<int> buffers;
893 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
895 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
897 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
898 buffers.insert(shader->getDefaultBlock().variables[ndx].layout.binding);
902 return (int)buffers.size();
905 template <typename DataTypeMap>
906 static int accumulateComplexType (const glu::VarType& complexType, const DataTypeMap& dTypeMap)
908 if (complexType.isBasicType())
909 return dTypeMap(complexType.getBasicType());
910 else if (complexType.isArrayType())
912 const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize());
913 return arraySize * accumulateComplexType(complexType.getElementType(), dTypeMap);
915 else if (complexType.isStructType())
918 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
919 sum += accumulateComplexType(complexType.getStructPtr()->getMember(ndx).getType(), dTypeMap);
929 template <typename InterfaceBlockFilter, typename VarDeclFilter, typename DataTypeMap>
930 static int accumulateShader (const ProgramInterfaceDefinition::Shader* shader,
931 const InterfaceBlockFilter& ibFilter,
932 const VarDeclFilter& vdFilter,
933 const DataTypeMap& dMap)
937 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
939 if (ibFilter(shader->getDefaultBlock().interfaceBlocks[ndx]))
941 int numInstances = 1;
943 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
944 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
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);
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);
958 static bool unusedTrueConstantTypeFilter (glu::DataType d)
964 class InstanceCounter
967 InstanceCounter (bool (*predicate)(glu::DataType))
968 : m_predicate(predicate)
972 int operator() (glu::DataType t) const
974 return (m_predicate(t)) ? (1) : (0);
978 bool (*const m_predicate)(glu::DataType);
981 class InterfaceBlockStorageFilter
984 InterfaceBlockStorageFilter (glu::Storage storage)
989 bool operator() (const glu::InterfaceBlock& b) const
991 return m_storage == b.storage;
995 const glu::Storage m_storage;
998 class VariableDeclarationStorageFilter
1001 VariableDeclarationStorageFilter (glu::Storage storage)
1002 : m_storage(storage)
1006 bool operator() (const glu::VariableDeclaration& d) const
1008 return m_storage == d.storage;
1012 const glu::Storage m_storage;
1015 static int getNumTypeInstances (const glu::VarType& complexType, bool (*predicate)(glu::DataType))
1017 return accumulateComplexType(complexType, InstanceCounter(predicate));
1020 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, bool (*predicate)(glu::DataType))
1022 return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), InstanceCounter(predicate));
1025 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1027 return getNumTypeInstances(shader, storage, unusedTrueConstantTypeFilter);
1030 static int accumulateShaderStorage (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, int (*typeMap)(glu::DataType))
1032 return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), typeMap);
1035 static int getNumDataTypeComponents (glu::DataType type)
1037 if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type))
1038 return glu::getDataTypeScalarSize(type);
1043 static int getNumDataTypeVectors (glu::DataType type)
1045 if (glu::isDataTypeScalar(type))
1047 else if (glu::isDataTypeVector(type))
1049 else if (glu::isDataTypeMatrix(type))
1050 return glu::getDataTypeMatrixNumColumns(type);
1055 static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1057 return accumulateShaderStorage(shader, storage, getNumDataTypeComponents);
1060 static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1062 return accumulateShaderStorage(shader, storage, getNumDataTypeVectors);
1065 static int getNumDefaultBlockComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
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);
1076 static int getMaxBufferBinding (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1078 int maxBinding = -1;
1080 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1082 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
1084 const int binding = (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding);
1085 int numInstances = 1;
1087 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
1088 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
1090 maxBinding = de::max(maxBinding, binding + numInstances - 1);
1094 return (int)maxBinding;
1097 static int getBufferTypeSize (glu::DataType type, glu::MatrixOrder order)
1099 // assume vec4 alignments, should produce values greater than or equal to the actual resource usage
1102 if (glu::isDataTypeScalarOrVector(type))
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);
1111 return 4 * numVectors;
1114 static int getBufferVariableSize (const glu::VarType& type, glu::MatrixOrder order)
1116 if (type.isBasicType())
1117 return getBufferTypeSize(type.getBasicType(), order);
1118 else if (type.isArrayType())
1120 const int arraySize = (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (type.getArraySize());
1121 return arraySize * getBufferVariableSize(type.getElementType(), order);
1123 else if (type.isStructType())
1126 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
1127 sum += getBufferVariableSize(type.getStructPtr()->getMember(ndx).getType(), order);
1137 static int getBufferSize (const glu::InterfaceBlock& block, glu::MatrixOrder blockOrder)
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));
1147 static int getBufferMaxSize (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
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));
1155 return (int)maxSize;
1158 static int getAtomicCounterMaxBinding (const ProgramInterfaceDefinition::Shader* shader)
1160 int maxBinding = -1;
1162 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1164 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
1166 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
1167 maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding);
1171 return (int)maxBinding;
1174 static int getUniformMaxBinding (const ProgramInterfaceDefinition::Shader* shader, bool (*predicate)(glu::DataType))
1176 int maxBinding = -1;
1178 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
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);
1183 maxBinding = de::max(maxBinding, binding + numInstances - 1);
1189 static int getAtomicCounterMaxBufferSize (const ProgramInterfaceDefinition::Shader* shader)
1191 std::map<int, int> bufferSizes;
1194 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1196 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
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);
1202 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
1204 if (bufferSizes.find(bufferBinding) == bufferSizes.end())
1205 bufferSizes[bufferBinding] = size;
1207 bufferSizes[bufferBinding] = de::max<int>(bufferSizes[bufferBinding], size);
1211 for (std::map<int, int>::iterator it = bufferSizes.begin(); it != bufferSizes.end(); ++it)
1212 maxSize = de::max<int>(maxSize, it->second);
1217 static int getNumFeedbackVaryingComponents (const ProgramInterfaceDefinition::Program* program, const std::string& name)
1219 std::vector<VariablePathComponent> path;
1221 if (name == "gl_Position")
1224 DE_ASSERT(deStringBeginsWith(name.c_str(), "gl_") == DE_FALSE);
1226 if (!traverseProgramVariablePath(path, program, name, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1227 DE_ASSERT(false); // Program failed validate, invalid operation
1229 return accumulateComplexType(*path.back().getVariableType(), getNumDataTypeComponents);
1232 static int getNumXFBComponents (const ProgramInterfaceDefinition::Program* program)
1234 int numComponents = 0;
1236 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1237 numComponents += getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]);
1239 return numComponents;
1242 static int getNumMaxXFBOutputComponents (const ProgramInterfaceDefinition::Program* program)
1244 int numComponents = 0;
1246 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1247 numComponents = de::max(numComponents, getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]));
1249 return numComponents;
1252 static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader)
1254 DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT);
1256 int maxOutputLocation = -1;
1258 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1260 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT)
1262 // missing location qualifier means location == 0
1263 const int outputLocation = (shader->getDefaultBlock().variables[ndx].layout.location == -1)
1265 : (shader->getDefaultBlock().variables[ndx].layout.location);
1267 // only basic types or arrays of basic types possible
1268 DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType());
1270 const int locationSlotsTaken = (shader->getDefaultBlock().variables[ndx].varType.isArrayType())
1271 ? (shader->getDefaultBlock().variables[ndx].varType.getArraySize())
1274 maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1);
1278 return maxOutputLocation;
1283 std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock)
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;
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));
1301 std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface)
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;
1312 case PROGRAMINTERFACE_UNIFORM:
1313 case PROGRAMINTERFACE_BUFFER_VARIABLE:
1315 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
1317 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1319 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
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);
1328 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1330 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1331 if (interfaceBlock.storage == storage)
1333 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
1334 resources.insert(resources.end(), blockResources.begin(), blockResources.end());
1341 case PROGRAMINTERFACE_UNIFORM_BLOCK:
1342 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1344 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
1346 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1348 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1349 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1351 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1352 if (interfaceBlock.storage == storage)
1354 std::vector<int> index(interfaceBlock.dimensions.size(), 0);
1358 // add resource string for each element
1360 std::ostringstream name;
1361 name << interfaceBlock.interfaceName;
1363 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
1364 name << "[" << index[dimensionNdx] << "]";
1366 resources.push_back(name.str());
1370 if (!incrementMultiDimensionIndex(index, interfaceBlock.dimensions))
1379 case PROGRAMINTERFACE_PROGRAM_INPUT:
1380 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
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());
1386 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1388 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1390 if (shader->getType() != shaderType)
1393 for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx)
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);
1403 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1405 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1406 if (interfaceBlock.storage == queryStorage || interfaceBlock.storage == queryPatchStorage)
1408 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
1409 resources.insert(resources.end(), blockResources.begin(), blockResources.end());
1415 if (interface == PROGRAMINTERFACE_PROGRAM_INPUT)
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)
1425 resources.push_back("gl_InvocationID");
1426 resources.push_back("gl_PerVertex.gl_Position");
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
1433 else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT)
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)
1443 resources.push_back("gl_PerVertex.gl_Position");
1444 resources.push_back("gl_TessLevelOuter[0]");
1445 resources.push_back("gl_TessLevelInner[0]");
1447 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1448 resources.push_back("gl_Position");
1454 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1456 const glu::ShaderType xfbStage = getProgramTransformFeedbackStage(program);
1458 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1460 const std::string& varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
1462 if (deStringBeginsWith(varyingName.c_str(), "gl_"))
1463 resources.push_back(varyingName); // builtin
1466 std::vector<VariablePathComponent> path;
1468 if (!traverseProgramVariablePath(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(xfbStage, glu::STORAGE_OUT)))
1469 DE_ASSERT(false); // Program failed validate, invalid operation
1471 generateVariableTypeResourceNames(resources,
1473 *path.back().getVariableType(),
1474 RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
1485 if (removeDuplicated)
1487 std::set<std::string> addedVariables;
1488 std::vector<std::string> uniqueResouces;
1490 for (int ndx = 0; ndx < (int)resources.size(); ++ndx)
1492 if (addedVariables.find(resources[ndx]) == addedVariables.end())
1494 addedVariables.insert(resources[ndx]);
1495 uniqueResouces.push_back(resources[ndx]);
1499 uniqueResouces.swap(resources);
1506 * Name of the unused uniform added by generateProgramInterfaceProgramSources
1508 * A uniform named "unusedZero" 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.
1513 * \sa deqp::gles31::Functional::ProgramInterfaceDefinition::generateProgramInterfaceProgramSources
1515 const char* getUnusedZeroUniformName()
1517 return "unusedZero";
1520 glu::ProgramSources generateProgramInterfaceProgramSources (const ProgramInterfaceDefinition::Program* program)
1522 glu::ProgramSources sources;
1524 DE_ASSERT(program->isValid());
1526 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1528 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1529 bool containsUserDefinedOutputs = false;
1530 bool containsUserDefinedInputs = false;
1531 std::ostringstream sourceBuf;
1532 std::ostringstream usageBuf;
1534 sourceBuf << glu::getGLSLVersionDeclaration(shader->getVersion()) << "\n"
1535 << getShaderExtensionDeclarations(shader)
1536 << getShaderTypeDeclarations(program, shader)
1539 // Struct definitions
1541 writeStructureDefinitions(sourceBuf, shader->getDefaultBlock());
1543 // variables in the default scope
1545 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1546 sourceBuf << shader->getDefaultBlock().variables[ndx] << ";\n";
1548 if (!shader->getDefaultBlock().variables.empty())
1553 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1554 writeInterfaceBlock(sourceBuf, shader->getDefaultBlock().interfaceBlocks[ndx]);
1556 // Use inputs and outputs so that they won't be removed by the optimizer
1558 usageBuf << "highp uniform vec4 " << getUnusedZeroUniformName() << "; // Default value is vec4(0.0).\n"
1559 "highp vec4 readInputs()\n"
1561 " highp vec4 retValue = " << getUnusedZeroUniformName() << ";\n";
1563 // User-defined inputs
1565 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
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)
1571 writeVariableReadAccumulateExpression(usageBuf,
1573 shader->getDefaultBlock().variables[ndx].name,
1575 shader->getDefaultBlock().variables[ndx].storage,
1577 shader->getDefaultBlock().variables[ndx].varType);
1578 containsUserDefinedInputs = true;
1582 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1584 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1585 if (isReadableInterface(interface))
1587 writeInterfaceReadAccumulateExpression(usageBuf,
1592 containsUserDefinedInputs = true;
1598 switch (shader->getType())
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";
1606 case glu::SHADERTYPE_FRAGMENT:
1607 // make readInputs to never be compile time constant
1608 if (!containsUserDefinedInputs)
1609 usageBuf << " retValue += gl_FragCoord;\n";
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";
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";
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";
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";
1633 usageBuf << " return retValue;\n"
1636 usageBuf << "void writeOutputs(in highp vec4 unusedValue)\n"
1639 // User-defined outputs
1641 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1643 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT ||
1644 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_OUT)
1646 writeVariableWriteExpression(usageBuf,
1648 shader->getDefaultBlock().variables[ndx].name,
1650 shader->getDefaultBlock().variables[ndx].storage,
1652 shader->getDefaultBlock().variables[ndx].varType);
1653 containsUserDefinedOutputs = true;
1657 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1659 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1660 if (isWritableInterface(interface))
1662 writeInterfaceWriteExpression(usageBuf, "unusedValue", interface, shader->getType(), program);
1663 containsUserDefinedOutputs = true;
1667 // Builtin-outputs that must be written to
1669 if (shader->getType() == glu::SHADERTYPE_VERTEX)
1670 usageBuf << " gl_Position = unusedValue;\n";
1671 else if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
1672 usageBuf << " gl_Position = unusedValue;\n"
1674 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL)
1675 usageBuf << " gl_out[gl_InvocationID].gl_Position = unusedValue;\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 = unusedValue;\n";
1685 // Output to sink input data to
1687 if (!containsUserDefinedOutputs)
1689 if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1690 usageBuf << " gl_FragDepth = dot(unusedValue.xy, unusedValue.xw);\n";
1691 else if (shader->getType() == glu::SHADERTYPE_COMPUTE)
1692 usageBuf << " unusedOutputBlock.unusedValue = unusedValue;\n";
1698 " writeOutputs(readInputs());\n"
1701 // Interface for unused output
1703 if (shader->getType() == glu::SHADERTYPE_COMPUTE && !containsUserDefinedOutputs)
1705 sourceBuf << "writeonly buffer UnusedOutputInterface\n"
1707 << " highp vec4 unusedValue;\n"
1708 << "} unusedOutputBlock;\n\n";
1711 sources << glu::ShaderSource(shader->getType(), sourceBuf.str() + usageBuf.str());
1714 if (program->isSeparable())
1715 sources << glu::ProgramSeparable(true);
1717 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1718 sources << glu::TransformFeedbackVarying(program->getTransformFeedbackVaryings()[ndx]);
1720 if (program->getTransformFeedbackMode())
1721 sources << glu::TransformFeedbackMode(program->getTransformFeedbackMode());
1726 bool findProgramVariablePathByPathName (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& pathName, const VariableSearchFilter& filter)
1728 std::vector<VariablePathComponent> modifiedPath;
1730 if (!traverseProgramVariablePath(modifiedPath, program, pathName, filter))
1733 // modify param only on success
1734 typePath.swap(modifiedPath);
1738 ProgramInterfaceDefinition::ShaderResourceUsage getShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader)
1740 ProgramInterfaceDefinition::ShaderResourceUsage retVal;
1742 retVal.numInputs = getNumTypeInstances(shader, glu::STORAGE_IN);
1743 retVal.numInputVectors = getNumVectors(shader, glu::STORAGE_IN);
1744 retVal.numInputComponents = getNumComponents(shader, glu::STORAGE_IN);
1746 retVal.numOutputs = getNumTypeInstances(shader, glu::STORAGE_OUT);
1747 retVal.numOutputVectors = getNumVectors(shader, glu::STORAGE_OUT);
1748 retVal.numOutputComponents = getNumComponents(shader, glu::STORAGE_OUT);
1750 retVal.numPatchInputComponents = getNumComponents(shader, glu::STORAGE_PATCH_IN);
1751 retVal.numPatchOutputComponents = getNumComponents(shader, glu::STORAGE_PATCH_OUT);
1753 retVal.numDefaultBlockUniformComponents = getNumDefaultBlockComponents(shader, glu::STORAGE_UNIFORM);
1754 retVal.numCombinedUniformComponents = getNumComponents(shader, glu::STORAGE_UNIFORM);
1755 retVal.numUniformVectors = getNumVectors(shader, glu::STORAGE_UNIFORM);
1757 retVal.numSamplers = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
1758 retVal.numImages = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1760 retVal.numAtomicCounterBuffers = getNumAtomicCounterBuffers(shader);
1761 retVal.numAtomicCounters = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter);
1763 retVal.numUniformBlocks = getNumShaderBlocks(shader, glu::STORAGE_UNIFORM);
1764 retVal.numShaderStorageBlocks = getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1767 switch (shader->getType())
1769 case glu::SHADERTYPE_VERTEX:
1770 // gl_Position is not counted
1773 case glu::SHADERTYPE_FRAGMENT:
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;
1784 retVal.numOutputs += 1;
1785 retVal.numOutputVectors += 1;
1786 retVal.numOutputComponents += 4;
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();
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();
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();
1808 retVal.numOutputs += 1;
1809 retVal.numOutputVectors += 1;
1810 retVal.numOutputComponents += 4;
1813 case glu::SHADERTYPE_COMPUTE:
1824 ProgramInterfaceDefinition::ProgramResourceUsage getCombinedProgramResourceUsage (const ProgramInterfaceDefinition::Program* program)
1826 ProgramInterfaceDefinition::ProgramResourceUsage retVal;
1827 int numVertexOutputComponents = 0;
1828 int numFragmentInputComponents = 0;
1829 int numVertexOutputVectors = 0;
1830 int numFragmentInputVectors = 0;
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
1858 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1860 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
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);
1866 switch (shader->getType())
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;
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);
1880 if (shader->getType() == glu::SHADERTYPE_VERTEX)
1882 numVertexOutputComponents += getNumComponents(shader, glu::STORAGE_OUT);
1883 numVertexOutputVectors += getNumVectors(shader, glu::STORAGE_OUT);
1885 else if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1887 numFragmentInputComponents += getNumComponents(shader, glu::STORAGE_IN);
1888 numFragmentInputVectors += getNumVectors(shader, glu::STORAGE_IN);
1891 retVal.numCombinedSamplers += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
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);
1900 retVal.numCombinedOutputResources += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1901 retVal.numCombinedOutputResources += getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1903 if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1905 retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT);
1906 retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader));
1910 if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS)
1911 retVal.numXFBInterleavedComponents = getNumXFBComponents(program);
1912 else if (program->getTransformFeedbackMode() == GL_SEPARATE_ATTRIBS)
1914 retVal.numXFBSeparateAttribs = (int)program->getTransformFeedbackVaryings().size();
1915 retVal.numXFBSeparateComponents = getNumMaxXFBOutputComponents(program);
1919 retVal.numVaryingComponents = de::max(numVertexOutputComponents, numFragmentInputComponents);
1920 retVal.numVaryingVectors = de::max(numVertexOutputVectors, numFragmentInputVectors);