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