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 SSBO layout case.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fSSBOLayoutCase.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluProgramInterfaceQuery.hpp"
31 #include "gluObjectWrapper.hpp"
32 #include "gluVarTypeUtil.hpp"
33 #include "glwFunctions.hpp"
34 #include "glwEnums.hpp"
35 #include "tcuTestLog.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuRenderTarget.hpp"
38 #include "deInt32.h"
39 #include "deRandom.hpp"
40 #include "deMath.h"
41 #include "deMemory.h"
42 #include "deString.h"
43 #include "deStringUtil.hpp"
44
45 #include <algorithm>
46 #include <map>
47
48 using std::map;
49 using std::string;
50 using std::vector;
51 using tcu::TestLog;
52
53 namespace deqp
54 {
55 namespace gles31
56 {
57
58 using glu::StructMember;
59 using glu::StructType;
60 using glu::VarType;
61
62 namespace bb
63 {
64
65 struct LayoutFlagsFmt
66 {
67 uint32_t flags;
LayoutFlagsFmtdeqp::gles31::bb::LayoutFlagsFmt68 LayoutFlagsFmt(uint32_t flags_) : flags(flags_)
69 {
70 }
71 };
72
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)73 std::ostream &operator<<(std::ostream &str, const LayoutFlagsFmt &fmt)
74 {
75 static const struct
76 {
77 uint32_t bit;
78 const char *token;
79 } bitDesc[] = {{LAYOUT_SHARED, "shared"}, {LAYOUT_PACKED, "packed"}, {LAYOUT_STD140, "std140"},
80 {LAYOUT_STD430, "std430"}, {LAYOUT_ROW_MAJOR, "row_major"}, {LAYOUT_COLUMN_MAJOR, "column_major"}};
81
82 uint32_t remBits = fmt.flags;
83 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
84 {
85 if (remBits & bitDesc[descNdx].bit)
86 {
87 if (remBits != fmt.flags)
88 str << ", ";
89 str << bitDesc[descNdx].token;
90 remBits &= ~bitDesc[descNdx].bit;
91 }
92 }
93 DE_ASSERT(remBits == 0);
94 return str;
95 }
96
97 // BufferVar implementation.
98
BufferVar(const char * name,const VarType & type,uint32_t flags)99 BufferVar::BufferVar(const char *name, const VarType &type, uint32_t flags) : m_name(name), m_type(type), m_flags(flags)
100 {
101 }
102
103 // BufferBlock implementation.
104
BufferBlock(const char * blockName)105 BufferBlock::BufferBlock(const char *blockName) : m_blockName(blockName), m_arraySize(-1), m_flags(0)
106 {
107 setArraySize(0);
108 }
109
setArraySize(int arraySize)110 void BufferBlock::setArraySize(int arraySize)
111 {
112 DE_ASSERT(arraySize >= 0);
113 m_lastUnsizedArraySizes.resize(arraySize == 0 ? 1 : arraySize, 0);
114 m_arraySize = arraySize;
115 }
116
117 struct BlockLayoutEntry
118 {
BlockLayoutEntrydeqp::gles31::bb::BlockLayoutEntry119 BlockLayoutEntry(void) : size(0)
120 {
121 }
122
123 std::string name;
124 int size;
125 std::vector<int> activeVarIndices;
126 };
127
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)128 std::ostream &operator<<(std::ostream &stream, const BlockLayoutEntry &entry)
129 {
130 stream << entry.name << " { name = " << entry.name << ", size = " << entry.size << ", activeVarIndices = [";
131
132 for (vector<int>::const_iterator i = entry.activeVarIndices.begin(); i != entry.activeVarIndices.end(); i++)
133 {
134 if (i != entry.activeVarIndices.begin())
135 stream << ", ";
136 stream << *i;
137 }
138
139 stream << "] }";
140 return stream;
141 }
142
143 struct BufferVarLayoutEntry
144 {
BufferVarLayoutEntrydeqp::gles31::bb::BufferVarLayoutEntry145 BufferVarLayoutEntry(void)
146 : type(glu::TYPE_LAST)
147 , blockNdx(-1)
148 , offset(-1)
149 , arraySize(-1)
150 , arrayStride(-1)
151 , matrixStride(-1)
152 , topLevelArraySize(-1)
153 , topLevelArrayStride(-1)
154 , isRowMajor(false)
155 {
156 }
157
158 std::string name;
159 glu::DataType type;
160 int blockNdx;
161 int offset;
162 int arraySize;
163 int arrayStride;
164 int matrixStride;
165 int topLevelArraySize;
166 int topLevelArrayStride;
167 bool isRowMajor;
168 };
169
isUnsizedArray(const BufferVarLayoutEntry & entry)170 static bool isUnsizedArray(const BufferVarLayoutEntry &entry)
171 {
172 DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0);
173 return entry.arraySize == 0 || entry.topLevelArraySize == 0;
174 }
175
operator <<(std::ostream & stream,const BufferVarLayoutEntry & entry)176 std::ostream &operator<<(std::ostream &stream, const BufferVarLayoutEntry &entry)
177 {
178 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) << ", blockNdx = " << entry.blockNdx
179 << ", offset = " << entry.offset << ", arraySize = " << entry.arraySize
180 << ", arrayStride = " << entry.arrayStride << ", matrixStride = " << entry.matrixStride
181 << ", topLevelArraySize = " << entry.topLevelArraySize
182 << ", topLevelArrayStride = " << entry.topLevelArrayStride
183 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") << " }";
184 return stream;
185 }
186
187 class BufferLayout
188 {
189 public:
190 std::vector<BlockLayoutEntry> blocks;
191 std::vector<BufferVarLayoutEntry> bufferVars;
192
193 int getVariableIndex(const string &name) const;
194 int getBlockIndex(const string &name) const;
195 };
196
197 // \todo [2012-01-24 pyry] Speed up lookups using hash.
198
getVariableIndex(const string & name) const199 int BufferLayout::getVariableIndex(const string &name) const
200 {
201 for (int ndx = 0; ndx < (int)bufferVars.size(); ndx++)
202 {
203 if (bufferVars[ndx].name == name)
204 return ndx;
205 }
206 return -1;
207 }
208
getBlockIndex(const string & name) const209 int BufferLayout::getBlockIndex(const string &name) const
210 {
211 for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
212 {
213 if (blocks[ndx].name == name)
214 return ndx;
215 }
216 return -1;
217 }
218
219 // ShaderInterface implementation.
220
ShaderInterface(void)221 ShaderInterface::ShaderInterface(void)
222 {
223 }
224
~ShaderInterface(void)225 ShaderInterface::~ShaderInterface(void)
226 {
227 for (std::vector<StructType *>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
228 delete *i;
229
230 for (std::vector<BufferBlock *>::iterator i = m_bufferBlocks.begin(); i != m_bufferBlocks.end(); i++)
231 delete *i;
232 }
233
allocStruct(const char * name)234 StructType &ShaderInterface::allocStruct(const char *name)
235 {
236 m_structs.reserve(m_structs.size() + 1);
237 m_structs.push_back(new StructType(name));
238 return *m_structs.back();
239 }
240
241 struct StructNameEquals
242 {
243 std::string name;
244
StructNameEqualsdeqp::gles31::bb::StructNameEquals245 StructNameEquals(const char *name_) : name(name_)
246 {
247 }
248
operator ()deqp::gles31::bb::StructNameEquals249 bool operator()(const StructType *type) const
250 {
251 return type->getTypeName() && name == type->getTypeName();
252 }
253 };
254
findStruct(const char * name) const255 const StructType *ShaderInterface::findStruct(const char *name) const
256 {
257 std::vector<StructType *>::const_iterator pos =
258 std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
259 return pos != m_structs.end() ? *pos : DE_NULL;
260 }
261
getNamedStructs(std::vector<const StructType * > & structs) const262 void ShaderInterface::getNamedStructs(std::vector<const StructType *> &structs) const
263 {
264 for (std::vector<StructType *>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
265 {
266 if ((*i)->getTypeName() != DE_NULL)
267 structs.push_back(*i);
268 }
269 }
270
allocBlock(const char * name)271 BufferBlock &ShaderInterface::allocBlock(const char *name)
272 {
273 m_bufferBlocks.reserve(m_bufferBlocks.size() + 1);
274 m_bufferBlocks.push_back(new BufferBlock(name));
275 return *m_bufferBlocks.back();
276 }
277
278 // BlockDataPtr
279
280 struct BlockDataPtr
281 {
282 void *ptr;
283 int size; //!< Redundant, for debugging purposes.
284 int lastUnsizedArraySize;
285
BlockDataPtrdeqp::gles31::bb::BlockDataPtr286 BlockDataPtr(void *ptr_, int size_, int lastUnsizedArraySize_)
287 : ptr(ptr_)
288 , size(size_)
289 , lastUnsizedArraySize(lastUnsizedArraySize_)
290 {
291 }
292
BlockDataPtrdeqp::gles31::bb::BlockDataPtr293 BlockDataPtr(void) : ptr(DE_NULL), size(0), lastUnsizedArraySize(0)
294 {
295 }
296 };
297
298 namespace // Utilities
299 {
300
findBlockIndex(const BufferLayout & layout,const string & name)301 int findBlockIndex(const BufferLayout &layout, const string &name)
302 {
303 for (int ndx = 0; ndx < (int)layout.blocks.size(); ndx++)
304 {
305 if (layout.blocks[ndx].name == name)
306 return ndx;
307 }
308 return -1;
309 }
310
311 // Layout computation.
312
getDataTypeByteSize(glu::DataType type)313 int getDataTypeByteSize(glu::DataType type)
314 {
315 return glu::getDataTypeScalarSize(type) * (int)sizeof(uint32_t);
316 }
317
getDataTypeByteAlignment(glu::DataType type)318 int getDataTypeByteAlignment(glu::DataType type)
319 {
320 switch (type)
321 {
322 case glu::TYPE_FLOAT:
323 case glu::TYPE_INT:
324 case glu::TYPE_UINT:
325 case glu::TYPE_BOOL:
326 return 1 * (int)sizeof(uint32_t);
327
328 case glu::TYPE_FLOAT_VEC2:
329 case glu::TYPE_INT_VEC2:
330 case glu::TYPE_UINT_VEC2:
331 case glu::TYPE_BOOL_VEC2:
332 return 2 * (int)sizeof(uint32_t);
333
334 case glu::TYPE_FLOAT_VEC3:
335 case glu::TYPE_INT_VEC3:
336 case glu::TYPE_UINT_VEC3:
337 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4
338
339 case glu::TYPE_FLOAT_VEC4:
340 case glu::TYPE_INT_VEC4:
341 case glu::TYPE_UINT_VEC4:
342 case glu::TYPE_BOOL_VEC4:
343 return 4 * (int)sizeof(uint32_t);
344
345 default:
346 DE_ASSERT(false);
347 return 0;
348 }
349 }
350
computeStd140BaseAlignment(const VarType & type,uint32_t layoutFlags)351 int computeStd140BaseAlignment(const VarType &type, uint32_t layoutFlags)
352 {
353 const int vec4Alignment = (int)sizeof(uint32_t) * 4;
354
355 if (type.isBasicType())
356 {
357 glu::DataType basicType = type.getBasicType();
358
359 if (glu::isDataTypeMatrix(basicType))
360 {
361 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
362 const int vecSize =
363 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
364 const int vecAlign = deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
365
366 return vecAlign;
367 }
368 else
369 return getDataTypeByteAlignment(basicType);
370 }
371 else if (type.isArrayType())
372 {
373 int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
374
375 // Round up to alignment of vec4
376 return deAlign32(elemAlignment, vec4Alignment);
377 }
378 else
379 {
380 DE_ASSERT(type.isStructType());
381
382 int maxBaseAlignment = 0;
383
384 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
385 memberIter != type.getStructPtr()->end(); memberIter++)
386 maxBaseAlignment =
387 de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
388
389 return deAlign32(maxBaseAlignment, vec4Alignment);
390 }
391 }
392
computeStd430BaseAlignment(const VarType & type,uint32_t layoutFlags)393 int computeStd430BaseAlignment(const VarType &type, uint32_t layoutFlags)
394 {
395 // Otherwise identical to std140 except that alignment of structures and arrays
396 // are not rounded up to alignment of vec4.
397
398 if (type.isBasicType())
399 {
400 glu::DataType basicType = type.getBasicType();
401
402 if (glu::isDataTypeMatrix(basicType))
403 {
404 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
405 const int vecSize =
406 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
407 const int vecAlign = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
408
409 return vecAlign;
410 }
411 else
412 return getDataTypeByteAlignment(basicType);
413 }
414 else if (type.isArrayType())
415 {
416 return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
417 }
418 else
419 {
420 DE_ASSERT(type.isStructType());
421
422 int maxBaseAlignment = 0;
423
424 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
425 memberIter != type.getStructPtr()->end(); memberIter++)
426 maxBaseAlignment =
427 de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
428
429 return maxBaseAlignment;
430 }
431 }
432
mergeLayoutFlags(uint32_t prevFlags,uint32_t newFlags)433 inline uint32_t mergeLayoutFlags(uint32_t prevFlags, uint32_t newFlags)
434 {
435 const uint32_t packingMask = LAYOUT_PACKED | LAYOUT_SHARED | LAYOUT_STD140 | LAYOUT_STD430;
436 const uint32_t matrixMask = LAYOUT_ROW_MAJOR | LAYOUT_COLUMN_MAJOR;
437
438 uint32_t mergedFlags = 0;
439
440 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
441 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
442
443 return mergedFlags;
444 }
445
446 //! Appends all child elements to layout, returns value that should be appended to offset.
computeReferenceLayout(BufferLayout & layout,int curBlockNdx,int baseOffset,const std::string & curPrefix,const VarType & type,uint32_t layoutFlags)447 int computeReferenceLayout(BufferLayout &layout, int curBlockNdx, int baseOffset, const std::string &curPrefix,
448 const VarType &type, uint32_t layoutFlags)
449 {
450 // Reference layout uses std430 rules by default. std140 rules are
451 // choosen only for blocks that have std140 layout.
452 const bool isStd140 = (layoutFlags & LAYOUT_STD140) != 0;
453 const int baseAlignment =
454 isStd140 ? computeStd140BaseAlignment(type, layoutFlags) : computeStd430BaseAlignment(type, layoutFlags);
455 int curOffset = deAlign32(baseOffset, baseAlignment);
456 const int topLevelArraySize = 1; // Default values
457 const int topLevelArrayStride = 0;
458
459 if (type.isBasicType())
460 {
461 const glu::DataType basicType = type.getBasicType();
462 BufferVarLayoutEntry entry;
463
464 entry.name = curPrefix;
465 entry.type = basicType;
466 entry.arraySize = 1;
467 entry.arrayStride = 0;
468 entry.matrixStride = 0;
469 entry.topLevelArraySize = topLevelArraySize;
470 entry.topLevelArrayStride = topLevelArrayStride;
471 entry.blockNdx = curBlockNdx;
472
473 if (glu::isDataTypeMatrix(basicType))
474 {
475 // Array of vectors as specified in rules 5 & 7.
476 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
477 const int numVecs =
478 isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) : glu::getDataTypeMatrixNumColumns(basicType);
479
480 entry.offset = curOffset;
481 entry.matrixStride = baseAlignment;
482 entry.isRowMajor = isRowMajor;
483
484 curOffset += numVecs * baseAlignment;
485 }
486 else
487 {
488 // Scalar or vector.
489 entry.offset = curOffset;
490
491 curOffset += getDataTypeByteSize(basicType);
492 }
493
494 layout.bufferVars.push_back(entry);
495 }
496 else if (type.isArrayType())
497 {
498 const VarType &elemType = type.getElementType();
499
500 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
501 {
502 // Array of scalars or vectors.
503 const glu::DataType elemBasicType = elemType.getBasicType();
504 const int stride = baseAlignment;
505 BufferVarLayoutEntry entry;
506
507 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0]
508 entry.type = elemBasicType;
509 entry.blockNdx = curBlockNdx;
510 entry.offset = curOffset;
511 entry.arraySize = type.getArraySize();
512 entry.arrayStride = stride;
513 entry.matrixStride = 0;
514 entry.topLevelArraySize = topLevelArraySize;
515 entry.topLevelArrayStride = topLevelArrayStride;
516
517 curOffset += stride * type.getArraySize();
518
519 layout.bufferVars.push_back(entry);
520 }
521 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
522 {
523 // Array of matrices.
524 const glu::DataType elemBasicType = elemType.getBasicType();
525 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
526 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) :
527 glu::getDataTypeMatrixNumColumns(elemBasicType);
528 const int vecStride = baseAlignment;
529 BufferVarLayoutEntry entry;
530
531 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0]
532 entry.type = elemBasicType;
533 entry.blockNdx = curBlockNdx;
534 entry.offset = curOffset;
535 entry.arraySize = type.getArraySize();
536 entry.arrayStride = vecStride * numVecs;
537 entry.matrixStride = vecStride;
538 entry.isRowMajor = isRowMajor;
539 entry.topLevelArraySize = topLevelArraySize;
540 entry.topLevelArrayStride = topLevelArrayStride;
541
542 curOffset += numVecs * vecStride * type.getArraySize();
543
544 layout.bufferVars.push_back(entry);
545 }
546 else
547 {
548 DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
549
550 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
551 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset,
552 curPrefix + "[" + de::toString(elemNdx) + "]",
553 type.getElementType(), layoutFlags);
554 }
555 }
556 else
557 {
558 DE_ASSERT(type.isStructType());
559
560 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
561 memberIter != type.getStructPtr()->end(); memberIter++)
562 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(),
563 memberIter->getType(), layoutFlags);
564
565 curOffset = deAlign32(curOffset, baseAlignment);
566 }
567
568 return curOffset - baseOffset;
569 }
570
571 //! Appends all child elements to layout, returns offset increment.
computeReferenceLayout(BufferLayout & layout,int curBlockNdx,const std::string & blockPrefix,int baseOffset,const BufferVar & bufVar,uint32_t blockLayoutFlags)572 int computeReferenceLayout(BufferLayout &layout, int curBlockNdx, const std::string &blockPrefix, int baseOffset,
573 const BufferVar &bufVar, uint32_t blockLayoutFlags)
574 {
575 const VarType &varType = bufVar.getType();
576 const uint32_t combinedFlags = mergeLayoutFlags(blockLayoutFlags, bufVar.getFlags());
577
578 if (varType.isArrayType())
579 {
580 // Top-level arrays need special care.
581 const int topLevelArraySize = varType.getArraySize() == VarType::UNSIZED_ARRAY ? 0 : varType.getArraySize();
582 const string prefix = blockPrefix + bufVar.getName() + "[0]";
583 const bool isStd140 = (blockLayoutFlags & LAYOUT_STD140) != 0;
584 const int vec4Align = (int)sizeof(uint32_t) * 4;
585 const int baseAlignment = isStd140 ? computeStd140BaseAlignment(varType, combinedFlags) :
586 computeStd430BaseAlignment(varType, combinedFlags);
587 int curOffset = deAlign32(baseOffset, baseAlignment);
588 const VarType &elemType = varType.getElementType();
589
590 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
591 {
592 // Array of scalars or vectors.
593 const glu::DataType elemBasicType = elemType.getBasicType();
594 const int elemBaseAlign = getDataTypeByteAlignment(elemBasicType);
595 const int stride = isStd140 ? deAlign32(elemBaseAlign, vec4Align) : elemBaseAlign;
596 BufferVarLayoutEntry entry;
597
598 entry.name = prefix;
599 entry.topLevelArraySize = 1;
600 entry.topLevelArrayStride = 0;
601 entry.type = elemBasicType;
602 entry.blockNdx = curBlockNdx;
603 entry.offset = curOffset;
604 entry.arraySize = topLevelArraySize;
605 entry.arrayStride = stride;
606 entry.matrixStride = 0;
607
608 layout.bufferVars.push_back(entry);
609
610 curOffset += stride * topLevelArraySize;
611 }
612 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
613 {
614 // Array of matrices.
615 const glu::DataType elemBasicType = elemType.getBasicType();
616 const bool isRowMajor = !!(combinedFlags & LAYOUT_ROW_MAJOR);
617 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) :
618 glu::getDataTypeMatrixNumRows(elemBasicType);
619 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) :
620 glu::getDataTypeMatrixNumColumns(elemBasicType);
621 const glu::DataType vecType = glu::getDataTypeFloatVec(vecSize);
622 const int vecBaseAlign = getDataTypeByteAlignment(vecType);
623 const int stride = isStd140 ? deAlign32(vecBaseAlign, vec4Align) : vecBaseAlign;
624 BufferVarLayoutEntry entry;
625
626 entry.name = prefix;
627 entry.topLevelArraySize = 1;
628 entry.topLevelArrayStride = 0;
629 entry.type = elemBasicType;
630 entry.blockNdx = curBlockNdx;
631 entry.offset = curOffset;
632 entry.arraySize = topLevelArraySize;
633 entry.arrayStride = stride * numVecs;
634 entry.matrixStride = stride;
635 entry.isRowMajor = isRowMajor;
636
637 layout.bufferVars.push_back(entry);
638
639 curOffset += stride * numVecs * topLevelArraySize;
640 }
641 else
642 {
643 DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
644
645 // Struct base alignment is not added multiple times as curOffset supplied to computeReferenceLayout
646 // was already aligned correctly. Thus computeReferenceLayout should not add any extra padding
647 // before struct. Padding after struct will be added as it should.
648 //
649 // Stride could be computed prior to creating child elements, but it would essentially require running
650 // the layout computation twice. Instead we fix stride to child elements afterwards.
651
652 const int firstChildNdx = (int)layout.bufferVars.size();
653 const int stride =
654 computeReferenceLayout(layout, curBlockNdx, curOffset, prefix, varType.getElementType(), combinedFlags);
655
656 for (int childNdx = firstChildNdx; childNdx < (int)layout.bufferVars.size(); childNdx++)
657 {
658 layout.bufferVars[childNdx].topLevelArraySize = topLevelArraySize;
659 layout.bufferVars[childNdx].topLevelArrayStride = stride;
660 }
661
662 curOffset += stride * topLevelArraySize;
663 }
664
665 return curOffset - baseOffset;
666 }
667 else
668 return computeReferenceLayout(layout, curBlockNdx, baseOffset, blockPrefix + bufVar.getName(), varType,
669 combinedFlags);
670 }
671
computeReferenceLayout(BufferLayout & layout,const ShaderInterface & interface)672 void computeReferenceLayout(BufferLayout &layout, const ShaderInterface &interface)
673 {
674 int numBlocks = interface.getNumBlocks();
675
676 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
677 {
678 const BufferBlock &block = interface.getBlock(blockNdx);
679 bool hasInstanceName = block.getInstanceName() != DE_NULL;
680 std::string blockPrefix = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
681 int curOffset = 0;
682 int activeBlockNdx = (int)layout.blocks.size();
683 int firstVarNdx = (int)layout.bufferVars.size();
684
685 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
686 {
687 const BufferVar &bufVar = *varIter;
688 curOffset +=
689 computeReferenceLayout(layout, activeBlockNdx, blockPrefix, curOffset, bufVar, block.getFlags());
690 }
691
692 int varIndicesEnd = (int)layout.bufferVars.size();
693 int blockSize = curOffset;
694 int numInstances = block.isArray() ? block.getArraySize() : 1;
695
696 // Create block layout entries for each instance.
697 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
698 {
699 // Allocate entry for instance.
700 layout.blocks.push_back(BlockLayoutEntry());
701 BlockLayoutEntry &blockEntry = layout.blocks.back();
702
703 blockEntry.name = block.getBlockName();
704 blockEntry.size = blockSize;
705
706 // Compute active variable set for block.
707 for (int varNdx = firstVarNdx; varNdx < varIndicesEnd; varNdx++)
708 blockEntry.activeVarIndices.push_back(varNdx);
709
710 if (block.isArray())
711 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
712 }
713 }
714 }
715
716 // Value generator.
717
generateValue(const BufferVarLayoutEntry & entry,int unsizedArraySize,void * basePtr,de::Random & rnd)718 void generateValue(const BufferVarLayoutEntry &entry, int unsizedArraySize, void *basePtr, de::Random &rnd)
719 {
720 const glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
721 const int scalarSize = glu::getDataTypeScalarSize(entry.type);
722 const int arraySize = entry.arraySize == 0 ? unsizedArraySize : entry.arraySize;
723 const int arrayStride = entry.arrayStride;
724 const int topLevelSize = entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize;
725 const int topLevelStride = entry.topLevelArrayStride;
726 const bool isMatrix = glu::isDataTypeMatrix(entry.type);
727 const int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) :
728 glu::getDataTypeMatrixNumColumns(entry.type)) :
729 1;
730 const int vecSize = scalarSize / numVecs;
731 const int compSize = sizeof(uint32_t);
732
733 DE_ASSERT(scalarSize % numVecs == 0);
734 DE_ASSERT(topLevelSize >= 0);
735 DE_ASSERT(arraySize >= 0);
736
737 for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++)
738 {
739 uint8_t *const topElemPtr = (uint8_t *)basePtr + entry.offset + topElemNdx * topLevelStride;
740
741 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
742 {
743 uint8_t *const elemPtr = topElemPtr + elemNdx * arrayStride;
744
745 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
746 {
747 uint8_t *const vecPtr = elemPtr + (isMatrix ? vecNdx * entry.matrixStride : 0);
748
749 for (int compNdx = 0; compNdx < vecSize; compNdx++)
750 {
751 uint8_t *const compPtr = vecPtr + compSize * compNdx;
752
753 switch (scalarType)
754 {
755 case glu::TYPE_FLOAT:
756 *((float *)compPtr) = (float)rnd.getInt(-9, 9);
757 break;
758 case glu::TYPE_INT:
759 *((int *)compPtr) = rnd.getInt(-9, 9);
760 break;
761 case glu::TYPE_UINT:
762 *((uint32_t *)compPtr) = (uint32_t)rnd.getInt(0, 9);
763 break;
764 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
765 // interpreted as true but some implementations fail this.
766 case glu::TYPE_BOOL:
767 *((uint32_t *)compPtr) = rnd.getBool() ? rnd.getUint32() | 1u : 0u;
768 break;
769 default:
770 DE_ASSERT(false);
771 }
772 }
773 }
774 }
775 }
776 }
777
generateValues(const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers,uint32_t seed)778 void generateValues(const BufferLayout &layout, const vector<BlockDataPtr> &blockPointers, uint32_t seed)
779 {
780 de::Random rnd(seed);
781 const int numBlocks = (int)layout.blocks.size();
782
783 DE_ASSERT(numBlocks == (int)blockPointers.size());
784
785 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
786 {
787 const BlockLayoutEntry &blockLayout = layout.blocks[blockNdx];
788 const BlockDataPtr &blockPtr = blockPointers[blockNdx];
789 const int numEntries = (int)layout.blocks[blockNdx].activeVarIndices.size();
790
791 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
792 {
793 const int varNdx = blockLayout.activeVarIndices[entryNdx];
794 const BufferVarLayoutEntry &varEntry = layout.bufferVars[varNdx];
795
796 generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd);
797 }
798 }
799 }
800
801 // Shader generator.
802
getCompareFuncForType(glu::DataType type)803 const char *getCompareFuncForType(glu::DataType type)
804 {
805 switch (type)
806 {
807 case glu::TYPE_FLOAT:
808 return "bool compare_float (highp float a, highp float b) { return abs(a - b) < 0.05; }\n";
809 case glu::TYPE_FLOAT_VEC2:
810 return "bool compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, "
811 "b.x)&&compare_float(a.y, b.y); }\n";
812 case glu::TYPE_FLOAT_VEC3:
813 return "bool compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, "
814 "b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z); }\n";
815 case glu::TYPE_FLOAT_VEC4:
816 return "bool compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, "
817 "b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z)&&compare_float(a.w, b.w); }\n";
818 case glu::TYPE_FLOAT_MAT2:
819 return "bool compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], "
820 "b[0])&&compare_vec2(a[1], b[1]); }\n";
821 case glu::TYPE_FLOAT_MAT2X3:
822 return "bool compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], "
823 "b[0])&&compare_vec3(a[1], b[1]); }\n";
824 case glu::TYPE_FLOAT_MAT2X4:
825 return "bool compare_mat2x4 (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], "
826 "b[0])&&compare_vec4(a[1], b[1]); }\n";
827 case glu::TYPE_FLOAT_MAT3X2:
828 return "bool compare_mat3x2 (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], "
829 "b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2]); }\n";
830 case glu::TYPE_FLOAT_MAT3:
831 return "bool compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], "
832 "b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2]); }\n";
833 case glu::TYPE_FLOAT_MAT3X4:
834 return "bool compare_mat3x4 (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], "
835 "b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2]); }\n";
836 case glu::TYPE_FLOAT_MAT4X2:
837 return "bool compare_mat4x2 (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], "
838 "b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2])&&compare_vec2(a[3], b[3]); }\n";
839 case glu::TYPE_FLOAT_MAT4X3:
840 return "bool compare_mat4x3 (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], "
841 "b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2])&&compare_vec3(a[3], b[3]); }\n";
842 case glu::TYPE_FLOAT_MAT4:
843 return "bool compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], "
844 "b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2])&&compare_vec4(a[3], b[3]); }\n";
845 case glu::TYPE_INT:
846 return "bool compare_int (highp int a, highp int b) { return a == b; }\n";
847 case glu::TYPE_INT_VEC2:
848 return "bool compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b; }\n";
849 case glu::TYPE_INT_VEC3:
850 return "bool compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b; }\n";
851 case glu::TYPE_INT_VEC4:
852 return "bool compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b; }\n";
853 case glu::TYPE_UINT:
854 return "bool compare_uint (highp uint a, highp uint b) { return a == b; }\n";
855 case glu::TYPE_UINT_VEC2:
856 return "bool compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b; }\n";
857 case glu::TYPE_UINT_VEC3:
858 return "bool compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b; }\n";
859 case glu::TYPE_UINT_VEC4:
860 return "bool compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b; }\n";
861 case glu::TYPE_BOOL:
862 return "bool compare_bool (bool a, bool b) { return a == b; }\n";
863 case glu::TYPE_BOOL_VEC2:
864 return "bool compare_bvec2 (bvec2 a, bvec2 b) { return a == b; }\n";
865 case glu::TYPE_BOOL_VEC3:
866 return "bool compare_bvec3 (bvec3 a, bvec3 b) { return a == b; }\n";
867 case glu::TYPE_BOOL_VEC4:
868 return "bool compare_bvec4 (bvec4 a, bvec4 b) { return a == b; }\n";
869 default:
870 DE_ASSERT(false);
871 return DE_NULL;
872 }
873 }
874
getCompareDependencies(std::set<glu::DataType> & compareFuncs,glu::DataType basicType)875 void getCompareDependencies(std::set<glu::DataType> &compareFuncs, glu::DataType basicType)
876 {
877 switch (basicType)
878 {
879 case glu::TYPE_FLOAT_VEC2:
880 case glu::TYPE_FLOAT_VEC3:
881 case glu::TYPE_FLOAT_VEC4:
882 compareFuncs.insert(glu::TYPE_FLOAT);
883 compareFuncs.insert(basicType);
884 break;
885
886 case glu::TYPE_FLOAT_MAT2:
887 case glu::TYPE_FLOAT_MAT2X3:
888 case glu::TYPE_FLOAT_MAT2X4:
889 case glu::TYPE_FLOAT_MAT3X2:
890 case glu::TYPE_FLOAT_MAT3:
891 case glu::TYPE_FLOAT_MAT3X4:
892 case glu::TYPE_FLOAT_MAT4X2:
893 case glu::TYPE_FLOAT_MAT4X3:
894 case glu::TYPE_FLOAT_MAT4:
895 compareFuncs.insert(glu::TYPE_FLOAT);
896 compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
897 compareFuncs.insert(basicType);
898 break;
899
900 default:
901 compareFuncs.insert(basicType);
902 break;
903 }
904 }
905
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const VarType & type)906 void collectUniqueBasicTypes(std::set<glu::DataType> &basicTypes, const VarType &type)
907 {
908 if (type.isStructType())
909 {
910 for (StructType::ConstIterator iter = type.getStructPtr()->begin(); iter != type.getStructPtr()->end(); ++iter)
911 collectUniqueBasicTypes(basicTypes, iter->getType());
912 }
913 else if (type.isArrayType())
914 collectUniqueBasicTypes(basicTypes, type.getElementType());
915 else
916 {
917 DE_ASSERT(type.isBasicType());
918 basicTypes.insert(type.getBasicType());
919 }
920 }
921
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const BufferBlock & bufferBlock)922 void collectUniqueBasicTypes(std::set<glu::DataType> &basicTypes, const BufferBlock &bufferBlock)
923 {
924 for (BufferBlock::const_iterator iter = bufferBlock.begin(); iter != bufferBlock.end(); ++iter)
925 collectUniqueBasicTypes(basicTypes, iter->getType());
926 }
927
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const ShaderInterface & interface)928 void collectUniqueBasicTypes(std::set<glu::DataType> &basicTypes, const ShaderInterface &interface)
929 {
930 for (int ndx = 0; ndx < interface.getNumBlocks(); ++ndx)
931 collectUniqueBasicTypes(basicTypes, interface.getBlock(ndx));
932 }
933
generateCompareFuncs(std::ostream & str,const ShaderInterface & interface)934 void generateCompareFuncs(std::ostream &str, const ShaderInterface &interface)
935 {
936 std::set<glu::DataType> types;
937 std::set<glu::DataType> compareFuncs;
938
939 // Collect unique basic types
940 collectUniqueBasicTypes(types, interface);
941
942 // Set of compare functions required
943 for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
944 {
945 getCompareDependencies(compareFuncs, *iter);
946 }
947
948 for (int type = 0; type < glu::TYPE_LAST; ++type)
949 {
950 if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
951 str << getCompareFuncForType(glu::DataType(type));
952 }
953 }
954
955 struct Indent
956 {
957 int level;
Indentdeqp::gles31::bb::__anonc1049a2c0211::Indent958 Indent(int level_) : level(level_)
959 {
960 }
961 };
962
operator <<(std::ostream & str,const Indent & indent)963 std::ostream &operator<<(std::ostream &str, const Indent &indent)
964 {
965 for (int i = 0; i < indent.level; i++)
966 str << "\t";
967 return str;
968 }
969
generateDeclaration(std::ostream & src,const BufferVar & bufferVar,int indentLevel)970 void generateDeclaration(std::ostream &src, const BufferVar &bufferVar, int indentLevel)
971 {
972 // \todo [pyry] Qualifiers
973
974 if ((bufferVar.getFlags() & LAYOUT_MASK) != 0)
975 src << "layout(" << LayoutFlagsFmt(bufferVar.getFlags() & LAYOUT_MASK) << ") ";
976
977 src << glu::declare(bufferVar.getType(), bufferVar.getName(), indentLevel);
978 }
979
generateDeclaration(std::ostream & src,const BufferBlock & block,int bindingPoint)980 void generateDeclaration(std::ostream &src, const BufferBlock &block, int bindingPoint)
981 {
982 src << "layout(";
983
984 if ((block.getFlags() & LAYOUT_MASK) != 0)
985 src << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ", ";
986
987 src << "binding = " << bindingPoint;
988
989 src << ") ";
990
991 src << "buffer " << block.getBlockName();
992 src << "\n{\n";
993
994 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
995 {
996 src << Indent(1);
997 generateDeclaration(src, *varIter, 1 /* indent level */);
998 src << ";\n";
999 }
1000
1001 src << "}";
1002
1003 if (block.getInstanceName() != DE_NULL)
1004 {
1005 src << " " << block.getInstanceName();
1006 if (block.isArray())
1007 src << "[" << block.getArraySize() << "]";
1008 }
1009 else
1010 DE_ASSERT(!block.isArray());
1011
1012 src << ";\n";
1013 }
1014
generateImmMatrixSrc(std::ostream & src,glu::DataType basicType,int matrixStride,bool isRowMajor,const void * valuePtr)1015 void generateImmMatrixSrc(std::ostream &src, glu::DataType basicType, int matrixStride, bool isRowMajor,
1016 const void *valuePtr)
1017 {
1018 DE_ASSERT(glu::isDataTypeMatrix(basicType));
1019
1020 const int compSize = sizeof(uint32_t);
1021 const int numRows = glu::getDataTypeMatrixNumRows(basicType);
1022 const int numCols = glu::getDataTypeMatrixNumColumns(basicType);
1023
1024 src << glu::getDataTypeName(basicType) << "(";
1025
1026 // Constructed in column-wise order.
1027 for (int colNdx = 0; colNdx < numCols; colNdx++)
1028 {
1029 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1030 {
1031 const uint8_t *compPtr =
1032 (const uint8_t *)valuePtr +
1033 (isRowMajor ? rowNdx * matrixStride + colNdx * compSize : colNdx * matrixStride + rowNdx * compSize);
1034
1035 if (colNdx > 0 || rowNdx > 0)
1036 src << ", ";
1037
1038 src << de::floatToString(*((const float *)compPtr), 1);
1039 }
1040 }
1041
1042 src << ")";
1043 }
1044
generateImmScalarVectorSrc(std::ostream & src,glu::DataType basicType,const void * valuePtr)1045 void generateImmScalarVectorSrc(std::ostream &src, glu::DataType basicType, const void *valuePtr)
1046 {
1047 DE_ASSERT(glu::isDataTypeFloatOrVec(basicType) || glu::isDataTypeIntOrIVec(basicType) ||
1048 glu::isDataTypeUintOrUVec(basicType) || glu::isDataTypeBoolOrBVec(basicType));
1049
1050 const glu::DataType scalarType = glu::getDataTypeScalarType(basicType);
1051 const int scalarSize = glu::getDataTypeScalarSize(basicType);
1052 const int compSize = sizeof(uint32_t);
1053
1054 if (scalarSize > 1)
1055 src << glu::getDataTypeName(basicType) << "(";
1056
1057 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1058 {
1059 const uint8_t *compPtr = (const uint8_t *)valuePtr + scalarNdx * compSize;
1060
1061 if (scalarNdx > 0)
1062 src << ", ";
1063
1064 switch (scalarType)
1065 {
1066 case glu::TYPE_FLOAT:
1067 src << de::floatToString(*((const float *)compPtr), 1);
1068 break;
1069 case glu::TYPE_INT:
1070 src << *((const int *)compPtr);
1071 break;
1072 case glu::TYPE_UINT:
1073 src << *((const uint32_t *)compPtr) << "u";
1074 break;
1075 case glu::TYPE_BOOL:
1076 src << (*((const uint32_t *)compPtr) != 0u ? "true" : "false");
1077 break;
1078 default:
1079 DE_ASSERT(false);
1080 }
1081 }
1082
1083 if (scalarSize > 1)
1084 src << ")";
1085 }
1086
getAPIName(const BufferBlock & block,const BufferVar & var,const glu::TypeComponentVector & accessPath)1087 string getAPIName(const BufferBlock &block, const BufferVar &var, const glu::TypeComponentVector &accessPath)
1088 {
1089 std::ostringstream name;
1090
1091 if (block.getInstanceName())
1092 name << block.getBlockName() << ".";
1093
1094 name << var.getName();
1095
1096 for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end();
1097 pathComp++)
1098 {
1099 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1100 {
1101 const VarType curType = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1102 const StructType *structPtr = curType.getStructPtr();
1103
1104 name << "." << structPtr->getMember(pathComp->index).getName();
1105 }
1106 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1107 {
1108 if (pathComp == accessPath.begin() || (pathComp + 1) == accessPath.end())
1109 name << "[0]"; // Top- / bottom-level array
1110 else
1111 name << "[" << pathComp->index << "]";
1112 }
1113 else
1114 DE_ASSERT(false);
1115 }
1116
1117 return name.str();
1118 }
1119
getShaderName(const BufferBlock & block,int instanceNdx,const BufferVar & var,const glu::TypeComponentVector & accessPath)1120 string getShaderName(const BufferBlock &block, int instanceNdx, const BufferVar &var,
1121 const glu::TypeComponentVector &accessPath)
1122 {
1123 std::ostringstream name;
1124
1125 if (block.getInstanceName())
1126 {
1127 name << block.getInstanceName();
1128
1129 if (block.isArray())
1130 name << "[" << instanceNdx << "]";
1131
1132 name << ".";
1133 }
1134 else
1135 DE_ASSERT(instanceNdx == 0);
1136
1137 name << var.getName();
1138
1139 for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end();
1140 pathComp++)
1141 {
1142 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1143 {
1144 const VarType curType = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1145 const StructType *structPtr = curType.getStructPtr();
1146
1147 name << "." << structPtr->getMember(pathComp->index).getName();
1148 }
1149 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1150 name << "[" << pathComp->index << "]";
1151 else
1152 DE_ASSERT(false);
1153 }
1154
1155 return name.str();
1156 }
1157
computeOffset(const BufferVarLayoutEntry & varLayout,const glu::TypeComponentVector & accessPath)1158 int computeOffset(const BufferVarLayoutEntry &varLayout, const glu::TypeComponentVector &accessPath)
1159 {
1160 const int topLevelNdx = (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ?
1161 accessPath.front().index :
1162 0;
1163 const int bottomLevelNdx = (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ?
1164 accessPath.back().index :
1165 0;
1166
1167 return varLayout.offset + varLayout.topLevelArrayStride * topLevelNdx + varLayout.arrayStride * bottomLevelNdx;
1168 }
1169
generateCompareSrc(std::ostream & src,const char * resultVar,const BufferLayout & bufferLayout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & blockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1170 void generateCompareSrc(std::ostream &src, const char *resultVar, const BufferLayout &bufferLayout,
1171 const BufferBlock &block, int instanceNdx, const BlockDataPtr &blockPtr,
1172 const BufferVar &bufVar, const glu::SubTypeAccess &accessPath)
1173 {
1174 const VarType curType = accessPath.getType();
1175
1176 if (curType.isArrayType())
1177 {
1178 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ?
1179 block.getLastUnsizedArraySize(instanceNdx) :
1180 curType.getArraySize();
1181
1182 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1183 generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar,
1184 accessPath.element(elemNdx));
1185 }
1186 else if (curType.isStructType())
1187 {
1188 const int numMembers = curType.getStructPtr()->getNumMembers();
1189
1190 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1191 generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar,
1192 accessPath.member(memberNdx));
1193 }
1194 else
1195 {
1196 DE_ASSERT(curType.isBasicType());
1197
1198 const string apiName = getAPIName(block, bufVar, accessPath.getPath());
1199 const int varNdx = bufferLayout.getVariableIndex(apiName);
1200
1201 DE_ASSERT(varNdx >= 0);
1202 {
1203 const BufferVarLayoutEntry &varLayout = bufferLayout.bufferVars[varNdx];
1204 const string shaderName = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1205 const glu::DataType basicType = curType.getBasicType();
1206 const bool isMatrix = glu::isDataTypeMatrix(basicType);
1207 const char *typeName = glu::getDataTypeName(basicType);
1208 const void *valuePtr = (const uint8_t *)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1209
1210 src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", ";
1211
1212 if (isMatrix)
1213 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1214 else
1215 generateImmScalarVectorSrc(src, basicType, valuePtr);
1216
1217 src << ");\n";
1218 }
1219 }
1220 }
1221
generateCompareSrc(std::ostream & src,const char * resultVar,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers)1222 void generateCompareSrc(std::ostream &src, const char *resultVar, const ShaderInterface &interface,
1223 const BufferLayout &layout, const vector<BlockDataPtr> &blockPointers)
1224 {
1225 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1226 {
1227 const BufferBlock &block = interface.getBlock(declNdx);
1228 const bool isArray = block.isArray();
1229 const int numInstances = isArray ? block.getArraySize() : 1;
1230
1231 DE_ASSERT(!isArray || block.getInstanceName());
1232
1233 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1234 {
1235 const string instanceName =
1236 block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1237 const int blockNdx = layout.getBlockIndex(instanceName);
1238 const BlockDataPtr &blockPtr = blockPointers[blockNdx];
1239
1240 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1241 {
1242 const BufferVar &bufVar = *varIter;
1243
1244 if ((bufVar.getFlags() & ACCESS_READ) == 0)
1245 continue; // Don't read from that variable.
1246
1247 generateCompareSrc(src, resultVar, layout, block, instanceNdx, blockPtr, bufVar,
1248 glu::SubTypeAccess(bufVar.getType()));
1249 }
1250 }
1251 }
1252 }
1253
1254 // \todo [2013-10-14 pyry] Almost identical to generateCompareSrc - unify?
1255
generateWriteSrc(std::ostream & src,const BufferLayout & bufferLayout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & blockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1256 void generateWriteSrc(std::ostream &src, const BufferLayout &bufferLayout, const BufferBlock &block, int instanceNdx,
1257 const BlockDataPtr &blockPtr, const BufferVar &bufVar, const glu::SubTypeAccess &accessPath)
1258 {
1259 const VarType curType = accessPath.getType();
1260
1261 if (curType.isArrayType())
1262 {
1263 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ?
1264 block.getLastUnsizedArraySize(instanceNdx) :
1265 curType.getArraySize();
1266
1267 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1268 generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1269 }
1270 else if (curType.isStructType())
1271 {
1272 const int numMembers = curType.getStructPtr()->getNumMembers();
1273
1274 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1275 generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1276 }
1277 else
1278 {
1279 DE_ASSERT(curType.isBasicType());
1280
1281 const string apiName = getAPIName(block, bufVar, accessPath.getPath());
1282 const int varNdx = bufferLayout.getVariableIndex(apiName);
1283
1284 DE_ASSERT(varNdx >= 0);
1285 {
1286 const BufferVarLayoutEntry &varLayout = bufferLayout.bufferVars[varNdx];
1287 const string shaderName = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1288 const glu::DataType basicType = curType.getBasicType();
1289 const bool isMatrix = glu::isDataTypeMatrix(basicType);
1290 const void *valuePtr = (const uint8_t *)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1291
1292 src << "\t" << shaderName << " = ";
1293
1294 if (isMatrix)
1295 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1296 else
1297 generateImmScalarVectorSrc(src, basicType, valuePtr);
1298
1299 src << ";\n";
1300 }
1301 }
1302 }
1303
generateWriteSrc(std::ostream & src,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers)1304 void generateWriteSrc(std::ostream &src, const ShaderInterface &interface, const BufferLayout &layout,
1305 const vector<BlockDataPtr> &blockPointers)
1306 {
1307 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1308 {
1309 const BufferBlock &block = interface.getBlock(declNdx);
1310 const bool isArray = block.isArray();
1311 const int numInstances = isArray ? block.getArraySize() : 1;
1312
1313 DE_ASSERT(!isArray || block.getInstanceName());
1314
1315 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1316 {
1317 const string instanceName =
1318 block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1319 const int blockNdx = layout.getBlockIndex(instanceName);
1320 const BlockDataPtr &blockPtr = blockPointers[blockNdx];
1321
1322 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1323 {
1324 const BufferVar &bufVar = *varIter;
1325
1326 if ((bufVar.getFlags() & ACCESS_WRITE) == 0)
1327 continue; // Don't write to that variable.
1328
1329 generateWriteSrc(src, layout, block, instanceNdx, blockPtr, bufVar,
1330 glu::SubTypeAccess(bufVar.getType()));
1331 }
1332 }
1333 }
1334 }
1335
generateComputeShader(const glw::Functions & gl,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & comparePtrs,const vector<BlockDataPtr> & writePtrs)1336 string generateComputeShader(const glw::Functions &gl, glu::GLSLVersion glslVersion, const ShaderInterface &interface,
1337 const BufferLayout &layout, const vector<BlockDataPtr> &comparePtrs,
1338 const vector<BlockDataPtr> &writePtrs)
1339 {
1340 std::ostringstream src;
1341 glw::GLint maxShaderStorageBufferBindings;
1342 glw::GLint maxComputeShaderStorageBlocks;
1343
1344 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430);
1345
1346 gl.getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxShaderStorageBufferBindings);
1347 gl.getIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
1348
1349 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1350 src << "layout(local_size_x = 1) in;\n";
1351 src << "\n";
1352
1353 std::vector<const StructType *> namedStructs;
1354 interface.getNamedStructs(namedStructs);
1355 for (std::vector<const StructType *>::const_iterator structIter = namedStructs.begin();
1356 structIter != namedStructs.end(); structIter++)
1357 src << glu::declare(*structIter) << ";\n";
1358
1359 {
1360 int bindingPoint = 0;
1361
1362 for (int blockNdx = 0; blockNdx < interface.getNumBlocks(); blockNdx++)
1363 {
1364 const BufferBlock &block = interface.getBlock(blockNdx);
1365 generateDeclaration(src, block, bindingPoint);
1366
1367 bindingPoint += block.isArray() ? block.getArraySize() : 1;
1368 }
1369
1370 if (bindingPoint > maxShaderStorageBufferBindings)
1371 {
1372 throw tcu::NotSupportedError("Test requires support for more SSBO bindings than implementation exposes");
1373 }
1374 if (bindingPoint > maxComputeShaderStorageBlocks)
1375 {
1376 throw tcu::NotSupportedError(
1377 "Test requires support for more compute shader storage blocks than implementation exposes");
1378 }
1379 }
1380
1381 // Atomic counter for counting passed invocations.
1382 src << "\nlayout(binding = 0) uniform atomic_uint ac_numPassed;\n";
1383
1384 // Comparison utilities.
1385 src << "\n";
1386 generateCompareFuncs(src, interface);
1387
1388 src << "\n"
1389 "void main (void)\n"
1390 "{\n"
1391 " bool allOk = true;\n";
1392
1393 // Value compare.
1394 generateCompareSrc(src, "allOk", interface, layout, comparePtrs);
1395
1396 src << " if (allOk)\n"
1397 << " atomicCounterIncrement(ac_numPassed);\n"
1398 << "\n";
1399
1400 // Value write.
1401 generateWriteSrc(src, interface, layout, writePtrs);
1402
1403 src << "}\n";
1404
1405 return src.str();
1406 }
1407
getGLBufferLayout(const glw::Functions & gl,BufferLayout & layout,uint32_t program)1408 void getGLBufferLayout(const glw::Functions &gl, BufferLayout &layout, uint32_t program)
1409 {
1410 int numActiveBufferVars = 0;
1411 int numActiveBlocks = 0;
1412
1413 gl.getProgramInterfaceiv(program, GL_BUFFER_VARIABLE, GL_ACTIVE_RESOURCES, &numActiveBufferVars);
1414 gl.getProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numActiveBlocks);
1415
1416 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of buffer variables and buffer blocks");
1417
1418 // Block entries.
1419 layout.blocks.resize(numActiveBlocks);
1420 for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++)
1421 {
1422 BlockLayoutEntry &entry = layout.blocks[blockNdx];
1423 const uint32_t queryParams[] = {GL_BUFFER_DATA_SIZE, GL_NUM_ACTIVE_VARIABLES, GL_NAME_LENGTH};
1424 int returnValues[] = {0, 0, 0};
1425
1426 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues));
1427
1428 {
1429 int returnLength = 0;
1430 gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (uint32_t)blockNdx,
1431 DE_LENGTH_OF_ARRAY(queryParams), &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues),
1432 &returnLength, &returnValues[0]);
1433 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) failed");
1434
1435 if (returnLength != DE_LENGTH_OF_ARRAY(returnValues))
1436 throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) returned wrong number of values");
1437 }
1438
1439 entry.size = returnValues[0];
1440
1441 // Query active variables
1442 if (returnValues[1] > 0)
1443 {
1444 const int numBlockVars = returnValues[1];
1445 const uint32_t queryArg = GL_ACTIVE_VARIABLES;
1446 int retLength = 0;
1447
1448 entry.activeVarIndices.resize(numBlockVars);
1449 gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (uint32_t)blockNdx, 1, &queryArg, numBlockVars,
1450 &retLength, &entry.activeVarIndices[0]);
1451 GLU_EXPECT_NO_ERROR(gl.getError(),
1452 "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) failed");
1453
1454 if (retLength != numBlockVars)
1455 throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) returned "
1456 "wrong number of values");
1457 }
1458
1459 // Query name
1460 if (returnValues[2] > 0)
1461 {
1462 const int nameLen = returnValues[2];
1463 int retLen = 0;
1464 vector<char> name(nameLen);
1465
1466 gl.getProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, (uint32_t)blockNdx, (glw::GLsizei)name.size(),
1467 &retLen, &name[0]);
1468 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) failed");
1469
1470 if (retLen + 1 != nameLen)
1471 throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. Number "
1472 "of characters written is inconsistent with NAME_LENGTH property.");
1473 if (name[nameLen - 1] != 0)
1474 throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. "
1475 "Expected null terminator at index " +
1476 de::toString(nameLen - 1));
1477
1478 entry.name = &name[0];
1479 }
1480 else
1481 throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH");
1482 }
1483
1484 layout.bufferVars.resize(numActiveBufferVars);
1485 for (int bufVarNdx = 0; bufVarNdx < numActiveBufferVars; bufVarNdx++)
1486 {
1487 BufferVarLayoutEntry &entry = layout.bufferVars[bufVarNdx];
1488 const uint32_t queryParams[] = {
1489 GL_BLOCK_INDEX, // 0
1490 GL_TYPE, // 1
1491 GL_OFFSET, // 2
1492 GL_ARRAY_SIZE, // 3
1493 GL_ARRAY_STRIDE, // 4
1494 GL_MATRIX_STRIDE, // 5
1495 GL_TOP_LEVEL_ARRAY_SIZE, // 6
1496 GL_TOP_LEVEL_ARRAY_STRIDE, // 7
1497 GL_IS_ROW_MAJOR, // 8
1498 GL_NAME_LENGTH // 9
1499 };
1500 int returnValues[DE_LENGTH_OF_ARRAY(queryParams)];
1501
1502 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues));
1503
1504 {
1505 int returnLength = 0;
1506 gl.getProgramResourceiv(program, GL_BUFFER_VARIABLE, (uint32_t)bufVarNdx, DE_LENGTH_OF_ARRAY(queryParams),
1507 &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues), &returnLength, &returnValues[0]);
1508 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_BUFFER_VARIABLE) failed");
1509
1510 if (returnLength != DE_LENGTH_OF_ARRAY(returnValues))
1511 throw tcu::TestError("glGetProgramResourceiv(GL_BUFFER_VARIABLE) returned wrong number of values");
1512 }
1513
1514 // Map values
1515 entry.blockNdx = returnValues[0];
1516 entry.type = glu::getDataTypeFromGLType(returnValues[1]);
1517 entry.offset = returnValues[2];
1518 entry.arraySize = returnValues[3];
1519 entry.arrayStride = returnValues[4];
1520 entry.matrixStride = returnValues[5];
1521 entry.topLevelArraySize = returnValues[6];
1522 entry.topLevelArrayStride = returnValues[7];
1523 entry.isRowMajor = returnValues[8] != 0;
1524
1525 // Query name
1526 DE_ASSERT(queryParams[9] == GL_NAME_LENGTH);
1527 if (returnValues[9] > 0)
1528 {
1529 const int nameLen = returnValues[9];
1530 int retLen = 0;
1531 vector<char> name(nameLen);
1532
1533 gl.getProgramResourceName(program, GL_BUFFER_VARIABLE, (uint32_t)bufVarNdx, (glw::GLsizei)name.size(),
1534 &retLen, &name[0]);
1535 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_BUFFER_VARIABLE) failed");
1536
1537 if (retLen + 1 != nameLen)
1538 throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Number of "
1539 "characters written is inconsistent with NAME_LENGTH property.");
1540 if (name[nameLen - 1] != 0)
1541 throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Expected "
1542 "null terminator at index " +
1543 de::toString(nameLen - 1));
1544
1545 entry.name = &name[0];
1546 }
1547 else
1548 throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH");
1549 }
1550 }
1551
copyBufferVarData(const BufferVarLayoutEntry & dstEntry,const BlockDataPtr & dstBlockPtr,const BufferVarLayoutEntry & srcEntry,const BlockDataPtr & srcBlockPtr)1552 void copyBufferVarData(const BufferVarLayoutEntry &dstEntry, const BlockDataPtr &dstBlockPtr,
1553 const BufferVarLayoutEntry &srcEntry, const BlockDataPtr &srcBlockPtr)
1554 {
1555 DE_ASSERT(dstEntry.arraySize <= srcEntry.arraySize);
1556 DE_ASSERT(dstEntry.topLevelArraySize <= srcEntry.topLevelArraySize);
1557 DE_ASSERT(dstBlockPtr.lastUnsizedArraySize <= srcBlockPtr.lastUnsizedArraySize);
1558 DE_ASSERT(dstEntry.type == srcEntry.type);
1559
1560 uint8_t *const dstBasePtr = (uint8_t *)dstBlockPtr.ptr + dstEntry.offset;
1561 const uint8_t *const srcBasePtr = (const uint8_t *)srcBlockPtr.ptr + srcEntry.offset;
1562 const int scalarSize = glu::getDataTypeScalarSize(dstEntry.type);
1563 const bool isMatrix = glu::isDataTypeMatrix(dstEntry.type);
1564 const int compSize = sizeof(uint32_t);
1565 const int dstArraySize = dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize;
1566 const int dstArrayStride = dstEntry.arrayStride;
1567 const int dstTopLevelSize =
1568 dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize;
1569 const int dstTopLevelStride = dstEntry.topLevelArrayStride;
1570 const int srcArraySize = srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize;
1571 const int srcArrayStride = srcEntry.arrayStride;
1572 const int srcTopLevelSize =
1573 srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize;
1574 const int srcTopLevelStride = srcEntry.topLevelArrayStride;
1575
1576 DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize);
1577 DE_UNREF(srcArraySize && srcTopLevelSize);
1578
1579 for (int topElemNdx = 0; topElemNdx < dstTopLevelSize; topElemNdx++)
1580 {
1581 uint8_t *const dstTopPtr = dstBasePtr + topElemNdx * dstTopLevelStride;
1582 const uint8_t *const srcTopPtr = srcBasePtr + topElemNdx * srcTopLevelStride;
1583
1584 for (int elementNdx = 0; elementNdx < dstArraySize; elementNdx++)
1585 {
1586 uint8_t *const dstElemPtr = dstTopPtr + elementNdx * dstArrayStride;
1587 const uint8_t *const srcElemPtr = srcTopPtr + elementNdx * srcArrayStride;
1588
1589 if (isMatrix)
1590 {
1591 const int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
1592 const int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
1593
1594 for (int colNdx = 0; colNdx < numCols; colNdx++)
1595 {
1596 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1597 {
1598 uint8_t *dstCompPtr =
1599 dstElemPtr + (dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize :
1600 colNdx * dstEntry.matrixStride + rowNdx * compSize);
1601 const uint8_t *srcCompPtr =
1602 srcElemPtr + (srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize :
1603 colNdx * srcEntry.matrixStride + rowNdx * compSize);
1604
1605 DE_ASSERT((intptr_t)(srcCompPtr + compSize) - (intptr_t)srcBlockPtr.ptr <=
1606 (intptr_t)srcBlockPtr.size);
1607 DE_ASSERT((intptr_t)(dstCompPtr + compSize) - (intptr_t)dstBlockPtr.ptr <=
1608 (intptr_t)dstBlockPtr.size);
1609 deMemcpy(dstCompPtr, srcCompPtr, compSize);
1610 }
1611 }
1612 }
1613 else
1614 {
1615 DE_ASSERT((intptr_t)(srcElemPtr + scalarSize * compSize) - (intptr_t)srcBlockPtr.ptr <=
1616 (intptr_t)srcBlockPtr.size);
1617 DE_ASSERT((intptr_t)(dstElemPtr + scalarSize * compSize) - (intptr_t)dstBlockPtr.ptr <=
1618 (intptr_t)dstBlockPtr.size);
1619 deMemcpy(dstElemPtr, srcElemPtr, scalarSize * compSize);
1620 }
1621 }
1622 }
1623 }
1624
copyData(const BufferLayout & dstLayout,const vector<BlockDataPtr> & dstBlockPointers,const BufferLayout & srcLayout,const vector<BlockDataPtr> & srcBlockPointers)1625 void copyData(const BufferLayout &dstLayout, const vector<BlockDataPtr> &dstBlockPointers,
1626 const BufferLayout &srcLayout, const vector<BlockDataPtr> &srcBlockPointers)
1627 {
1628 // \note Src layout is used as reference in case of activeVarIndices happens to be incorrect in dstLayout blocks.
1629 int numBlocks = (int)srcLayout.blocks.size();
1630
1631 for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1632 {
1633 const BlockLayoutEntry &srcBlock = srcLayout.blocks[srcBlockNdx];
1634 const BlockDataPtr &srcBlockPtr = srcBlockPointers[srcBlockNdx];
1635 int dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name.c_str());
1636
1637 if (dstBlockNdx >= 0)
1638 {
1639 DE_ASSERT(de::inBounds(dstBlockNdx, 0, (int)dstBlockPointers.size()));
1640
1641 const BlockDataPtr &dstBlockPtr = dstBlockPointers[dstBlockNdx];
1642
1643 for (vector<int>::const_iterator srcVarNdxIter = srcBlock.activeVarIndices.begin();
1644 srcVarNdxIter != srcBlock.activeVarIndices.end(); srcVarNdxIter++)
1645 {
1646 const BufferVarLayoutEntry &srcEntry = srcLayout.bufferVars[*srcVarNdxIter];
1647 int dstVarNdx = dstLayout.getVariableIndex(srcEntry.name.c_str());
1648
1649 if (dstVarNdx >= 0)
1650 copyBufferVarData(dstLayout.bufferVars[dstVarNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1651 }
1652 }
1653 }
1654 }
1655
copyNonWrittenData(const BufferLayout & layout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & srcBlockPtr,const BlockDataPtr & dstBlockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1656 void copyNonWrittenData(const BufferLayout &layout, const BufferBlock &block, int instanceNdx,
1657 const BlockDataPtr &srcBlockPtr, const BlockDataPtr &dstBlockPtr, const BufferVar &bufVar,
1658 const glu::SubTypeAccess &accessPath)
1659 {
1660 const VarType curType = accessPath.getType();
1661
1662 if (curType.isArrayType())
1663 {
1664 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ?
1665 block.getLastUnsizedArraySize(instanceNdx) :
1666 curType.getArraySize();
1667
1668 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1669 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar,
1670 accessPath.element(elemNdx));
1671 }
1672 else if (curType.isStructType())
1673 {
1674 const int numMembers = curType.getStructPtr()->getNumMembers();
1675
1676 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1677 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar,
1678 accessPath.member(memberNdx));
1679 }
1680 else
1681 {
1682 DE_ASSERT(curType.isBasicType());
1683
1684 const string apiName = getAPIName(block, bufVar, accessPath.getPath());
1685 const int varNdx = layout.getVariableIndex(apiName);
1686
1687 DE_ASSERT(varNdx >= 0);
1688 {
1689 const BufferVarLayoutEntry &varLayout = layout.bufferVars[varNdx];
1690 copyBufferVarData(varLayout, dstBlockPtr, varLayout, srcBlockPtr);
1691 }
1692 }
1693 }
1694
copyNonWrittenData(const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & srcPtrs,const vector<BlockDataPtr> & dstPtrs)1695 void copyNonWrittenData(const ShaderInterface &interface, const BufferLayout &layout,
1696 const vector<BlockDataPtr> &srcPtrs, const vector<BlockDataPtr> &dstPtrs)
1697 {
1698 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1699 {
1700 const BufferBlock &block = interface.getBlock(declNdx);
1701 const bool isArray = block.isArray();
1702 const int numInstances = isArray ? block.getArraySize() : 1;
1703
1704 DE_ASSERT(!isArray || block.getInstanceName());
1705
1706 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1707 {
1708 const string instanceName =
1709 block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1710 const int blockNdx = layout.getBlockIndex(instanceName);
1711 const BlockDataPtr &srcBlockPtr = srcPtrs[blockNdx];
1712 const BlockDataPtr &dstBlockPtr = dstPtrs[blockNdx];
1713
1714 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1715 {
1716 const BufferVar &bufVar = *varIter;
1717
1718 if (bufVar.getFlags() & ACCESS_WRITE)
1719 continue;
1720
1721 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar,
1722 glu::SubTypeAccess(bufVar.getType()));
1723 }
1724 }
1725 }
1726 }
1727
compareComponents(glu::DataType scalarType,const void * ref,const void * res,int numComps)1728 bool compareComponents(glu::DataType scalarType, const void *ref, const void *res, int numComps)
1729 {
1730 if (scalarType == glu::TYPE_FLOAT)
1731 {
1732 const float threshold = 0.05f; // Same as used in shaders - should be fine for values being used.
1733
1734 for (int ndx = 0; ndx < numComps; ndx++)
1735 {
1736 const float refVal = *((const float *)ref + ndx);
1737 const float resVal = *((const float *)res + ndx);
1738
1739 if (!(deFloatAbs(resVal - refVal) <= threshold))
1740 return false;
1741 }
1742 }
1743 else if (scalarType == glu::TYPE_BOOL)
1744 {
1745 for (int ndx = 0; ndx < numComps; ndx++)
1746 {
1747 const uint32_t refVal = *((const uint32_t *)ref + ndx);
1748 const uint32_t resVal = *((const uint32_t *)res + ndx);
1749
1750 if ((refVal != 0) != (resVal != 0))
1751 return false;
1752 }
1753 }
1754 else
1755 {
1756 DE_ASSERT(scalarType == glu::TYPE_INT || scalarType == glu::TYPE_UINT);
1757
1758 for (int ndx = 0; ndx < numComps; ndx++)
1759 {
1760 const uint32_t refVal = *((const uint32_t *)ref + ndx);
1761 const uint32_t resVal = *((const uint32_t *)res + ndx);
1762
1763 if (refVal != resVal)
1764 return false;
1765 }
1766 }
1767
1768 return true;
1769 }
1770
compareBufferVarData(tcu::TestLog & log,const BufferVarLayoutEntry & refEntry,const BlockDataPtr & refBlockPtr,const BufferVarLayoutEntry & resEntry,const BlockDataPtr & resBlockPtr)1771 bool compareBufferVarData(tcu::TestLog &log, const BufferVarLayoutEntry &refEntry, const BlockDataPtr &refBlockPtr,
1772 const BufferVarLayoutEntry &resEntry, const BlockDataPtr &resBlockPtr)
1773 {
1774 DE_ASSERT(resEntry.arraySize <= refEntry.arraySize);
1775 DE_ASSERT(resEntry.topLevelArraySize <= refEntry.topLevelArraySize);
1776 DE_ASSERT(resBlockPtr.lastUnsizedArraySize <= refBlockPtr.lastUnsizedArraySize);
1777 DE_ASSERT(resEntry.type == refEntry.type);
1778
1779 uint8_t *const resBasePtr = (uint8_t *)resBlockPtr.ptr + resEntry.offset;
1780 const uint8_t *const refBasePtr = (const uint8_t *)refBlockPtr.ptr + refEntry.offset;
1781 const glu::DataType scalarType = glu::getDataTypeScalarType(refEntry.type);
1782 const int scalarSize = glu::getDataTypeScalarSize(resEntry.type);
1783 const bool isMatrix = glu::isDataTypeMatrix(resEntry.type);
1784 const int compSize = sizeof(uint32_t);
1785 const int maxPrints = 3;
1786 int numFailed = 0;
1787
1788 const int resArraySize = resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize;
1789 const int resArrayStride = resEntry.arrayStride;
1790 const int resTopLevelSize =
1791 resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize;
1792 const int resTopLevelStride = resEntry.topLevelArrayStride;
1793 const int refArraySize = refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize;
1794 const int refArrayStride = refEntry.arrayStride;
1795 const int refTopLevelSize =
1796 refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize;
1797 const int refTopLevelStride = refEntry.topLevelArrayStride;
1798
1799 DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize);
1800 DE_UNREF(refArraySize && refTopLevelSize);
1801
1802 for (int topElemNdx = 0; topElemNdx < resTopLevelSize; topElemNdx++)
1803 {
1804 uint8_t *const resTopPtr = resBasePtr + topElemNdx * resTopLevelStride;
1805 const uint8_t *const refTopPtr = refBasePtr + topElemNdx * refTopLevelStride;
1806
1807 for (int elementNdx = 0; elementNdx < resArraySize; elementNdx++)
1808 {
1809 uint8_t *const resElemPtr = resTopPtr + elementNdx * resArrayStride;
1810 const uint8_t *const refElemPtr = refTopPtr + elementNdx * refArrayStride;
1811
1812 if (isMatrix)
1813 {
1814 const int numRows = glu::getDataTypeMatrixNumRows(resEntry.type);
1815 const int numCols = glu::getDataTypeMatrixNumColumns(resEntry.type);
1816 bool isOk = true;
1817
1818 for (int colNdx = 0; colNdx < numCols; colNdx++)
1819 {
1820 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1821 {
1822 uint8_t *resCompPtr =
1823 resElemPtr + (resEntry.isRowMajor ? rowNdx * resEntry.matrixStride + colNdx * compSize :
1824 colNdx * resEntry.matrixStride + rowNdx * compSize);
1825 const uint8_t *refCompPtr =
1826 refElemPtr + (refEntry.isRowMajor ? rowNdx * refEntry.matrixStride + colNdx * compSize :
1827 colNdx * refEntry.matrixStride + rowNdx * compSize);
1828
1829 DE_ASSERT((intptr_t)(refCompPtr + compSize) - (intptr_t)refBlockPtr.ptr <=
1830 (intptr_t)refBlockPtr.size);
1831 DE_ASSERT((intptr_t)(resCompPtr + compSize) - (intptr_t)resBlockPtr.ptr <=
1832 (intptr_t)resBlockPtr.size);
1833
1834 isOk = isOk && compareComponents(scalarType, resCompPtr, refCompPtr, 1);
1835 }
1836 }
1837
1838 if (!isOk)
1839 {
1840 numFailed += 1;
1841 if (numFailed < maxPrints)
1842 {
1843 std::ostringstream expected, got;
1844 generateImmMatrixSrc(expected, refEntry.type, refEntry.matrixStride, refEntry.isRowMajor,
1845 refElemPtr);
1846 generateImmMatrixSrc(got, resEntry.type, resEntry.matrixStride, resEntry.isRowMajor,
1847 resElemPtr);
1848 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx "
1849 << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1850 << " expected " << expected.str() << "\n"
1851 << " got " << got.str() << TestLog::EndMessage;
1852 }
1853 }
1854 }
1855 else
1856 {
1857 DE_ASSERT((intptr_t)(refElemPtr + scalarSize * compSize) - (intptr_t)refBlockPtr.ptr <=
1858 (intptr_t)refBlockPtr.size);
1859 DE_ASSERT((intptr_t)(resElemPtr + scalarSize * compSize) - (intptr_t)resBlockPtr.ptr <=
1860 (intptr_t)resBlockPtr.size);
1861
1862 const bool isOk = compareComponents(scalarType, resElemPtr, refElemPtr, scalarSize);
1863
1864 if (!isOk)
1865 {
1866 numFailed += 1;
1867 if (numFailed < maxPrints)
1868 {
1869 std::ostringstream expected, got;
1870 generateImmScalarVectorSrc(expected, refEntry.type, refElemPtr);
1871 generateImmScalarVectorSrc(got, resEntry.type, resElemPtr);
1872 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx "
1873 << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1874 << " expected " << expected.str() << "\n"
1875 << " got " << got.str() << TestLog::EndMessage;
1876 }
1877 }
1878 }
1879 }
1880 }
1881
1882 if (numFailed >= maxPrints)
1883 log << TestLog::Message << "... (" << numFailed << " failures for " << refEntry.name << " in total)"
1884 << TestLog::EndMessage;
1885
1886 return numFailed == 0;
1887 }
1888
compareData(tcu::TestLog & log,const BufferLayout & refLayout,const vector<BlockDataPtr> & refBlockPointers,const BufferLayout & resLayout,const vector<BlockDataPtr> & resBlockPointers)1889 bool compareData(tcu::TestLog &log, const BufferLayout &refLayout, const vector<BlockDataPtr> &refBlockPointers,
1890 const BufferLayout &resLayout, const vector<BlockDataPtr> &resBlockPointers)
1891 {
1892 const int numBlocks = (int)refLayout.blocks.size();
1893 bool allOk = true;
1894
1895 for (int refBlockNdx = 0; refBlockNdx < numBlocks; refBlockNdx++)
1896 {
1897 const BlockLayoutEntry &refBlock = refLayout.blocks[refBlockNdx];
1898 const BlockDataPtr &refBlockPtr = refBlockPointers[refBlockNdx];
1899 int resBlockNdx = resLayout.getBlockIndex(refBlock.name.c_str());
1900
1901 if (resBlockNdx >= 0)
1902 {
1903 DE_ASSERT(de::inBounds(resBlockNdx, 0, (int)resBlockPointers.size()));
1904
1905 const BlockDataPtr &resBlockPtr = resBlockPointers[resBlockNdx];
1906
1907 for (vector<int>::const_iterator refVarNdxIter = refBlock.activeVarIndices.begin();
1908 refVarNdxIter != refBlock.activeVarIndices.end(); refVarNdxIter++)
1909 {
1910 const BufferVarLayoutEntry &refEntry = refLayout.bufferVars[*refVarNdxIter];
1911 int resVarNdx = resLayout.getVariableIndex(refEntry.name.c_str());
1912
1913 if (resVarNdx >= 0)
1914 {
1915 const BufferVarLayoutEntry &resEntry = resLayout.bufferVars[resVarNdx];
1916 allOk = compareBufferVarData(log, refEntry, refBlockPtr, resEntry, resBlockPtr) && allOk;
1917 }
1918 }
1919 }
1920 }
1921
1922 return allOk;
1923 }
1924
getBlockAPIName(const BufferBlock & block,int instanceNdx)1925 string getBlockAPIName(const BufferBlock &block, int instanceNdx)
1926 {
1927 DE_ASSERT(block.isArray() || instanceNdx == 0);
1928 return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string());
1929 }
1930
1931 // \note Some implementations don't report block members in the order they are declared.
1932 // For checking whether size has to be adjusted by some top-level array actual size,
1933 // we only need to know a) whether there is a unsized top-level array, and b)
1934 // what is stride of that array.
1935
hasUnsizedArray(const BufferLayout & layout,const BlockLayoutEntry & entry)1936 static bool hasUnsizedArray(const BufferLayout &layout, const BlockLayoutEntry &entry)
1937 {
1938 for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end();
1939 ++varNdx)
1940 {
1941 if (isUnsizedArray(layout.bufferVars[*varNdx]))
1942 return true;
1943 }
1944
1945 return false;
1946 }
1947
getUnsizedArrayStride(const BufferLayout & layout,const BlockLayoutEntry & entry)1948 static int getUnsizedArrayStride(const BufferLayout &layout, const BlockLayoutEntry &entry)
1949 {
1950 for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end();
1951 ++varNdx)
1952 {
1953 const BufferVarLayoutEntry &varEntry = layout.bufferVars[*varNdx];
1954
1955 if (varEntry.arraySize == 0)
1956 return varEntry.arrayStride;
1957 else if (varEntry.topLevelArraySize == 0)
1958 return varEntry.topLevelArrayStride;
1959 }
1960
1961 return 0;
1962 }
1963
computeBufferSizes(const ShaderInterface & interface,const BufferLayout & layout)1964 vector<int> computeBufferSizes(const ShaderInterface &interface, const BufferLayout &layout)
1965 {
1966 vector<int> sizes(layout.blocks.size());
1967
1968 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1969 {
1970 const BufferBlock &block = interface.getBlock(declNdx);
1971 const bool isArray = block.isArray();
1972 const int numInstances = isArray ? block.getArraySize() : 1;
1973
1974 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1975 {
1976 const string apiName = getBlockAPIName(block, instanceNdx);
1977 const int blockNdx = layout.getBlockIndex(apiName);
1978
1979 if (blockNdx >= 0)
1980 {
1981 const BlockLayoutEntry &blockLayout = layout.blocks[blockNdx];
1982 const int baseSize = blockLayout.size;
1983 const bool isLastUnsized = hasUnsizedArray(layout, blockLayout);
1984 const int lastArraySize = isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0;
1985 const int stride = isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0;
1986
1987 sizes[blockNdx] = baseSize + lastArraySize * stride;
1988 }
1989 }
1990 }
1991
1992 return sizes;
1993 }
1994
getBlockDataPtr(const BufferLayout & layout,const BlockLayoutEntry & blockLayout,void * ptr,int bufferSize)1995 BlockDataPtr getBlockDataPtr(const BufferLayout &layout, const BlockLayoutEntry &blockLayout, void *ptr, int bufferSize)
1996 {
1997 const bool isLastUnsized = hasUnsizedArray(layout, blockLayout);
1998 const int baseSize = blockLayout.size;
1999
2000 if (isLastUnsized)
2001 {
2002 const int lastArrayStride = getUnsizedArrayStride(layout, blockLayout);
2003 const int lastArraySize = (bufferSize - baseSize) / (lastArrayStride ? lastArrayStride : 1);
2004
2005 DE_ASSERT(baseSize + lastArraySize * lastArrayStride == bufferSize);
2006
2007 return BlockDataPtr(ptr, bufferSize, lastArraySize);
2008 }
2009 else
2010 return BlockDataPtr(ptr, bufferSize, 0);
2011 }
2012
2013 struct RefDataStorage
2014 {
2015 vector<uint8_t> data;
2016 vector<BlockDataPtr> pointers;
2017 };
2018
2019 struct Buffer
2020 {
2021 uint32_t buffer;
2022 int size;
2023
Bufferdeqp::gles31::bb::__anonc1049a2c0211::Buffer2024 Buffer(uint32_t buffer_, int size_) : buffer(buffer_), size(size_)
2025 {
2026 }
Bufferdeqp::gles31::bb::__anonc1049a2c0211::Buffer2027 Buffer(void) : buffer(0), size(0)
2028 {
2029 }
2030 };
2031
2032 struct BlockLocation
2033 {
2034 int index;
2035 int offset;
2036 int size;
2037
BlockLocationdeqp::gles31::bb::__anonc1049a2c0211::BlockLocation2038 BlockLocation(int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_)
2039 {
2040 }
BlockLocationdeqp::gles31::bb::__anonc1049a2c0211::BlockLocation2041 BlockLocation(void) : index(0), offset(0), size(0)
2042 {
2043 }
2044 };
2045
initRefDataStorage(const ShaderInterface & interface,const BufferLayout & layout,RefDataStorage & storage)2046 void initRefDataStorage(const ShaderInterface &interface, const BufferLayout &layout, RefDataStorage &storage)
2047 {
2048 DE_ASSERT(storage.data.empty() && storage.pointers.empty());
2049
2050 const vector<int> bufferSizes = computeBufferSizes(interface, layout);
2051 int totalSize = 0;
2052
2053 for (vector<int>::const_iterator sizeIter = bufferSizes.begin(); sizeIter != bufferSizes.end(); ++sizeIter)
2054 totalSize += *sizeIter;
2055
2056 storage.data.resize(totalSize);
2057
2058 // Pointers for each block.
2059 {
2060 uint8_t *basePtr = storage.data.empty() ? DE_NULL : &storage.data[0];
2061 int curOffset = 0;
2062
2063 DE_ASSERT(bufferSizes.size() == layout.blocks.size());
2064 DE_ASSERT(totalSize == 0 || basePtr);
2065
2066 storage.pointers.resize(layout.blocks.size());
2067
2068 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
2069 {
2070 const BlockLayoutEntry &blockLayout = layout.blocks[blockNdx];
2071 const int bufferSize = bufferSizes[blockNdx];
2072
2073 storage.pointers[blockNdx] = getBlockDataPtr(layout, blockLayout, basePtr + curOffset, bufferSize);
2074
2075 curOffset += bufferSize;
2076 }
2077 }
2078 }
2079
blockLocationsToPtrs(const BufferLayout & layout,const vector<BlockLocation> & blockLocations,const vector<void * > & bufPtrs)2080 vector<BlockDataPtr> blockLocationsToPtrs(const BufferLayout &layout, const vector<BlockLocation> &blockLocations,
2081 const vector<void *> &bufPtrs)
2082 {
2083 vector<BlockDataPtr> blockPtrs(blockLocations.size());
2084
2085 DE_ASSERT(layout.blocks.size() == blockLocations.size());
2086
2087 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
2088 {
2089 const BlockLayoutEntry &blockLayout = layout.blocks[blockNdx];
2090 const BlockLocation &location = blockLocations[blockNdx];
2091
2092 blockPtrs[blockNdx] =
2093 getBlockDataPtr(layout, blockLayout, (uint8_t *)bufPtrs[location.index] + location.offset, location.size);
2094 }
2095
2096 return blockPtrs;
2097 }
2098
mapBuffers(const glw::Functions & gl,const vector<Buffer> & buffers,uint32_t access)2099 vector<void *> mapBuffers(const glw::Functions &gl, const vector<Buffer> &buffers, uint32_t access)
2100 {
2101 vector<void *> mapPtrs(buffers.size(), DE_NULL);
2102
2103 try
2104 {
2105 for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
2106 {
2107 if (buffers[ndx].size > 0)
2108 {
2109 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2110 mapPtrs[ndx] = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, buffers[ndx].size, access);
2111 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to map buffer");
2112 TCU_CHECK(mapPtrs[ndx]);
2113 }
2114 else
2115 mapPtrs[ndx] = DE_NULL;
2116 }
2117
2118 return mapPtrs;
2119 }
2120 catch (...)
2121 {
2122 for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
2123 {
2124 if (mapPtrs[ndx])
2125 {
2126 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2127 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2128 }
2129 }
2130
2131 throw;
2132 }
2133 }
2134
unmapBuffers(const glw::Functions & gl,const vector<Buffer> & buffers)2135 void unmapBuffers(const glw::Functions &gl, const vector<Buffer> &buffers)
2136 {
2137 for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
2138 {
2139 if (buffers[ndx].size > 0)
2140 {
2141 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2142 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2143 }
2144 }
2145
2146 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unmap buffer");
2147 }
2148
2149 } // namespace
2150
2151 class BufferManager
2152 {
2153 public:
2154 BufferManager(const glu::RenderContext &renderCtx);
2155 ~BufferManager(void);
2156
2157 uint32_t allocBuffer(void);
2158
2159 private:
2160 BufferManager(const BufferManager &other);
2161 BufferManager &operator=(const BufferManager &other);
2162
2163 const glu::RenderContext &m_renderCtx;
2164 std::vector<uint32_t> m_buffers;
2165 };
2166
BufferManager(const glu::RenderContext & renderCtx)2167 BufferManager::BufferManager(const glu::RenderContext &renderCtx) : m_renderCtx(renderCtx)
2168 {
2169 }
2170
~BufferManager(void)2171 BufferManager::~BufferManager(void)
2172 {
2173 if (!m_buffers.empty())
2174 m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
2175 }
2176
allocBuffer(void)2177 uint32_t BufferManager::allocBuffer(void)
2178 {
2179 uint32_t buf = 0;
2180
2181 m_buffers.reserve(m_buffers.size() + 1);
2182 m_renderCtx.getFunctions().genBuffers(1, &buf);
2183 GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate buffer");
2184 m_buffers.push_back(buf);
2185
2186 return buf;
2187 }
2188
2189 } // namespace bb
2190
2191 using namespace bb;
2192
2193 // SSBOLayoutCase.
2194
SSBOLayoutCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,glu::GLSLVersion glslVersion,BufferMode bufferMode)2195 SSBOLayoutCase::SSBOLayoutCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const char *name,
2196 const char *description, glu::GLSLVersion glslVersion, BufferMode bufferMode)
2197 : TestCase(testCtx, name, description)
2198 , m_renderCtx(renderCtx)
2199 , m_glslVersion(glslVersion)
2200 , m_bufferMode(bufferMode)
2201 {
2202 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430);
2203 }
2204
~SSBOLayoutCase(void)2205 SSBOLayoutCase::~SSBOLayoutCase(void)
2206 {
2207 }
2208
iterate(void)2209 SSBOLayoutCase::IterateResult SSBOLayoutCase::iterate(void)
2210 {
2211 TestLog &log = m_testCtx.getLog();
2212 const glw::Functions &gl = m_renderCtx.getFunctions();
2213
2214 BufferLayout refLayout; // std140 / std430 layout.
2215 BufferLayout glLayout; // Layout reported by GL.
2216 RefDataStorage initialData; // Initial data stored in buffer.
2217 RefDataStorage writeData; // Data written by compute shader.
2218
2219 BufferManager bufferManager(m_renderCtx);
2220 vector<Buffer> buffers; // Buffers allocated for storage
2221 vector<BlockLocation> blockLocations; // Block locations in storage (index, offset)
2222
2223 // Initialize result to pass.
2224 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2225
2226 computeReferenceLayout(refLayout, m_interface);
2227 initRefDataStorage(m_interface, refLayout, initialData);
2228 initRefDataStorage(m_interface, refLayout, writeData);
2229 generateValues(refLayout, initialData.pointers, deStringHash(getName()) ^ 0xad2f7214);
2230 generateValues(refLayout, writeData.pointers, deStringHash(getName()) ^ 0x25ca4e7);
2231 copyNonWrittenData(m_interface, refLayout, initialData.pointers, writeData.pointers);
2232
2233 const glu::ShaderProgram program(
2234 m_renderCtx, glu::ProgramSources() << glu::ComputeSource(generateComputeShader(
2235 gl, m_glslVersion, m_interface, refLayout, initialData.pointers, writeData.pointers)));
2236 log << program;
2237
2238 if (!program.isOk())
2239 {
2240 // Compile failed.
2241 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
2242 return STOP;
2243 }
2244
2245 // Query layout from GL.
2246 getGLBufferLayout(gl, glLayout, program.getProgram());
2247
2248 // Print layout to log.
2249 {
2250 tcu::ScopedLogSection section(log, "ActiveBufferBlocks", "Active Buffer Blocks");
2251 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
2252 log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage;
2253 }
2254
2255 {
2256 tcu::ScopedLogSection section(log, "ActiveBufferVars", "Active Buffer Variables");
2257 for (int varNdx = 0; varNdx < (int)glLayout.bufferVars.size(); varNdx++)
2258 log << TestLog::Message << varNdx << ": " << glLayout.bufferVars[varNdx] << TestLog::EndMessage;
2259 }
2260
2261 // Verify layouts.
2262 {
2263 if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout))
2264 {
2265 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout");
2266 return STOP; // It is not safe to use the given layout.
2267 }
2268
2269 if (!compareStdBlocks(refLayout, glLayout))
2270 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 or std430 layout");
2271
2272 if (!compareSharedBlocks(refLayout, glLayout))
2273 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout");
2274
2275 if (!checkIndexQueries(program.getProgram(), glLayout))
2276 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results");
2277 }
2278
2279 // Allocate GL buffers & compute placement.
2280 {
2281 const int numBlocks = (int)glLayout.blocks.size();
2282 const vector<int> bufferSizes = computeBufferSizes(m_interface, glLayout);
2283
2284 DE_ASSERT(bufferSizes.size() == glLayout.blocks.size());
2285
2286 blockLocations.resize(numBlocks);
2287
2288 if (m_bufferMode == BUFFERMODE_PER_BLOCK)
2289 {
2290 buffers.resize(numBlocks);
2291
2292 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2293 {
2294 const int bufferSize = bufferSizes[blockNdx];
2295
2296 buffers[blockNdx].size = bufferSize;
2297 blockLocations[blockNdx] = BlockLocation(blockNdx, 0, bufferSize);
2298 }
2299 }
2300 else
2301 {
2302 DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE);
2303
2304 int bindingAlignment = 0;
2305 int totalSize = 0;
2306
2307 gl.getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &bindingAlignment);
2308
2309 {
2310 int curOffset = 0;
2311 DE_ASSERT(bufferSizes.size() == glLayout.blocks.size());
2312 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2313 {
2314 const int bufferSize = bufferSizes[blockNdx];
2315
2316 if (bindingAlignment > 0)
2317 curOffset = deRoundUp32(curOffset, bindingAlignment);
2318
2319 blockLocations[blockNdx] = BlockLocation(0, curOffset, bufferSize);
2320 curOffset += bufferSize;
2321 }
2322 totalSize = curOffset;
2323 }
2324
2325 buffers.resize(1);
2326 buffers[0].size = totalSize;
2327 }
2328
2329 for (int bufNdx = 0; bufNdx < (int)buffers.size(); bufNdx++)
2330 {
2331 const int bufferSize = buffers[bufNdx].size;
2332 const uint32_t buffer = bufferManager.allocBuffer();
2333
2334 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2335 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_STATIC_DRAW);
2336 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate buffer");
2337
2338 buffers[bufNdx].buffer = buffer;
2339 }
2340 }
2341
2342 {
2343 const vector<void *> mapPtrs = mapBuffers(gl, buffers, GL_MAP_WRITE_BIT);
2344 const vector<BlockDataPtr> mappedBlockPtrs = blockLocationsToPtrs(glLayout, blockLocations, mapPtrs);
2345
2346 copyData(glLayout, mappedBlockPtrs, refLayout, initialData.pointers);
2347
2348 unmapBuffers(gl, buffers);
2349 }
2350
2351 {
2352 int bindingPoint = 0;
2353
2354 for (int blockDeclNdx = 0; blockDeclNdx < m_interface.getNumBlocks(); blockDeclNdx++)
2355 {
2356 const BufferBlock &block = m_interface.getBlock(blockDeclNdx);
2357 const int numInst = block.isArray() ? block.getArraySize() : 1;
2358
2359 for (int instNdx = 0; instNdx < numInst; instNdx++)
2360 {
2361 const string instName = getBlockAPIName(block, instNdx);
2362 const int layoutNdx = findBlockIndex(glLayout, instName);
2363
2364 if (layoutNdx >= 0)
2365 {
2366 const BlockLocation &blockLoc = blockLocations[layoutNdx];
2367
2368 if (blockLoc.size > 0)
2369 gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, bindingPoint, buffers[blockLoc.index].buffer,
2370 blockLoc.offset, blockLoc.size);
2371 }
2372
2373 bindingPoint += 1;
2374 }
2375 }
2376 }
2377
2378 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind buffers");
2379
2380 {
2381 const bool execOk = execute(program.getProgram());
2382
2383 if (execOk)
2384 {
2385 const vector<void *> mapPtrs = mapBuffers(gl, buffers, GL_MAP_READ_BIT);
2386 const vector<BlockDataPtr> mappedBlockPtrs = blockLocationsToPtrs(glLayout, blockLocations, mapPtrs);
2387
2388 const bool compareOk =
2389 compareData(m_testCtx.getLog(), refLayout, writeData.pointers, glLayout, mappedBlockPtrs);
2390
2391 unmapBuffers(gl, buffers);
2392
2393 if (!compareOk)
2394 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
2395 }
2396 else
2397 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader execution failed");
2398 }
2399
2400 return STOP;
2401 }
2402
compareStdBlocks(const BufferLayout & refLayout,const BufferLayout & cmpLayout) const2403 bool SSBOLayoutCase::compareStdBlocks(const BufferLayout &refLayout, const BufferLayout &cmpLayout) const
2404 {
2405 TestLog &log = m_testCtx.getLog();
2406 bool isOk = true;
2407 int numBlocks = m_interface.getNumBlocks();
2408
2409 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2410 {
2411 const BufferBlock &block = m_interface.getBlock(blockNdx);
2412 bool isArray = block.isArray();
2413 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
2414 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str());
2415 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str());
2416
2417 if ((block.getFlags() & (LAYOUT_STD140 | LAYOUT_STD430)) == 0)
2418 continue; // Not std* layout.
2419
2420 DE_ASSERT(refBlockNdx >= 0);
2421
2422 if (cmpBlockNdx < 0)
2423 {
2424 // Not found.
2425 log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage;
2426 isOk = false;
2427 continue;
2428 }
2429
2430 const BlockLayoutEntry &refBlockLayout = refLayout.blocks[refBlockNdx];
2431 const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
2432
2433 // \todo [2012-01-24 pyry] Verify that activeVarIndices is correct.
2434 // \todo [2012-01-24 pyry] Verify all instances.
2435 if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size())
2436 {
2437 log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName
2438 << "' (expected " << refBlockLayout.activeVarIndices.size() << ", got "
2439 << cmpBlockLayout.activeVarIndices.size() << ")" << TestLog::EndMessage;
2440 isOk = false;
2441 }
2442
2443 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin();
2444 ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++)
2445 {
2446 const BufferVarLayoutEntry &refEntry = refLayout.bufferVars[*ndxIter];
2447 int cmpEntryNdx = cmpLayout.getVariableIndex(refEntry.name.c_str());
2448
2449 if (cmpEntryNdx < 0)
2450 {
2451 log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found"
2452 << TestLog::EndMessage;
2453 isOk = false;
2454 continue;
2455 }
2456
2457 const BufferVarLayoutEntry &cmpEntry = cmpLayout.bufferVars[cmpEntryNdx];
2458
2459 if (refEntry.type != cmpEntry.type || refEntry.arraySize != cmpEntry.arraySize ||
2460 refEntry.offset != cmpEntry.offset || refEntry.arrayStride != cmpEntry.arrayStride ||
2461 refEntry.matrixStride != cmpEntry.matrixStride ||
2462 refEntry.topLevelArraySize != cmpEntry.topLevelArraySize ||
2463 refEntry.topLevelArrayStride != cmpEntry.topLevelArrayStride ||
2464 refEntry.isRowMajor != cmpEntry.isRowMajor)
2465 {
2466 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
2467 << " expected: " << refEntry << "\n"
2468 << " got: " << cmpEntry << TestLog::EndMessage;
2469 isOk = false;
2470 }
2471 }
2472 }
2473
2474 return isOk;
2475 }
2476
compareSharedBlocks(const BufferLayout & refLayout,const BufferLayout & cmpLayout) const2477 bool SSBOLayoutCase::compareSharedBlocks(const BufferLayout &refLayout, const BufferLayout &cmpLayout) const
2478 {
2479 TestLog &log = m_testCtx.getLog();
2480 bool isOk = true;
2481 int numBlocks = m_interface.getNumBlocks();
2482
2483 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2484 {
2485 const BufferBlock &block = m_interface.getBlock(blockNdx);
2486 bool isArray = block.isArray();
2487 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
2488 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str());
2489 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str());
2490
2491 if ((block.getFlags() & LAYOUT_SHARED) == 0)
2492 continue; // Not shared layout.
2493
2494 DE_ASSERT(refBlockNdx >= 0);
2495
2496 if (cmpBlockNdx < 0)
2497 {
2498 // Not found, should it?
2499 log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage;
2500 isOk = false;
2501 continue;
2502 }
2503
2504 const BlockLayoutEntry &refBlockLayout = refLayout.blocks[refBlockNdx];
2505 const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
2506
2507 if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size())
2508 {
2509 log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName
2510 << "' (expected " << refBlockLayout.activeVarIndices.size() << ", got "
2511 << cmpBlockLayout.activeVarIndices.size() << ")" << TestLog::EndMessage;
2512 isOk = false;
2513 }
2514
2515 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin();
2516 ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++)
2517 {
2518 const BufferVarLayoutEntry &refEntry = refLayout.bufferVars[*ndxIter];
2519 int cmpEntryNdx = cmpLayout.getVariableIndex(refEntry.name.c_str());
2520
2521 if (cmpEntryNdx < 0)
2522 {
2523 log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found"
2524 << TestLog::EndMessage;
2525 isOk = false;
2526 continue;
2527 }
2528
2529 const BufferVarLayoutEntry &cmpEntry = cmpLayout.bufferVars[cmpEntryNdx];
2530
2531 if (refEntry.type != cmpEntry.type || refEntry.arraySize != cmpEntry.arraySize ||
2532 refEntry.topLevelArraySize != cmpEntry.topLevelArraySize || refEntry.isRowMajor != cmpEntry.isRowMajor)
2533 {
2534 log << TestLog::Message << "Error: Type / array size mismatch in '" << refEntry.name << "':\n"
2535 << " expected: " << refEntry << "\n"
2536 << " got: " << cmpEntry << TestLog::EndMessage;
2537 isOk = false;
2538 }
2539 }
2540 }
2541
2542 return isOk;
2543 }
2544
compareTypes(const BufferLayout & refLayout,const BufferLayout & cmpLayout) const2545 bool SSBOLayoutCase::compareTypes(const BufferLayout &refLayout, const BufferLayout &cmpLayout) const
2546 {
2547 TestLog &log = m_testCtx.getLog();
2548 bool isOk = true;
2549 int numBlocks = m_interface.getNumBlocks();
2550
2551 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2552 {
2553 const BufferBlock &block = m_interface.getBlock(blockNdx);
2554 bool isArray = block.isArray();
2555 int numInstances = isArray ? block.getArraySize() : 1;
2556
2557 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
2558 {
2559 std::ostringstream instanceName;
2560
2561 instanceName << block.getBlockName();
2562 if (isArray)
2563 instanceName << "[" << instanceNdx << "]";
2564
2565 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str());
2566
2567 if (cmpBlockNdx < 0)
2568 continue;
2569
2570 const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
2571
2572 for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeVarIndices.begin();
2573 ndxIter != cmpBlockLayout.activeVarIndices.end(); ndxIter++)
2574 {
2575 const BufferVarLayoutEntry &cmpEntry = cmpLayout.bufferVars[*ndxIter];
2576 int refEntryNdx = refLayout.getVariableIndex(cmpEntry.name.c_str());
2577
2578 if (refEntryNdx < 0)
2579 {
2580 log << TestLog::Message << "Error: Buffer variable '" << cmpEntry.name
2581 << "' not found in reference layout" << TestLog::EndMessage;
2582 isOk = false;
2583 continue;
2584 }
2585
2586 const BufferVarLayoutEntry &refEntry = refLayout.bufferVars[refEntryNdx];
2587
2588 if (refEntry.type != cmpEntry.type)
2589 {
2590 log << TestLog::Message << "Error: Buffer variable type mismatch in '" << refEntry.name << "':\n"
2591 << " expected: " << glu::getDataTypeName(refEntry.type) << "\n"
2592 << " got: " << glu::getDataTypeName(cmpEntry.type) << TestLog::EndMessage;
2593 isOk = false;
2594 }
2595
2596 if (refEntry.arraySize < cmpEntry.arraySize)
2597 {
2598 log << TestLog::Message << "Error: Invalid array size in '" << refEntry.name
2599 << "': expected <= " << refEntry.arraySize << TestLog::EndMessage;
2600 isOk = false;
2601 }
2602
2603 if (refEntry.topLevelArraySize < cmpEntry.topLevelArraySize)
2604 {
2605 log << TestLog::Message << "Error: Invalid top-level array size in '" << refEntry.name
2606 << "': expected <= " << refEntry.topLevelArraySize << TestLog::EndMessage;
2607 isOk = false;
2608 }
2609 }
2610 }
2611 }
2612
2613 return isOk;
2614 }
2615
checkLayoutIndices(const BufferLayout & layout) const2616 bool SSBOLayoutCase::checkLayoutIndices(const BufferLayout &layout) const
2617 {
2618 TestLog &log = m_testCtx.getLog();
2619 int numVars = (int)layout.bufferVars.size();
2620 int numBlocks = (int)layout.blocks.size();
2621 bool isOk = true;
2622
2623 // Check variable block indices.
2624 for (int varNdx = 0; varNdx < numVars; varNdx++)
2625 {
2626 const BufferVarLayoutEntry &bufVar = layout.bufferVars[varNdx];
2627
2628 if (bufVar.blockNdx < 0 || !deInBounds32(bufVar.blockNdx, 0, numBlocks))
2629 {
2630 log << TestLog::Message << "Error: Invalid block index in buffer variable '" << bufVar.name << "'"
2631 << TestLog::EndMessage;
2632 isOk = false;
2633 }
2634 }
2635
2636 // Check active variables.
2637 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2638 {
2639 const BlockLayoutEntry &block = layout.blocks[blockNdx];
2640
2641 for (vector<int>::const_iterator varNdxIter = block.activeVarIndices.begin();
2642 varNdxIter != block.activeVarIndices.end(); varNdxIter++)
2643 {
2644 if (!deInBounds32(*varNdxIter, 0, numVars))
2645 {
2646 log << TestLog::Message << "Error: Invalid active variable index " << *varNdxIter << " in block '"
2647 << block.name << "'" << TestLog::EndMessage;
2648 isOk = false;
2649 }
2650 }
2651 }
2652
2653 return isOk;
2654 }
2655
checkLayoutBounds(const BufferLayout & layout) const2656 bool SSBOLayoutCase::checkLayoutBounds(const BufferLayout &layout) const
2657 {
2658 TestLog &log = m_testCtx.getLog();
2659 const int numVars = (int)layout.bufferVars.size();
2660 bool isOk = true;
2661
2662 for (int varNdx = 0; varNdx < numVars; varNdx++)
2663 {
2664 const BufferVarLayoutEntry &var = layout.bufferVars[varNdx];
2665
2666 if (var.blockNdx < 0 || isUnsizedArray(var))
2667 continue;
2668
2669 const BlockLayoutEntry &block = layout.blocks[var.blockNdx];
2670 const bool isMatrix = glu::isDataTypeMatrix(var.type);
2671 const int numVecs = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumRows(var.type) :
2672 glu::getDataTypeMatrixNumColumns(var.type)) :
2673 1;
2674 const int numComps = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumColumns(var.type) :
2675 glu::getDataTypeMatrixNumRows(var.type)) :
2676 glu::getDataTypeScalarSize(var.type);
2677 const int numElements = var.arraySize;
2678 const int topLevelSize = var.topLevelArraySize;
2679 const int arrayStride = var.arrayStride;
2680 const int topLevelStride = var.topLevelArrayStride;
2681 const int compSize = sizeof(uint32_t);
2682 const int vecSize = numComps * compSize;
2683
2684 int minOffset = 0;
2685 int maxOffset = 0;
2686
2687 // For negative strides.
2688 minOffset = de::min(minOffset, (numVecs - 1) * var.matrixStride);
2689 minOffset = de::min(minOffset, (numElements - 1) * arrayStride);
2690 minOffset = de::min(minOffset, (topLevelSize - 1) * topLevelStride + (numElements - 1) * arrayStride +
2691 (numVecs - 1) * var.matrixStride);
2692
2693 maxOffset = de::max(maxOffset, vecSize);
2694 maxOffset = de::max(maxOffset, (numVecs - 1) * var.matrixStride + vecSize);
2695 maxOffset = de::max(maxOffset, (numElements - 1) * arrayStride + vecSize);
2696 maxOffset = de::max(maxOffset, (topLevelSize - 1) * topLevelStride + (numElements - 1) * arrayStride + vecSize);
2697 maxOffset = de::max(maxOffset, (topLevelSize - 1) * topLevelStride + (numElements - 1) * arrayStride +
2698 (numVecs - 1) * var.matrixStride + vecSize);
2699
2700 if (var.offset + minOffset < 0 || var.offset + maxOffset > block.size)
2701 {
2702 log << TestLog::Message << "Error: Variable '" << var.name << "' out of block bounds"
2703 << TestLog::EndMessage;
2704 isOk = false;
2705 }
2706 }
2707
2708 return isOk;
2709 }
2710
checkIndexQueries(uint32_t program,const BufferLayout & layout) const2711 bool SSBOLayoutCase::checkIndexQueries(uint32_t program, const BufferLayout &layout) const
2712 {
2713 tcu::TestLog &log = m_testCtx.getLog();
2714 const glw::Functions &gl = m_renderCtx.getFunctions();
2715 bool allOk = true;
2716
2717 // \note Spec mandates that buffer blocks are assigned consecutive locations from 0.
2718 // BlockLayoutEntries are stored in that order in UniformLayout.
2719 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
2720 {
2721 const BlockLayoutEntry &block = layout.blocks[blockNdx];
2722 const int queriedNdx = gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, block.name.c_str());
2723
2724 if (queriedNdx != blockNdx)
2725 {
2726 log << TestLog::Message << "ERROR: glGetProgramResourceIndex(" << block.name << ") returned " << queriedNdx
2727 << ", expected " << blockNdx << "!" << TestLog::EndMessage;
2728 allOk = false;
2729 }
2730
2731 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()");
2732 }
2733
2734 return allOk;
2735 }
2736
execute(uint32_t program)2737 bool SSBOLayoutCase::execute(uint32_t program)
2738 {
2739 const glw::Functions &gl = m_renderCtx.getFunctions();
2740 const uint32_t numPassedLoc = gl.getProgramResourceIndex(program, GL_UNIFORM, "ac_numPassed");
2741 const glu::InterfaceVariableInfo acVarInfo =
2742 numPassedLoc != GL_INVALID_INDEX ? glu::getProgramInterfaceVariableInfo(gl, program, GL_UNIFORM, numPassedLoc) :
2743 glu::InterfaceVariableInfo();
2744 const glu::InterfaceBlockInfo acBufferInfo =
2745 acVarInfo.atomicCounterBufferIndex != GL_INVALID_INDEX ?
2746 glu::getProgramInterfaceBlockInfo(gl, program, GL_ATOMIC_COUNTER_BUFFER,
2747 acVarInfo.atomicCounterBufferIndex) :
2748 glu::InterfaceBlockInfo();
2749 const glu::Buffer acBuffer(m_renderCtx);
2750 bool isOk = true;
2751
2752 if (numPassedLoc == GL_INVALID_INDEX)
2753 throw tcu::TestError("No location for ac_numPassed found");
2754
2755 if (acBufferInfo.index == GL_INVALID_INDEX)
2756 throw tcu::TestError("ac_numPassed buffer index is GL_INVALID_INDEX");
2757
2758 if (acBufferInfo.dataSize == 0)
2759 throw tcu::TestError("ac_numPassed buffer size = 0");
2760
2761 // Initialize atomic counter buffer.
2762 {
2763 vector<uint8_t> emptyData(acBufferInfo.dataSize, 0);
2764
2765 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *acBuffer);
2766 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_READ);
2767 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, acBufferInfo.index, *acBuffer);
2768 GLU_EXPECT_NO_ERROR(gl.getError(), "Setting up buffer for ac_numPassed failed");
2769 }
2770
2771 gl.useProgram(program);
2772 gl.dispatchCompute(1, 1, 1);
2773 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() failed");
2774
2775 // Read back ac_numPassed data.
2776 {
2777 const void *mapPtr = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, acBufferInfo.dataSize, GL_MAP_READ_BIT);
2778 const int refCount = 1;
2779 int resCount = 0;
2780
2781 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER) failed");
2782 TCU_CHECK(mapPtr);
2783
2784 resCount = *(const int *)((const uint8_t *)mapPtr + acVarInfo.offset);
2785
2786 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2787 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER) failed");
2788
2789 if (refCount != resCount)
2790 {
2791 m_testCtx.getLog() << TestLog::Message << "ERROR: ac_numPassed = " << resCount << ", expected " << refCount
2792 << TestLog::EndMessage;
2793 isOk = false;
2794 }
2795 }
2796
2797 GLU_EXPECT_NO_ERROR(gl.getError(), "Shader execution failed");
2798
2799 return isOk;
2800 }
2801
2802 } // namespace gles31
2803 } // namespace deqp
2804