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