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