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