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