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