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