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