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