1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */ /*!
21 * \file
22 * \brief Uniform block case.
23 */ /*-------------------------------------------------------------------*/
24
25 #include "glcUniformBlockCase.hpp"
26 #include "deInt32.h"
27 #include "deMemory.h"
28 #include "deRandom.hpp"
29 #include "deString.h"
30 #include "deStringUtil.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDrawUtil.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluRenderContext.hpp"
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
37 #include "tcuRenderTarget.hpp"
38 #include "tcuSurface.hpp"
39 #include "tcuTestLog.hpp"
40
41 #include <algorithm>
42 #include <map>
43
44 using std::map;
45 using std::string;
46 using std::vector;
47 using tcu::TestLog;
48
49 namespace deqp
50 {
51 namespace ub
52 {
53
54 struct PrecisionFlagsFmt
55 {
56 uint32_t flags;
57
PrecisionFlagsFmtdeqp::ub::PrecisionFlagsFmt58 PrecisionFlagsFmt(uint32_t flags_) : flags(flags_)
59 {
60 }
61 };
62
operator <<(std::ostream & str,const PrecisionFlagsFmt & fmt)63 std::ostream &operator<<(std::ostream &str, const PrecisionFlagsFmt &fmt)
64 {
65 // Precision.
66 DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW | PRECISION_MEDIUM | PRECISION_HIGH)) <= 1);
67 str << (fmt.flags & PRECISION_LOW ? "lowp" :
68 fmt.flags & PRECISION_MEDIUM ? "mediump" :
69 fmt.flags & PRECISION_HIGH ? "highp" :
70 "");
71 return str;
72 }
73
74 struct LayoutFlagsFmt
75 {
76 uint32_t flags;
LayoutFlagsFmtdeqp::ub::LayoutFlagsFmt77 LayoutFlagsFmt(uint32_t flags_) : flags(flags_)
78 {
79 }
80 };
81
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)82 std::ostream &operator<<(std::ostream &str, const LayoutFlagsFmt &fmt)
83 {
84 static const struct
85 {
86 uint32_t bit;
87 const char *token;
88 } bitDesc[] = {{LAYOUT_SHARED, "shared"},
89 {LAYOUT_PACKED, "packed"},
90 {LAYOUT_STD140, "std140"},
91 {LAYOUT_ROW_MAJOR, "row_major"},
92 {LAYOUT_COLUMN_MAJOR, "column_major"}};
93
94 uint32_t remBits = fmt.flags;
95 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
96 {
97 if (remBits & bitDesc[descNdx].bit)
98 {
99 if (remBits != fmt.flags)
100 str << ", ";
101 str << bitDesc[descNdx].token;
102 remBits &= ~bitDesc[descNdx].bit;
103 }
104 }
105 DE_ASSERT(remBits == 0);
106 return str;
107 }
108
109 // VarType implementation.
110
VarType(void)111 VarType::VarType(void) : m_type(TYPE_LAST), m_flags(0)
112 {
113 }
114
VarType(const VarType & other)115 VarType::VarType(const VarType &other) : m_type(TYPE_LAST), m_flags(0)
116 {
117 *this = other;
118 }
119
VarType(glu::DataType basicType,uint32_t flags)120 VarType::VarType(glu::DataType basicType, uint32_t flags) : m_type(TYPE_BASIC), m_flags(flags)
121 {
122 m_data.basicType = basicType;
123 }
124
VarType(const VarType & elementType,int arraySize)125 VarType::VarType(const VarType &elementType, int arraySize) : m_type(TYPE_ARRAY), m_flags(0)
126 {
127 m_data.array.size = arraySize;
128 m_data.array.elementType = new VarType(elementType);
129 }
130
VarType(const StructType * structPtr)131 VarType::VarType(const StructType *structPtr) : m_type(TYPE_STRUCT), m_flags(0)
132 {
133 m_data.structPtr = structPtr;
134 }
135
~VarType(void)136 VarType::~VarType(void)
137 {
138 if (m_type == TYPE_ARRAY)
139 delete m_data.array.elementType;
140 }
141
operator =(const VarType & other)142 VarType &VarType::operator=(const VarType &other)
143 {
144 if (this == &other)
145 return *this; // Self-assignment.
146
147 if (m_type == TYPE_ARRAY)
148 delete m_data.array.elementType;
149
150 m_type = other.m_type;
151 m_flags = other.m_flags;
152 m_data = Data();
153
154 if (m_type == TYPE_ARRAY)
155 {
156 m_data.array.elementType = new VarType(*other.m_data.array.elementType);
157 m_data.array.size = other.m_data.array.size;
158 }
159 else
160 m_data = other.m_data;
161
162 return *this;
163 }
164
165 // StructType implementation.
166
addMember(const char * name,const VarType & type,uint32_t flags)167 void StructType::addMember(const char *name, const VarType &type, uint32_t flags)
168 {
169 m_members.push_back(StructMember(name, type, flags));
170 }
171
172 // Uniform implementation.
173
Uniform(const char * name,const VarType & type,uint32_t flags)174 Uniform::Uniform(const char *name, const VarType &type, uint32_t flags) : m_name(name), m_type(type), m_flags(flags)
175 {
176 }
177
178 // UniformBlock implementation.
179
UniformBlock(const char * blockName)180 UniformBlock::UniformBlock(const char *blockName) : m_blockName(blockName), m_arraySize(0), m_flags(0)
181 {
182 }
183
184 struct BlockLayoutEntry
185 {
BlockLayoutEntrydeqp::ub::BlockLayoutEntry186 BlockLayoutEntry(void) : size(0)
187 {
188 }
189
190 std::string name;
191 int size;
192 std::vector<int> activeUniformIndices;
193 };
194
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)195 std::ostream &operator<<(std::ostream &stream, const BlockLayoutEntry &entry)
196 {
197 stream << entry.name << " { name = " << entry.name << ", size = " << entry.size << ", activeUniformIndices = [";
198
199 for (vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++)
200 {
201 if (i != entry.activeUniformIndices.begin())
202 stream << ", ";
203 stream << *i;
204 }
205
206 stream << "] }";
207 return stream;
208 }
209
210 struct UniformLayoutEntry
211 {
UniformLayoutEntrydeqp::ub::UniformLayoutEntry212 UniformLayoutEntry(void)
213 : type(glu::TYPE_LAST)
214 , size(0)
215 , blockNdx(-1)
216 , offset(-1)
217 , arrayStride(-1)
218 , matrixStride(-1)
219 , isRowMajor(false)
220 {
221 }
222
223 std::string name;
224 glu::DataType type;
225 int size;
226 int blockNdx;
227 int offset;
228 int arrayStride;
229 int matrixStride;
230 bool isRowMajor;
231 };
232
operator <<(std::ostream & stream,const UniformLayoutEntry & entry)233 std::ostream &operator<<(std::ostream &stream, const UniformLayoutEntry &entry)
234 {
235 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) << ", size = " << entry.size
236 << ", blockNdx = " << entry.blockNdx << ", offset = " << entry.offset
237 << ", arrayStride = " << entry.arrayStride << ", matrixStride = " << entry.matrixStride
238 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") << " }";
239 return stream;
240 }
241
242 class UniformLayout
243 {
244 public:
245 std::vector<BlockLayoutEntry> blocks;
246 std::vector<UniformLayoutEntry> uniforms;
247
248 int getUniformIndex(const char *name) const;
249 int getBlockIndex(const char *name) const;
250 };
251
252 // \todo [2012-01-24 pyry] Speed up lookups using hash.
253
getUniformIndex(const char * name) const254 int UniformLayout::getUniformIndex(const char *name) const
255 {
256 for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
257 {
258 if (uniforms[ndx].name == name)
259 return ndx;
260 }
261 return -1;
262 }
263
getBlockIndex(const char * name) const264 int UniformLayout::getBlockIndex(const char *name) const
265 {
266 for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
267 {
268 if (blocks[ndx].name == name)
269 return ndx;
270 }
271 return -1;
272 }
273
274 // ShaderInterface implementation.
275
ShaderInterface(void)276 ShaderInterface::ShaderInterface(void)
277 {
278 }
279
~ShaderInterface(void)280 ShaderInterface::~ShaderInterface(void)
281 {
282 for (std::vector<StructType *>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
283 delete *i;
284
285 for (std::vector<UniformBlock *>::iterator i = m_uniformBlocks.begin(); i != m_uniformBlocks.end(); i++)
286 delete *i;
287 }
288
allocStruct(const char * name)289 StructType &ShaderInterface::allocStruct(const char *name)
290 {
291 m_structs.reserve(m_structs.size() + 1);
292 m_structs.push_back(new StructType(name));
293 return *m_structs.back();
294 }
295
296 struct StructNameEquals
297 {
298 std::string name;
299
StructNameEqualsdeqp::ub::StructNameEquals300 StructNameEquals(const char *name_) : name(name_)
301 {
302 }
303
operator ()deqp::ub::StructNameEquals304 bool operator()(const StructType *type) const
305 {
306 return type->getTypeName() && name == type->getTypeName();
307 }
308 };
309
findStruct(const char * name) const310 const StructType *ShaderInterface::findStruct(const char *name) const
311 {
312 std::vector<StructType *>::const_iterator pos =
313 std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
314 return pos != m_structs.end() ? *pos : DE_NULL;
315 }
316
getNamedStructs(std::vector<const StructType * > & structs) const317 void ShaderInterface::getNamedStructs(std::vector<const StructType *> &structs) const
318 {
319 for (std::vector<StructType *>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
320 {
321 if ((*i)->getTypeName() != DE_NULL)
322 structs.push_back(*i);
323 }
324 }
325
allocBlock(const char * name)326 UniformBlock &ShaderInterface::allocBlock(const char *name)
327 {
328 m_uniformBlocks.reserve(m_uniformBlocks.size() + 1);
329 m_uniformBlocks.push_back(new UniformBlock(name));
330 return *m_uniformBlocks.back();
331 }
332
333 namespace // Utilities
334 {
335
336 // Layout computation.
337
getDataTypeByteSize(glu::DataType type)338 int getDataTypeByteSize(glu::DataType type)
339 {
340 return static_cast<int>(glu::getDataTypeScalarSize(type) * sizeof(uint32_t));
341 }
342
getDataTypeByteAlignment(glu::DataType type)343 int getDataTypeByteAlignment(glu::DataType type)
344 {
345 switch (type)
346 {
347 case glu::TYPE_FLOAT:
348 case glu::TYPE_INT:
349 case glu::TYPE_UINT:
350 case glu::TYPE_BOOL:
351 return static_cast<int>(1 * sizeof(uint32_t));
352
353 case glu::TYPE_FLOAT_VEC2:
354 case glu::TYPE_INT_VEC2:
355 case glu::TYPE_UINT_VEC2:
356 case glu::TYPE_BOOL_VEC2:
357 return static_cast<int>(2 * sizeof(uint32_t));
358
359 case glu::TYPE_FLOAT_VEC3:
360 case glu::TYPE_INT_VEC3:
361 case glu::TYPE_UINT_VEC3:
362 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4
363
364 case glu::TYPE_FLOAT_VEC4:
365 case glu::TYPE_INT_VEC4:
366 case glu::TYPE_UINT_VEC4:
367 case glu::TYPE_BOOL_VEC4:
368 return static_cast<int>(4 * sizeof(uint32_t));
369
370 default:
371 DE_ASSERT(false);
372 return 0;
373 }
374 }
375
getDataTypeArrayStride(glu::DataType type)376 int getDataTypeArrayStride(glu::DataType type)
377 {
378 DE_ASSERT(!glu::isDataTypeMatrix(type));
379
380 int baseStride = getDataTypeByteSize(type);
381 int vec4Alignment = static_cast<int>(sizeof(uint32_t) * 4);
382
383 DE_ASSERT(baseStride <= vec4Alignment);
384 return de::max(baseStride, vec4Alignment); // Really? See rule 4.
385 }
386
computeStd140BaseAlignment(const VarType & type)387 int computeStd140BaseAlignment(const VarType &type)
388 {
389 const int vec4Alignment = static_cast<int>(sizeof(uint32_t) * 4);
390
391 if (type.isBasicType())
392 {
393 glu::DataType basicType = type.getBasicType();
394
395 if (glu::isDataTypeMatrix(basicType))
396 {
397 bool isRowMajor = !!(type.getFlags() & LAYOUT_ROW_MAJOR);
398 int vecSize =
399 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
400
401 return getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
402 }
403 else
404 return getDataTypeByteAlignment(basicType);
405 }
406 else if (type.isArrayType())
407 {
408 int elemAlignment = computeStd140BaseAlignment(type.getElementType());
409
410 // Round up to alignment of vec4
411 return deRoundUp32(elemAlignment, vec4Alignment);
412 }
413 else
414 {
415 DE_ASSERT(type.isStructType());
416
417 int maxBaseAlignment = 0;
418
419 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
420 memberIter++)
421 maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType()));
422
423 return deRoundUp32(maxBaseAlignment, vec4Alignment);
424 }
425 }
426
mergeLayoutFlags(uint32_t prevFlags,uint32_t newFlags)427 inline uint32_t mergeLayoutFlags(uint32_t prevFlags, uint32_t newFlags)
428 {
429 const uint32_t packingMask = LAYOUT_PACKED | LAYOUT_SHARED | LAYOUT_STD140;
430 const uint32_t matrixMask = LAYOUT_ROW_MAJOR | LAYOUT_COLUMN_MAJOR;
431
432 uint32_t mergedFlags = 0;
433
434 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
435 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
436
437 return mergedFlags;
438 }
439
computeStd140Layout(UniformLayout & layout,int & curOffset,int curBlockNdx,const std::string & curPrefix,const VarType & type,uint32_t layoutFlags)440 void computeStd140Layout(UniformLayout &layout, int &curOffset, int curBlockNdx, const std::string &curPrefix,
441 const VarType &type, uint32_t layoutFlags)
442 {
443 int baseAlignment = computeStd140BaseAlignment(type);
444
445 curOffset = deAlign32(curOffset, baseAlignment);
446
447 if (type.isBasicType())
448 {
449 glu::DataType basicType = type.getBasicType();
450 UniformLayoutEntry entry;
451
452 entry.name = curPrefix;
453 entry.type = basicType;
454 entry.size = 1;
455 entry.arrayStride = 0;
456 entry.matrixStride = 0;
457 entry.blockNdx = curBlockNdx;
458
459 if (glu::isDataTypeMatrix(basicType))
460 {
461 // Array of vectors as specified in rules 5 & 7.
462 bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
463 int vecSize =
464 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
465 int numVecs =
466 isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) : glu::getDataTypeMatrixNumColumns(basicType);
467 int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
468
469 entry.offset = curOffset;
470 entry.matrixStride = stride;
471 entry.isRowMajor = isRowMajor;
472
473 curOffset += numVecs * stride;
474 }
475 else
476 {
477 // Scalar or vector.
478 entry.offset = curOffset;
479
480 curOffset += getDataTypeByteSize(basicType);
481 }
482
483 layout.uniforms.push_back(entry);
484 }
485 else if (type.isArrayType())
486 {
487 const VarType &elemType = type.getElementType();
488
489 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
490 {
491 // Array of scalars or vectors.
492 glu::DataType elemBasicType = elemType.getBasicType();
493 UniformLayoutEntry entry;
494 int stride = getDataTypeArrayStride(elemBasicType);
495
496 entry.name = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
497 entry.type = elemBasicType;
498 entry.blockNdx = curBlockNdx;
499 entry.offset = curOffset;
500 entry.size = type.getArraySize();
501 entry.arrayStride = stride;
502 entry.matrixStride = 0;
503
504 curOffset += stride * type.getArraySize();
505
506 layout.uniforms.push_back(entry);
507 }
508 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
509 {
510 // Array of matrices.
511 glu::DataType elemBasicType = elemType.getBasicType();
512 bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
513 int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) :
514 glu::getDataTypeMatrixNumRows(elemBasicType);
515 int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) :
516 glu::getDataTypeMatrixNumColumns(elemBasicType);
517 int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
518 UniformLayoutEntry entry;
519
520 entry.name = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
521 entry.type = elemBasicType;
522 entry.blockNdx = curBlockNdx;
523 entry.offset = curOffset;
524 entry.size = type.getArraySize();
525 entry.arrayStride = stride * numVecs;
526 entry.matrixStride = stride;
527 entry.isRowMajor = isRowMajor;
528
529 curOffset += numVecs * type.getArraySize() * stride;
530
531 layout.uniforms.push_back(entry);
532 }
533 else
534 {
535 DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
536
537 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
538 computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "[" + de::toString(elemNdx) + "]",
539 type.getElementType(), layoutFlags);
540 }
541 }
542 else
543 {
544 DE_ASSERT(type.isStructType());
545
546 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
547 memberIter++)
548 computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "." + memberIter->getName(),
549 memberIter->getType(), layoutFlags);
550
551 curOffset = deAlign32(curOffset, baseAlignment);
552 }
553 }
554
computeStd140Layout(UniformLayout & layout,const ShaderInterface & interface)555 void computeStd140Layout(UniformLayout &layout, const ShaderInterface &interface)
556 {
557 // \todo [2012-01-23 pyry] Uniforms in default block.
558
559 int numUniformBlocks = interface.getNumUniformBlocks();
560
561 for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
562 {
563 const UniformBlock &block = interface.getUniformBlock(blockNdx);
564 bool hasInstanceName = block.getInstanceName() != DE_NULL;
565 std::string blockPrefix = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
566 int curOffset = 0;
567 int activeBlockNdx = (int)layout.blocks.size();
568 int firstUniformNdx = (int)layout.uniforms.size();
569
570 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
571 {
572 const Uniform &uniform = *uniformIter;
573 computeStd140Layout(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(),
574 mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
575 }
576
577 int uniformIndicesEnd = (int)layout.uniforms.size();
578 int blockSize = curOffset;
579 int numInstances = block.isArray() ? block.getArraySize() : 1;
580
581 // Create block layout entries for each instance.
582 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
583 {
584 // Allocate entry for instance.
585 layout.blocks.push_back(BlockLayoutEntry());
586 BlockLayoutEntry &blockEntry = layout.blocks.back();
587
588 blockEntry.name = block.getBlockName();
589 blockEntry.size = blockSize;
590
591 // Compute active uniform set for block.
592 for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
593 blockEntry.activeUniformIndices.push_back(uniformNdx);
594
595 if (block.isArray())
596 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
597 }
598 }
599 }
600
601 // Value generator.
602
generateValue(const UniformLayoutEntry & entry,void * basePtr,de::Random & rnd)603 void generateValue(const UniformLayoutEntry &entry, void *basePtr, de::Random &rnd)
604 {
605 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
606 int scalarSize = glu::getDataTypeScalarSize(entry.type);
607 bool isMatrix = glu::isDataTypeMatrix(entry.type);
608 int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) :
609 glu::getDataTypeMatrixNumColumns(entry.type)) :
610 1;
611 int vecSize = scalarSize / numVecs;
612 bool isArray = entry.size > 1;
613 const int compSize = sizeof(uint32_t);
614
615 DE_ASSERT(scalarSize % numVecs == 0);
616
617 for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
618 {
619 uint8_t *elemPtr = (uint8_t *)basePtr + entry.offset + (isArray ? elemNdx * entry.arrayStride : 0);
620
621 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
622 {
623 uint8_t *vecPtr = elemPtr + (isMatrix ? vecNdx * entry.matrixStride : 0);
624
625 for (int compNdx = 0; compNdx < vecSize; compNdx++)
626 {
627 uint8_t *compPtr = vecPtr + compSize * compNdx;
628
629 switch (scalarType)
630 {
631 case glu::TYPE_FLOAT:
632 *((float *)compPtr) = (float)rnd.getInt(-9, 9);
633 break;
634 case glu::TYPE_INT:
635 *((int *)compPtr) = rnd.getInt(-9, 9);
636 break;
637 case glu::TYPE_UINT:
638 *((uint32_t *)compPtr) = (uint32_t)rnd.getInt(0, 9);
639 break;
640 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
641 // interpreted as true but some implementations fail this.
642 case glu::TYPE_BOOL:
643 *((uint32_t *)compPtr) = rnd.getBool() ? rnd.getUint32() | 1u : 0u;
644 break;
645 default:
646 DE_ASSERT(false);
647 }
648 }
649 }
650 }
651 }
652
generateValues(const UniformLayout & layout,const std::map<int,void * > & blockPointers,uint32_t seed)653 void generateValues(const UniformLayout &layout, const std::map<int, void *> &blockPointers, uint32_t seed)
654 {
655 de::Random rnd(seed);
656 int numBlocks = (int)layout.blocks.size();
657
658 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
659 {
660 void *basePtr = blockPointers.find(blockNdx)->second;
661 int numEntries = (int)layout.blocks[blockNdx].activeUniformIndices.size();
662
663 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
664 {
665 const UniformLayoutEntry &entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
666 generateValue(entry, basePtr, rnd);
667 }
668 }
669 }
670
671 // Shader generator.
672
673 static const char *s_compareFuncs =
674 "mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n"
675 "mediump float compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, "
676 "b.x)*compare_float(a.y, b.y); }\n"
677 "mediump float compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, "
678 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n"
679 "mediump float compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, "
680 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n"
681 "mediump float compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], "
682 "b[0])*compare_vec2(a[1], b[1]); }\n"
683 "mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], "
684 "b[0])*compare_vec3(a[1], b[1]); }\n"
685 "mediump float compare_mat2x4 (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], "
686 "b[0])*compare_vec4(a[1], b[1]); }\n"
687 "mediump float compare_mat3x2 (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], "
688 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n"
689 "mediump float compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], "
690 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n"
691 "mediump float compare_mat3x4 (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], "
692 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n"
693 "mediump float compare_mat4x2 (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], "
694 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n"
695 "mediump float compare_mat4x3 (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], "
696 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n"
697 "mediump float compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], "
698 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n"
699 "mediump float compare_int (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n"
700 "mediump float compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n"
701 "mediump float compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n"
702 "mediump float compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n"
703 "mediump float compare_uint (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n"
704 "mediump float compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n"
705 "mediump float compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n"
706 "mediump float compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n"
707 "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }\n"
708 "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }\n"
709 "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }\n"
710 "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }\n";
711
712 struct Indent
713 {
714 int level;
715
Indentdeqp::ub::__anon657cb1de0211::Indent716 Indent(int level_) : level(level_)
717 {
718 }
719 };
720
operator <<(std::ostream & str,const Indent & indent)721 std::ostream &operator<<(std::ostream &str, const Indent &indent)
722 {
723 for (int i = 0; i < indent.level; i++)
724 str << "\t";
725 return str;
726 }
727
728 void generateDeclaration(std::ostringstream &src, const VarType &type, const char *name, int indentLevel,
729 uint32_t unusedHints);
730 void generateDeclaration(std::ostringstream &src, const Uniform &uniform, int indentLevel);
731 void generateDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
732
733 void generateLocalDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
734 void generateFullDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
735
generateDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)736 void generateDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
737 {
738 DE_ASSERT(structType.getTypeName() != DE_NULL);
739 generateFullDeclaration(src, structType, indentLevel);
740 src << ";\n";
741 }
742
generateFullDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)743 void generateFullDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
744 {
745 src << "struct";
746 if (structType.getTypeName())
747 src << " " << structType.getTypeName();
748 src << "\n" << Indent(indentLevel) << "{\n";
749
750 for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
751 {
752 src << Indent(indentLevel + 1);
753 generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1,
754 memberIter->getFlags() & UNUSED_BOTH);
755 }
756
757 src << Indent(indentLevel) << "}";
758 }
759
generateLocalDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)760 void generateLocalDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
761 {
762 if (structType.getTypeName() == DE_NULL)
763 generateFullDeclaration(src, structType, indentLevel);
764 else
765 src << structType.getTypeName();
766 }
767
generateDeclaration(std::ostringstream & src,const VarType & type,const char * name,int indentLevel,uint32_t unusedHints)768 void generateDeclaration(std::ostringstream &src, const VarType &type, const char *name, int indentLevel,
769 uint32_t unusedHints)
770 {
771 uint32_t flags = type.getFlags();
772
773 if ((flags & LAYOUT_MASK) != 0)
774 src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK) << ") ";
775
776 if ((flags & PRECISION_MASK) != 0)
777 src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
778
779 if (type.isBasicType())
780 src << glu::getDataTypeName(type.getBasicType()) << " " << name;
781 else if (type.isArrayType())
782 {
783 std::vector<int> arraySizes;
784 const VarType *curType = &type;
785 while (curType->isArrayType())
786 {
787 arraySizes.push_back(curType->getArraySize());
788 curType = &curType->getElementType();
789 }
790
791 if (curType->isBasicType())
792 {
793 if ((curType->getFlags() & PRECISION_MASK) != 0)
794 src << PrecisionFlagsFmt(curType->getFlags() & PRECISION_MASK) << " ";
795 src << glu::getDataTypeName(curType->getBasicType());
796 }
797 else
798 {
799 DE_ASSERT(curType->isStructType());
800 generateLocalDeclaration(src, curType->getStruct(), indentLevel + 1);
801 }
802
803 src << " " << name;
804
805 for (std::vector<int>::const_reverse_iterator sizeIter = arraySizes.rbegin(); sizeIter != arraySizes.rend();
806 sizeIter++)
807 src << "[" << *sizeIter << "]";
808 }
809 else
810 {
811 generateLocalDeclaration(src, type.getStruct(), indentLevel + 1);
812 src << " " << name;
813 }
814
815 src << ";";
816
817 // Print out unused hints.
818 if (unusedHints != 0)
819 src << " // unused in "
820 << (unusedHints == UNUSED_BOTH ? "both shaders" :
821 unusedHints == UNUSED_VERTEX ? "vertex shader" :
822 unusedHints == UNUSED_FRAGMENT ? "fragment shader" :
823 "???");
824
825 src << "\n";
826 }
827
generateDeclaration(std::ostringstream & src,const Uniform & uniform,int indentLevel)828 void generateDeclaration(std::ostringstream &src, const Uniform &uniform, int indentLevel)
829 {
830 if ((uniform.getFlags() & LAYOUT_MASK) != 0)
831 src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
832
833 generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH);
834 }
835
generateDeclaration(std::ostringstream & src,const UniformBlock & block)836 void generateDeclaration(std::ostringstream &src, const UniformBlock &block)
837 {
838 if ((block.getFlags() & LAYOUT_MASK) != 0)
839 src << "layout(" << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ") ";
840
841 src << "uniform " << block.getBlockName();
842 src << "\n{\n";
843
844 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
845 {
846 src << Indent(1);
847 generateDeclaration(src, *uniformIter, 1 /* indent level */);
848 }
849
850 src << "}";
851
852 if (block.getInstanceName() != DE_NULL)
853 {
854 src << " " << block.getInstanceName();
855 if (block.isArray())
856 src << "[" << block.getArraySize() << "]";
857 }
858 else
859 DE_ASSERT(!block.isArray());
860
861 src << ";\n";
862 }
863
generateValueSrc(std::ostringstream & src,const UniformLayoutEntry & entry,const void * basePtr,int elementNdx)864 void generateValueSrc(std::ostringstream &src, const UniformLayoutEntry &entry, const void *basePtr, int elementNdx)
865 {
866 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
867 int scalarSize = glu::getDataTypeScalarSize(entry.type);
868 bool isArray = entry.size > 1;
869 const uint8_t *elemPtr = (const uint8_t *)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
870 const int compSize = sizeof(uint32_t);
871
872 if (scalarSize > 1)
873 src << glu::getDataTypeName(entry.type) << "(";
874
875 if (glu::isDataTypeMatrix(entry.type))
876 {
877 int numRows = glu::getDataTypeMatrixNumRows(entry.type);
878 int numCols = glu::getDataTypeMatrixNumColumns(entry.type);
879
880 DE_ASSERT(scalarType == glu::TYPE_FLOAT);
881
882 // Constructed in column-wise order.
883 for (int colNdx = 0; colNdx < numCols; colNdx++)
884 {
885 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
886 {
887 const uint8_t *compPtr = elemPtr + (entry.isRowMajor ? rowNdx * entry.matrixStride + colNdx * compSize :
888 colNdx * entry.matrixStride + rowNdx * compSize);
889
890 if (colNdx > 0 || rowNdx > 0)
891 src << ", ";
892
893 src << de::floatToString(*((const float *)compPtr), 1);
894 }
895 }
896 }
897 else
898 {
899 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
900 {
901 const uint8_t *compPtr = elemPtr + scalarNdx * compSize;
902
903 if (scalarNdx > 0)
904 src << ", ";
905
906 switch (scalarType)
907 {
908 case glu::TYPE_FLOAT:
909 src << de::floatToString(*((const float *)compPtr), 1);
910 break;
911 case glu::TYPE_INT:
912 src << *((const int *)compPtr);
913 break;
914 case glu::TYPE_UINT:
915 src << *((const uint32_t *)compPtr) << "u";
916 break;
917 case glu::TYPE_BOOL:
918 src << (*((const uint32_t *)compPtr) != 0u ? "true" : "false");
919 break;
920 default:
921 DE_ASSERT(false);
922 }
923 }
924 }
925
926 if (scalarSize > 1)
927 src << ")";
928 }
929
generateCompareSrc(std::ostringstream & src,const char * resultVar,const VarType & type,const char * srcName,const char * apiName,const UniformLayout & layout,const void * basePtr,uint32_t unusedMask)930 void generateCompareSrc(std::ostringstream &src, const char *resultVar, const VarType &type, const char *srcName,
931 const char *apiName, const UniformLayout &layout, const void *basePtr, uint32_t unusedMask)
932 {
933 if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
934 {
935 // Basic type or array of basic types.
936 bool isArray = type.isArrayType();
937 glu::DataType elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType();
938 const char *typeName = glu::getDataTypeName(elementType);
939 std::string fullApiName = string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
940 int uniformNdx = layout.getUniformIndex(fullApiName.c_str());
941 const UniformLayoutEntry &entry = layout.uniforms[uniformNdx];
942
943 if (isArray)
944 {
945 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
946 {
947 src << "\tresult *= compare_" << typeName << "(" << srcName << "[" << elemNdx << "], ";
948 generateValueSrc(src, entry, basePtr, elemNdx);
949 src << ");\n";
950 }
951 }
952 else
953 {
954 src << "\tresult *= compare_" << typeName << "(" << srcName << ", ";
955 generateValueSrc(src, entry, basePtr, 0);
956 src << ");\n";
957 }
958 }
959 else if (type.isArrayType())
960 {
961 const VarType &elementType = type.getElementType();
962 DE_ASSERT(!elementType.isArrayType());
963
964 for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
965 {
966 std::string op = string("[") + de::toString(elementNdx) + "]";
967 generateCompareSrc(src, resultVar, elementType, (string(srcName) + op).c_str(),
968 (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
969 }
970 }
971 else
972 {
973 DE_ASSERT(type.isStructType());
974
975 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
976 memberIter++)
977 {
978 if (memberIter->getFlags() & unusedMask)
979 continue; // Skip member.
980
981 string op = string(".") + memberIter->getName();
982 generateCompareSrc(src, resultVar, memberIter->getType(), (string(srcName) + op).c_str(),
983 (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
984 }
985 }
986 }
987
generateCompareSrc(std::ostringstream & src,const char * resultVar,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,bool isVertex)988 void generateCompareSrc(std::ostringstream &src, const char *resultVar, const ShaderInterface &interface,
989 const UniformLayout &layout, const std::map<int, void *> &blockPointers, bool isVertex)
990 {
991 uint32_t unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
992
993 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
994 {
995 const UniformBlock &block = interface.getUniformBlock(blockNdx);
996
997 if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
998 continue; // Skip.
999
1000 bool hasInstanceName = block.getInstanceName() != DE_NULL;
1001 bool isArray = block.isArray();
1002 int numInstances = isArray ? block.getArraySize() : 1;
1003 std::string apiPrefix = hasInstanceName ? string(block.getBlockName()) + "." : string("");
1004
1005 DE_ASSERT(!isArray || hasInstanceName);
1006
1007 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1008 {
1009 std::string instancePostfix = isArray ? string("[") + de::toString(instanceNdx) + "]" : string("");
1010 std::string blockInstanceName = block.getBlockName() + instancePostfix;
1011 std::string srcPrefix =
1012 hasInstanceName ? string(block.getInstanceName()) + instancePostfix + "." : string("");
1013 int activeBlockNdx = layout.getBlockIndex(blockInstanceName.c_str());
1014 void *basePtr = blockPointers.find(activeBlockNdx)->second;
1015
1016 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
1017 {
1018 const Uniform &uniform = *uniformIter;
1019
1020 if (uniform.getFlags() & unusedMask)
1021 continue; // Don't read from that uniform.
1022
1023 generateCompareSrc(src, resultVar, uniform.getType(), (srcPrefix + uniform.getName()).c_str(),
1024 (apiPrefix + uniform.getName()).c_str(), layout, basePtr, unusedMask);
1025 }
1026 }
1027 }
1028 }
1029
generateVertexShader(std::ostringstream & src,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1030 void generateVertexShader(std::ostringstream &src, glu::GLSLVersion glslVersion, const ShaderInterface &interface,
1031 const UniformLayout &layout, const std::map<int, void *> &blockPointers)
1032 {
1033 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
1034 de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
1035
1036 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1037 src << "in highp vec4 a_position;\n";
1038 src << "out mediump float v_vtxResult;\n";
1039 src << "\n";
1040
1041 std::vector<const StructType *> namedStructs;
1042 interface.getNamedStructs(namedStructs);
1043 for (std::vector<const StructType *>::const_iterator structIter = namedStructs.begin();
1044 structIter != namedStructs.end(); structIter++)
1045 generateDeclaration(src, **structIter, 0);
1046
1047 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1048 {
1049 const UniformBlock &block = interface.getUniformBlock(blockNdx);
1050 if (block.getFlags() & DECLARE_VERTEX)
1051 generateDeclaration(src, block);
1052 }
1053
1054 // Comparison utilities.
1055 src << "\n" << s_compareFuncs;
1056
1057 src << "\n"
1058 "void main (void)\n"
1059 "{\n"
1060 " gl_Position = a_position;\n"
1061 " mediump float result = 1.0;\n";
1062
1063 // Value compare.
1064 generateCompareSrc(src, "result", interface, layout, blockPointers, true);
1065
1066 src << " v_vtxResult = result;\n"
1067 "}\n";
1068 }
1069
generateFragmentShader(std::ostringstream & src,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1070 void generateFragmentShader(std::ostringstream &src, glu::GLSLVersion glslVersion, const ShaderInterface &interface,
1071 const UniformLayout &layout, const std::map<int, void *> &blockPointers)
1072 {
1073 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
1074 de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
1075
1076 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1077 src << "in mediump float v_vtxResult;\n";
1078 src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1079 src << "\n";
1080
1081 std::vector<const StructType *> namedStructs;
1082 interface.getNamedStructs(namedStructs);
1083 for (std::vector<const StructType *>::const_iterator structIter = namedStructs.begin();
1084 structIter != namedStructs.end(); structIter++)
1085 generateDeclaration(src, **structIter, 0);
1086
1087 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1088 {
1089 const UniformBlock &block = interface.getUniformBlock(blockNdx);
1090 if (block.getFlags() & DECLARE_FRAGMENT)
1091 generateDeclaration(src, block);
1092 }
1093
1094 // Comparison utilities.
1095 src << "\n" << s_compareFuncs;
1096
1097 src << "\n"
1098 "void main (void)\n"
1099 "{\n"
1100 " mediump float result = 1.0;\n";
1101
1102 // Value compare.
1103 generateCompareSrc(src, "result", interface, layout, blockPointers, false);
1104
1105 src << " dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
1106 "}\n";
1107 }
1108
getGLUniformLayout(const glw::Functions & gl,UniformLayout & layout,uint32_t program)1109 void getGLUniformLayout(const glw::Functions &gl, UniformLayout &layout, uint32_t program)
1110 {
1111 int numActiveUniforms = 0;
1112 int numActiveBlocks = 0;
1113
1114 gl.getProgramiv(program, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
1115 gl.getProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveBlocks);
1116
1117 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of uniforms and uniform blocks");
1118
1119 // Block entries.
1120 layout.blocks.resize(numActiveBlocks);
1121 for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++)
1122 {
1123 BlockLayoutEntry &entry = layout.blocks[blockNdx];
1124 int size;
1125 int nameLen;
1126 int numBlockUniforms;
1127
1128 gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
1129 gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLen);
1130 gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numBlockUniforms);
1131
1132 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
1133
1134 // \note Some implementations incorrectly return 0 as name length even though the length should include null terminator.
1135 std::vector<char> nameBuf(nameLen > 0 ? nameLen : 1);
1136 gl.getActiveUniformBlockName(program, (uint32_t)blockNdx, (glw::GLsizei)nameBuf.size(), DE_NULL, &nameBuf[0]);
1137
1138 entry.name = std::string(&nameBuf[0]);
1139 entry.size = size;
1140 entry.activeUniformIndices.resize(numBlockUniforms);
1141
1142 if (numBlockUniforms > 0)
1143 gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
1144 &entry.activeUniformIndices[0]);
1145
1146 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
1147 }
1148
1149 if (numActiveUniforms > 0)
1150 {
1151 // Uniform entries.
1152 std::vector<uint32_t> uniformIndices(numActiveUniforms);
1153 for (int i = 0; i < numActiveUniforms; i++)
1154 uniformIndices[i] = (uint32_t)i;
1155
1156 std::vector<int> types(numActiveUniforms);
1157 std::vector<int> sizes(numActiveUniforms);
1158 std::vector<int> nameLengths(numActiveUniforms);
1159 std::vector<int> blockIndices(numActiveUniforms);
1160 std::vector<int> offsets(numActiveUniforms);
1161 std::vector<int> arrayStrides(numActiveUniforms);
1162 std::vector<int> matrixStrides(numActiveUniforms);
1163 std::vector<int> rowMajorFlags(numActiveUniforms);
1164
1165 // Execute queries.
1166 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_TYPE,
1167 &types[0]);
1168 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_SIZE,
1169 &sizes[0]);
1170 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_NAME_LENGTH,
1171 &nameLengths[0]);
1172 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_BLOCK_INDEX,
1173 &blockIndices[0]);
1174 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_OFFSET,
1175 &offsets[0]);
1176 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1177 GL_UNIFORM_ARRAY_STRIDE, &arrayStrides[0]);
1178 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1179 GL_UNIFORM_MATRIX_STRIDE, &matrixStrides[0]);
1180 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1181 GL_UNIFORM_IS_ROW_MAJOR, &rowMajorFlags[0]);
1182
1183 GLU_EXPECT_NO_ERROR(gl.getError(), "Active uniform query failed");
1184
1185 // Translate to LayoutEntries
1186 layout.uniforms.resize(numActiveUniforms);
1187 for (int uniformNdx = 0; uniformNdx < numActiveUniforms; uniformNdx++)
1188 {
1189 UniformLayoutEntry &entry = layout.uniforms[uniformNdx];
1190 std::vector<char> nameBuf(nameLengths[uniformNdx]);
1191 glw::GLsizei nameLen = 0;
1192 int size = 0;
1193 uint32_t type = GL_NONE;
1194
1195 gl.getActiveUniform(program, (uint32_t)uniformNdx, (glw::GLsizei)nameBuf.size(), &nameLen, &size, &type,
1196 &nameBuf[0]);
1197
1198 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform name query failed");
1199
1200 // \note glGetActiveUniform() returns length without \0 and glGetActiveUniformsiv() with \0
1201 if (nameLen + 1 != nameLengths[uniformNdx] || size != sizes[uniformNdx] ||
1202 type != (uint32_t)types[uniformNdx])
1203 TCU_FAIL("Values returned by glGetActiveUniform() don't match with values queried with "
1204 "glGetActiveUniformsiv().");
1205
1206 entry.name = std::string(&nameBuf[0]);
1207 entry.type = glu::getDataTypeFromGLType(types[uniformNdx]);
1208 entry.size = sizes[uniformNdx];
1209 entry.blockNdx = blockIndices[uniformNdx];
1210 entry.offset = offsets[uniformNdx];
1211 entry.arrayStride = arrayStrides[uniformNdx];
1212 entry.matrixStride = matrixStrides[uniformNdx];
1213 entry.isRowMajor = rowMajorFlags[uniformNdx] != GL_FALSE;
1214 }
1215 }
1216 }
1217
copyUniformData(const UniformLayoutEntry & dstEntry,void * dstBlockPtr,const UniformLayoutEntry & srcEntry,const void * srcBlockPtr)1218 void copyUniformData(const UniformLayoutEntry &dstEntry, void *dstBlockPtr, const UniformLayoutEntry &srcEntry,
1219 const void *srcBlockPtr)
1220 {
1221 uint8_t *dstBasePtr = (uint8_t *)dstBlockPtr + dstEntry.offset;
1222 const uint8_t *srcBasePtr = (const uint8_t *)srcBlockPtr + srcEntry.offset;
1223
1224 DE_ASSERT(dstEntry.size <= srcEntry.size);
1225 DE_ASSERT(dstEntry.type == srcEntry.type);
1226
1227 int scalarSize = glu::getDataTypeScalarSize(dstEntry.type);
1228 bool isMatrix = glu::isDataTypeMatrix(dstEntry.type);
1229 const int compSize = sizeof(uint32_t);
1230
1231 for (int elementNdx = 0; elementNdx < dstEntry.size; elementNdx++)
1232 {
1233 uint8_t *dstElemPtr = dstBasePtr + elementNdx * dstEntry.arrayStride;
1234 const uint8_t *srcElemPtr = srcBasePtr + elementNdx * srcEntry.arrayStride;
1235
1236 if (isMatrix)
1237 {
1238 int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
1239 int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
1240
1241 for (int colNdx = 0; colNdx < numCols; colNdx++)
1242 {
1243 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1244 {
1245 uint8_t *dstCompPtr =
1246 dstElemPtr + (dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize :
1247 colNdx * dstEntry.matrixStride + rowNdx * compSize);
1248 const uint8_t *srcCompPtr =
1249 srcElemPtr + (srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize :
1250 colNdx * srcEntry.matrixStride + rowNdx * compSize);
1251 deMemcpy(dstCompPtr, srcCompPtr, compSize);
1252 }
1253 }
1254 }
1255 else
1256 deMemcpy(dstElemPtr, srcElemPtr, scalarSize * compSize);
1257 }
1258 }
1259
copyUniformData(const UniformLayout & dstLayout,const std::map<int,void * > & dstBlockPointers,const UniformLayout & srcLayout,const std::map<int,void * > & srcBlockPointers)1260 void copyUniformData(const UniformLayout &dstLayout, const std::map<int, void *> &dstBlockPointers,
1261 const UniformLayout &srcLayout, const std::map<int, void *> &srcBlockPointers)
1262 {
1263 // \note Src layout is used as reference in case of activeUniforms happens to be incorrect in dstLayout blocks.
1264 int numBlocks = (int)srcLayout.blocks.size();
1265
1266 for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1267 {
1268 const BlockLayoutEntry &srcBlock = srcLayout.blocks[srcBlockNdx];
1269 const void *srcBlockPtr = srcBlockPointers.find(srcBlockNdx)->second;
1270 int dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name.c_str());
1271 void *dstBlockPtr = dstBlockNdx >= 0 ? dstBlockPointers.find(dstBlockNdx)->second : DE_NULL;
1272
1273 if (dstBlockNdx < 0)
1274 continue;
1275
1276 for (vector<int>::const_iterator srcUniformNdxIter = srcBlock.activeUniformIndices.begin();
1277 srcUniformNdxIter != srcBlock.activeUniformIndices.end(); srcUniformNdxIter++)
1278 {
1279 const UniformLayoutEntry &srcEntry = srcLayout.uniforms[*srcUniformNdxIter];
1280 int dstUniformNdx = dstLayout.getUniformIndex(srcEntry.name.c_str());
1281
1282 if (dstUniformNdx < 0)
1283 continue;
1284
1285 copyUniformData(dstLayout.uniforms[dstUniformNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1286 }
1287 }
1288 }
1289
1290 } // namespace
1291
1292 class UniformBufferManager
1293 {
1294 public:
1295 UniformBufferManager(const glu::RenderContext &renderCtx);
1296 ~UniformBufferManager(void);
1297
1298 uint32_t allocBuffer(void);
1299
1300 private:
1301 UniformBufferManager(const UniformBufferManager &other);
1302 UniformBufferManager &operator=(const UniformBufferManager &other);
1303
1304 const glu::RenderContext &m_renderCtx;
1305 std::vector<uint32_t> m_buffers;
1306 };
1307
UniformBufferManager(const glu::RenderContext & renderCtx)1308 UniformBufferManager::UniformBufferManager(const glu::RenderContext &renderCtx) : m_renderCtx(renderCtx)
1309 {
1310 }
1311
~UniformBufferManager(void)1312 UniformBufferManager::~UniformBufferManager(void)
1313 {
1314 if (!m_buffers.empty())
1315 m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
1316 }
1317
allocBuffer(void)1318 uint32_t UniformBufferManager::allocBuffer(void)
1319 {
1320 uint32_t buf = 0;
1321
1322 m_buffers.reserve(m_buffers.size() + 1);
1323 m_renderCtx.getFunctions().genBuffers(1, &buf);
1324 GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate uniform buffer");
1325 m_buffers.push_back(buf);
1326
1327 return buf;
1328 }
1329
1330 } // namespace ub
1331
1332 using namespace ub;
1333
1334 // UniformBlockCase.
1335
UniformBlockCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,BufferMode bufferMode)1336 UniformBlockCase::UniformBlockCase(Context &context, const char *name, const char *description,
1337 glu::GLSLVersion glslVersion, BufferMode bufferMode)
1338 : TestCase(context, name, description)
1339 , m_glslVersion(glslVersion)
1340 , m_bufferMode(bufferMode)
1341 {
1342 // \todo [2013-05-25 pyry] Support other versions as well.
1343 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_330);
1344 }
1345
~UniformBlockCase(void)1346 UniformBlockCase::~UniformBlockCase(void)
1347 {
1348 }
1349
iterate(void)1350 UniformBlockCase::IterateResult UniformBlockCase::iterate(void)
1351 {
1352 TestLog &log = m_testCtx.getLog();
1353 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1354 UniformLayout refLayout; //!< std140 layout.
1355 vector<uint8_t> data; //!< Data.
1356 map<int, void *> blockPointers; //!< Reference block pointers.
1357
1358 // Initialize result to pass.
1359 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1360
1361 // Compute reference layout.
1362 computeStd140Layout(refLayout, m_interface);
1363
1364 // Assign storage for reference values.
1365 {
1366 int totalSize = 0;
1367 for (vector<BlockLayoutEntry>::const_iterator blockIter = refLayout.blocks.begin();
1368 blockIter != refLayout.blocks.end(); blockIter++)
1369 totalSize += blockIter->size;
1370 data.resize(totalSize);
1371
1372 // Pointers for each block.
1373 int curOffset = 0;
1374 for (int blockNdx = 0; blockNdx < (int)refLayout.blocks.size(); blockNdx++)
1375 {
1376 blockPointers[blockNdx] = &data[0] + curOffset;
1377 curOffset += refLayout.blocks[blockNdx].size;
1378 }
1379 }
1380
1381 // Generate values.
1382 generateValues(refLayout, blockPointers, 1 /* seed */);
1383
1384 // Generate shaders and build program.
1385 std::ostringstream vtxSrc;
1386 std::ostringstream fragSrc;
1387
1388 generateVertexShader(vtxSrc, m_glslVersion, m_interface, refLayout, blockPointers);
1389 generateFragmentShader(fragSrc, m_glslVersion, m_interface, refLayout, blockPointers);
1390
1391 glu::ShaderProgram program(m_context.getRenderContext(),
1392 glu::makeVtxFragSources(vtxSrc.str().c_str(), fragSrc.str().c_str()));
1393 log << program;
1394
1395 if (!program.isOk())
1396 {
1397 // Compile failed.
1398 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
1399 return STOP;
1400 }
1401
1402 // Query layout from GL.
1403 UniformLayout glLayout;
1404 getGLUniformLayout(gl, glLayout, program.getProgram());
1405
1406 // Print layout to log.
1407 log << TestLog::Section("ActiveUniformBlocks", "Active Uniform Blocks");
1408 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
1409 log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage;
1410 log << TestLog::EndSection;
1411
1412 log << TestLog::Section("ActiveUniforms", "Active Uniforms");
1413 for (int uniformNdx = 0; uniformNdx < (int)glLayout.uniforms.size(); uniformNdx++)
1414 log << TestLog::Message << uniformNdx << ": " << glLayout.uniforms[uniformNdx] << TestLog::EndMessage;
1415 log << TestLog::EndSection;
1416
1417 // Check that we can even try rendering with given layout.
1418 if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout))
1419 {
1420 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout");
1421 return STOP; // It is not safe to use the given layout.
1422 }
1423
1424 // Verify all std140 blocks.
1425 if (!compareStd140Blocks(refLayout, glLayout))
1426 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 layout");
1427
1428 // Verify all shared blocks - all uniforms should be active, and certain properties match.
1429 if (!compareSharedBlocks(refLayout, glLayout))
1430 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout");
1431
1432 // Check consistency with index queries
1433 if (!checkIndexQueries(program.getProgram(), glLayout))
1434 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results");
1435
1436 // Use program.
1437 gl.useProgram(program.getProgram());
1438
1439 // Assign binding points to all active uniform blocks.
1440 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
1441 {
1442 uint32_t binding = (uint32_t)blockNdx; // \todo [2012-01-25 pyry] Randomize order?
1443 gl.uniformBlockBinding(program.getProgram(), (uint32_t)blockNdx, binding);
1444 }
1445
1446 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set uniform block bindings");
1447
1448 // Allocate buffers, write data and bind to targets.
1449 UniformBufferManager bufferManager(m_context.getRenderContext());
1450 if (m_bufferMode == BUFFERMODE_PER_BLOCK)
1451 {
1452 int numBlocks = (int)glLayout.blocks.size();
1453 vector<vector<uint8_t>> glData(numBlocks);
1454 map<int, void *> glBlockPointers;
1455
1456 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1457 {
1458 glData[blockNdx].resize(glLayout.blocks[blockNdx].size);
1459 glBlockPointers[blockNdx] = &glData[blockNdx][0];
1460 }
1461
1462 copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
1463
1464 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1465 {
1466 uint32_t buffer = bufferManager.allocBuffer();
1467 uint32_t binding = (uint32_t)blockNdx;
1468
1469 gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
1470 gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData[blockNdx].size(), &glData[blockNdx][0],
1471 GL_STATIC_DRAW);
1472 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
1473
1474 gl.bindBufferBase(GL_UNIFORM_BUFFER, binding, buffer);
1475 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase(GL_UNIFORM_BUFFER) failed");
1476 }
1477 }
1478 else
1479 {
1480 DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE);
1481
1482 int totalSize = 0;
1483 int curOffset = 0;
1484 int numBlocks = (int)glLayout.blocks.size();
1485 int bindingAlignment = m_context.getContextInfo().getInt(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
1486 map<int, int> glBlockOffsets;
1487
1488 // Compute total size and offsets.
1489 curOffset = 0;
1490 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1491 {
1492 if (bindingAlignment > 0)
1493 curOffset = deRoundUp32(curOffset, bindingAlignment);
1494 glBlockOffsets[blockNdx] = curOffset;
1495 curOffset += glLayout.blocks[blockNdx].size;
1496 }
1497 totalSize = curOffset;
1498
1499 // Assign block pointers.
1500 vector<uint8_t> glData(totalSize);
1501 map<int, void *> glBlockPointers;
1502
1503 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1504 glBlockPointers[blockNdx] = &glData[glBlockOffsets[blockNdx]];
1505
1506 // Copy to gl format.
1507 copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
1508
1509 // Allocate buffer and upload data.
1510 uint32_t buffer = bufferManager.allocBuffer();
1511 gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
1512 if (!glData.empty())
1513 gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData.size(), &glData[0], GL_STATIC_DRAW);
1514
1515 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
1516
1517 // Bind ranges to binding points.
1518 curOffset = 0;
1519 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1520 {
1521 uint32_t binding = (uint32_t)blockNdx;
1522 gl.bindBufferRange(GL_UNIFORM_BUFFER, binding, buffer, (glw::GLintptr)glBlockOffsets[blockNdx],
1523 (glw::GLsizeiptr)glLayout.blocks[blockNdx].size);
1524 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_UNIFORM_BUFFER) failed");
1525 curOffset += glLayout.blocks[blockNdx].size;
1526 }
1527 }
1528
1529 bool renderOk = render(program);
1530 if (!renderOk)
1531 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed");
1532
1533 return STOP;
1534 }
1535
compareStd140Blocks(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1536 bool UniformBlockCase::compareStd140Blocks(const UniformLayout &refLayout, const UniformLayout &cmpLayout) const
1537 {
1538 TestLog &log = m_testCtx.getLog();
1539 bool isOk = true;
1540 int numBlocks = m_interface.getNumUniformBlocks();
1541
1542 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1543 {
1544 const UniformBlock &block = m_interface.getUniformBlock(blockNdx);
1545 bool isArray = block.isArray();
1546 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
1547 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str());
1548 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str());
1549 bool isUsed = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
1550
1551 if ((block.getFlags() & LAYOUT_STD140) == 0)
1552 continue; // Not std140 layout.
1553
1554 DE_ASSERT(refBlockNdx >= 0);
1555
1556 if (cmpBlockNdx < 0)
1557 {
1558 // Not found, should it?
1559 if (isUsed)
1560 {
1561 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
1562 << TestLog::EndMessage;
1563 isOk = false;
1564 }
1565
1566 continue; // Skip block.
1567 }
1568
1569 const BlockLayoutEntry &refBlockLayout = refLayout.blocks[refBlockNdx];
1570 const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1571
1572 // \todo [2012-01-24 pyry] Verify that activeUniformIndices is correct.
1573 // \todo [2012-01-24 pyry] Verify all instances.
1574 if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
1575 {
1576 log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
1577 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
1578 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
1579 isOk = false;
1580 }
1581
1582 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
1583 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
1584 {
1585 const UniformLayoutEntry &refEntry = refLayout.uniforms[*ndxIter];
1586 int cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str());
1587
1588 if (cmpEntryNdx < 0)
1589 {
1590 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
1591 isOk = false;
1592 continue;
1593 }
1594
1595 const UniformLayoutEntry &cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
1596
1597 if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
1598 refEntry.offset != cmpEntry.offset || refEntry.arrayStride != cmpEntry.arrayStride ||
1599 refEntry.matrixStride != cmpEntry.matrixStride || refEntry.isRowMajor != cmpEntry.isRowMajor)
1600 {
1601 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
1602 << " expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
1603 << ", offset = " << refEntry.offset << ", array stride = " << refEntry.arrayStride
1604 << ", matrix stride = " << refEntry.matrixStride
1605 << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
1606 << " got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
1607 << ", offset = " << cmpEntry.offset << ", array stride = " << cmpEntry.arrayStride
1608 << ", matrix stride = " << cmpEntry.matrixStride
1609 << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
1610 isOk = false;
1611 }
1612 }
1613 }
1614
1615 return isOk;
1616 }
1617
compareSharedBlocks(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1618 bool UniformBlockCase::compareSharedBlocks(const UniformLayout &refLayout, const UniformLayout &cmpLayout) const
1619 {
1620 TestLog &log = m_testCtx.getLog();
1621 bool isOk = true;
1622 int numBlocks = m_interface.getNumUniformBlocks();
1623
1624 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1625 {
1626 const UniformBlock &block = m_interface.getUniformBlock(blockNdx);
1627 bool isArray = block.isArray();
1628 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
1629 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str());
1630 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str());
1631 bool isUsed = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
1632
1633 if ((block.getFlags() & LAYOUT_SHARED) == 0)
1634 continue; // Not shared layout.
1635
1636 DE_ASSERT(refBlockNdx >= 0);
1637
1638 if (cmpBlockNdx < 0)
1639 {
1640 // Not found, should it?
1641 if (isUsed)
1642 {
1643 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
1644 << TestLog::EndMessage;
1645 isOk = false;
1646 }
1647
1648 continue; // Skip block.
1649 }
1650
1651 const BlockLayoutEntry &refBlockLayout = refLayout.blocks[refBlockNdx];
1652 const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1653
1654 if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
1655 {
1656 log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
1657 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
1658 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
1659 isOk = false;
1660 }
1661
1662 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
1663 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
1664 {
1665 const UniformLayoutEntry &refEntry = refLayout.uniforms[*ndxIter];
1666 int cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str());
1667
1668 if (cmpEntryNdx < 0)
1669 {
1670 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
1671 isOk = false;
1672 continue;
1673 }
1674
1675 const UniformLayoutEntry &cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
1676
1677 if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
1678 refEntry.isRowMajor != cmpEntry.isRowMajor)
1679 {
1680 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
1681 << " expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
1682 << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
1683 << " got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
1684 << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
1685 isOk = false;
1686 }
1687 }
1688 }
1689
1690 return isOk;
1691 }
1692
compareTypes(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1693 bool UniformBlockCase::compareTypes(const UniformLayout &refLayout, const UniformLayout &cmpLayout) const
1694 {
1695 TestLog &log = m_testCtx.getLog();
1696 bool isOk = true;
1697 int numBlocks = m_interface.getNumUniformBlocks();
1698
1699 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1700 {
1701 const UniformBlock &block = m_interface.getUniformBlock(blockNdx);
1702 bool isArray = block.isArray();
1703 int numInstances = isArray ? block.getArraySize() : 1;
1704
1705 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1706 {
1707 std::ostringstream instanceName;
1708
1709 instanceName << block.getBlockName();
1710 if (isArray)
1711 instanceName << "[" << instanceNdx << "]";
1712
1713 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str());
1714
1715 if (cmpBlockNdx < 0)
1716 continue;
1717
1718 const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1719
1720 for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeUniformIndices.begin();
1721 ndxIter != cmpBlockLayout.activeUniformIndices.end(); ndxIter++)
1722 {
1723 const UniformLayoutEntry &cmpEntry = cmpLayout.uniforms[*ndxIter];
1724 int refEntryNdx = refLayout.getUniformIndex(cmpEntry.name.c_str());
1725
1726 if (refEntryNdx < 0)
1727 {
1728 log << TestLog::Message << "Error: Uniform '" << cmpEntry.name << "' not found in reference layout"
1729 << TestLog::EndMessage;
1730 isOk = false;
1731 continue;
1732 }
1733
1734 const UniformLayoutEntry &refEntry = refLayout.uniforms[refEntryNdx];
1735
1736 // \todo [2012-11-26 pyry] Should we check other properties as well?
1737 if (refEntry.type != cmpEntry.type)
1738 {
1739 log << TestLog::Message << "Error: Uniform type mismatch in '" << refEntry.name << "':\n"
1740 << " expected: " << glu::getDataTypeName(refEntry.type) << "\n"
1741 << " got: " << glu::getDataTypeName(cmpEntry.type) << TestLog::EndMessage;
1742 isOk = false;
1743 }
1744 }
1745 }
1746 }
1747
1748 return isOk;
1749 }
1750
checkLayoutIndices(const UniformLayout & layout) const1751 bool UniformBlockCase::checkLayoutIndices(const UniformLayout &layout) const
1752 {
1753 TestLog &log = m_testCtx.getLog();
1754 int numUniforms = (int)layout.uniforms.size();
1755 int numBlocks = (int)layout.blocks.size();
1756 bool isOk = true;
1757
1758 // Check uniform block indices.
1759 for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
1760 {
1761 const UniformLayoutEntry &uniform = layout.uniforms[uniformNdx];
1762
1763 if (uniform.blockNdx < 0 || !deInBounds32(uniform.blockNdx, 0, numBlocks))
1764 {
1765 log << TestLog::Message << "Error: Invalid block index in uniform '" << uniform.name << "'"
1766 << TestLog::EndMessage;
1767 isOk = false;
1768 }
1769 }
1770
1771 // Check active uniforms.
1772 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1773 {
1774 const BlockLayoutEntry &block = layout.blocks[blockNdx];
1775
1776 for (vector<int>::const_iterator uniformIter = block.activeUniformIndices.begin();
1777 uniformIter != block.activeUniformIndices.end(); uniformIter++)
1778 {
1779 if (!deInBounds32(*uniformIter, 0, numUniforms))
1780 {
1781 log << TestLog::Message << "Error: Invalid active uniform index " << *uniformIter << " in block '"
1782 << block.name << "'" << TestLog::EndMessage;
1783 isOk = false;
1784 }
1785 }
1786 }
1787
1788 return isOk;
1789 }
1790
checkLayoutBounds(const UniformLayout & layout) const1791 bool UniformBlockCase::checkLayoutBounds(const UniformLayout &layout) const
1792 {
1793 TestLog &log = m_testCtx.getLog();
1794 int numUniforms = (int)layout.uniforms.size();
1795 bool isOk = true;
1796
1797 for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
1798 {
1799 const UniformLayoutEntry &uniform = layout.uniforms[uniformNdx];
1800
1801 if (uniform.blockNdx < 0)
1802 continue;
1803
1804 const BlockLayoutEntry &block = layout.blocks[uniform.blockNdx];
1805 bool isMatrix = glu::isDataTypeMatrix(uniform.type);
1806 int numVecs = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumRows(uniform.type) :
1807 glu::getDataTypeMatrixNumColumns(uniform.type)) :
1808 1;
1809 int numComps = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumColumns(uniform.type) :
1810 glu::getDataTypeMatrixNumRows(uniform.type)) :
1811 glu::getDataTypeScalarSize(uniform.type);
1812 int numElements = uniform.size;
1813 const int compSize = sizeof(uint32_t);
1814 int vecSize = numComps * compSize;
1815
1816 int minOffset = 0;
1817 int maxOffset = 0;
1818
1819 // For negative strides.
1820 minOffset = de::min(minOffset, (numVecs - 1) * uniform.matrixStride);
1821 minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride);
1822 minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride);
1823
1824 maxOffset = de::max(maxOffset, vecSize);
1825 maxOffset = de::max(maxOffset, (numVecs - 1) * uniform.matrixStride + vecSize);
1826 maxOffset = de::max(maxOffset, (numElements - 1) * uniform.arrayStride + vecSize);
1827 maxOffset = de::max(maxOffset,
1828 (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride + vecSize);
1829
1830 if (uniform.offset + minOffset < 0 || uniform.offset + maxOffset > block.size)
1831 {
1832 log << TestLog::Message << "Error: Uniform '" << uniform.name << "' out of block bounds"
1833 << TestLog::EndMessage;
1834 isOk = false;
1835 }
1836 }
1837
1838 return isOk;
1839 }
1840
checkIndexQueries(uint32_t program,const UniformLayout & layout) const1841 bool UniformBlockCase::checkIndexQueries(uint32_t program, const UniformLayout &layout) const
1842 {
1843 tcu::TestLog &log = m_testCtx.getLog();
1844 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1845 bool allOk = true;
1846
1847 // \note Spec mandates that uniform blocks are assigned consecutive locations from 0
1848 // to ACTIVE_UNIFORM_BLOCKS. BlockLayoutEntries are stored in that order in UniformLayout.
1849 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1850 {
1851 const BlockLayoutEntry &block = layout.blocks[blockNdx];
1852 const int queriedNdx = gl.getUniformBlockIndex(program, block.name.c_str());
1853
1854 if (queriedNdx != blockNdx)
1855 {
1856 log << TestLog::Message << "ERROR: glGetUniformBlockIndex(" << block.name << ") returned " << queriedNdx
1857 << ", expected " << blockNdx << "!" << TestLog::EndMessage;
1858 allOk = false;
1859 }
1860
1861 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()");
1862 }
1863
1864 return allOk;
1865 }
1866
render(glu::ShaderProgram & program) const1867 bool UniformBlockCase::render(glu::ShaderProgram &program) const
1868 {
1869 tcu::TestLog &log = m_testCtx.getLog();
1870 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1871 de::Random rnd(deStringHash(getName()));
1872 const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
1873 const int viewportW = de::min(renderTarget.getWidth(), 128);
1874 const int viewportH = de::min(renderTarget.getHeight(), 128);
1875 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - viewportW);
1876 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - viewportH);
1877
1878 // Draw
1879 {
1880 const float position[] = {-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f,
1881 +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f};
1882 const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
1883
1884 gl.viewport(viewportX, viewportY, viewportW, viewportH);
1885
1886 glu::VertexArrayBinding posArray = glu::va::Float("a_position", 4, 4, 0, &position[0]);
1887 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posArray,
1888 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1889 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1890 }
1891
1892 // Verify that all pixels are white.
1893 {
1894 tcu::Surface pixels(viewportW, viewportH);
1895 int numFailedPixels = 0;
1896
1897 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, pixels.getAccess());
1898 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
1899
1900 for (int y = 0; y < pixels.getHeight(); y++)
1901 {
1902 for (int x = 0; x < pixels.getWidth(); x++)
1903 {
1904 if (pixels.getPixel(x, y) != tcu::RGBA::white())
1905 numFailedPixels += 1;
1906 }
1907 }
1908
1909 if (numFailedPixels > 0)
1910 {
1911 log << TestLog::Image("Image", "Rendered image", pixels);
1912 log << TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels"
1913 << TestLog::EndMessage;
1914 }
1915
1916 return numFailedPixels == 0;
1917 }
1918 }
1919
1920 } // namespace deqp
1921