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