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