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