1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 * \brief Uniform block case.
23 */ /*-------------------------------------------------------------------*/
25 #include "glcUniformBlockCase.hpp"
27 #include "deRandom.hpp"
29 #include "deStringUtil.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluDrawUtil.hpp"
32 #include "gluPixelTransfer.hpp"
33 #include "gluRenderContext.hpp"
34 #include "glwEnums.hpp"
35 #include "glwFunctions.hpp"
36 #include "tcuRenderTarget.hpp"
37 #include "tcuSurface.hpp"
38 #include "tcuTestLog.hpp"
53 struct PrecisionFlagsFmt
57 PrecisionFlagsFmt(deUint32 flags_) : flags(flags_)
62 std::ostream& operator<<(std::ostream& str, const PrecisionFlagsFmt& fmt)
65 DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW | PRECISION_MEDIUM | PRECISION_HIGH)) <= 1);
66 str << (fmt.flags & PRECISION_LOW ?
68 fmt.flags & PRECISION_MEDIUM ? "mediump" : fmt.flags & PRECISION_HIGH ? "highp" : "");
75 LayoutFlagsFmt(deUint32 flags_) : flags(flags_)
80 std::ostream& operator<<(std::ostream& str, const LayoutFlagsFmt& fmt)
86 } bitDesc[] = { { LAYOUT_SHARED, "shared" },
87 { LAYOUT_PACKED, "packed" },
88 { LAYOUT_STD140, "std140" },
89 { LAYOUT_ROW_MAJOR, "row_major" },
90 { LAYOUT_COLUMN_MAJOR, "column_major" } };
92 deUint32 remBits = fmt.flags;
93 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
95 if (remBits & bitDesc[descNdx].bit)
97 if (remBits != fmt.flags)
99 str << bitDesc[descNdx].token;
100 remBits &= ~bitDesc[descNdx].bit;
103 DE_ASSERT(remBits == 0);
107 // VarType implementation.
109 VarType::VarType(void) : m_type(TYPE_LAST), m_flags(0)
113 VarType::VarType(const VarType& other) : m_type(TYPE_LAST), m_flags(0)
118 VarType::VarType(glu::DataType basicType, deUint32 flags) : m_type(TYPE_BASIC), m_flags(flags)
120 m_data.basicType = basicType;
123 VarType::VarType(const VarType& elementType, int arraySize) : m_type(TYPE_ARRAY), m_flags(0)
125 m_data.array.size = arraySize;
126 m_data.array.elementType = new VarType(elementType);
129 VarType::VarType(const StructType* structPtr) : m_type(TYPE_STRUCT), m_flags(0)
131 m_data.structPtr = structPtr;
134 VarType::~VarType(void)
136 if (m_type == TYPE_ARRAY)
137 delete m_data.array.elementType;
140 VarType& VarType::operator=(const VarType& other)
143 return *this; // Self-assignment.
145 if (m_type == TYPE_ARRAY)
146 delete m_data.array.elementType;
148 m_type = other.m_type;
149 m_flags = other.m_flags;
152 if (m_type == TYPE_ARRAY)
154 m_data.array.elementType = new VarType(*other.m_data.array.elementType);
155 m_data.array.size = other.m_data.array.size;
158 m_data = other.m_data;
163 // StructType implementation.
165 void StructType::addMember(const char* name, const VarType& type, deUint32 flags)
167 m_members.push_back(StructMember(name, type, flags));
170 // Uniform implementation.
172 Uniform::Uniform(const char* name, const VarType& type, deUint32 flags) : m_name(name), m_type(type), m_flags(flags)
176 // UniformBlock implementation.
178 UniformBlock::UniformBlock(const char* blockName) : m_blockName(blockName), m_arraySize(0), m_flags(0)
182 struct BlockLayoutEntry
184 BlockLayoutEntry(void) : size(0)
190 std::vector<int> activeUniformIndices;
193 std::ostream& operator<<(std::ostream& stream, const BlockLayoutEntry& entry)
195 stream << entry.name << " { name = " << entry.name << ", size = " << entry.size << ", activeUniformIndices = [";
197 for (vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++)
199 if (i != entry.activeUniformIndices.begin())
208 struct UniformLayoutEntry
210 UniformLayoutEntry(void)
211 : type(glu::TYPE_LAST), size(0), blockNdx(-1), offset(-1), arrayStride(-1), matrixStride(-1), isRowMajor(false)
225 std::ostream& operator<<(std::ostream& stream, const UniformLayoutEntry& entry)
227 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) << ", size = " << entry.size
228 << ", blockNdx = " << entry.blockNdx << ", offset = " << entry.offset
229 << ", arrayStride = " << entry.arrayStride << ", matrixStride = " << entry.matrixStride
230 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") << " }";
237 std::vector<BlockLayoutEntry> blocks;
238 std::vector<UniformLayoutEntry> uniforms;
240 int getUniformIndex(const char* name) const;
241 int getBlockIndex(const char* name) const;
244 // \todo [2012-01-24 pyry] Speed up lookups using hash.
246 int UniformLayout::getUniformIndex(const char* name) const
248 for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
250 if (uniforms[ndx].name == name)
256 int UniformLayout::getBlockIndex(const char* name) const
258 for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
260 if (blocks[ndx].name == name)
266 // ShaderInterface implementation.
268 ShaderInterface::ShaderInterface(void)
272 ShaderInterface::~ShaderInterface(void)
274 for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
277 for (std::vector<UniformBlock*>::iterator i = m_uniformBlocks.begin(); i != m_uniformBlocks.end(); i++)
281 StructType& ShaderInterface::allocStruct(const char* name)
283 m_structs.reserve(m_structs.size() + 1);
284 m_structs.push_back(new StructType(name));
285 return *m_structs.back();
288 struct StructNameEquals
292 StructNameEquals(const char* name_) : name(name_)
296 bool operator()(const StructType* type) const
298 return type->getTypeName() && name == type->getTypeName();
302 const StructType* ShaderInterface::findStruct(const char* name) const
304 std::vector<StructType*>::const_iterator pos =
305 std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
306 return pos != m_structs.end() ? *pos : DE_NULL;
309 void ShaderInterface::getNamedStructs(std::vector<const StructType*>& structs) const
311 for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
313 if ((*i)->getTypeName() != DE_NULL)
314 structs.push_back(*i);
318 UniformBlock& ShaderInterface::allocBlock(const char* name)
320 m_uniformBlocks.reserve(m_uniformBlocks.size() + 1);
321 m_uniformBlocks.push_back(new UniformBlock(name));
322 return *m_uniformBlocks.back();
325 namespace // Utilities
328 // Layout computation.
330 int getDataTypeByteSize(glu::DataType type)
332 return static_cast<int>(glu::getDataTypeScalarSize(type) * sizeof(deUint32));
335 int getDataTypeByteAlignment(glu::DataType type)
339 case glu::TYPE_FLOAT:
343 return static_cast<int>(1 * sizeof(deUint32));
345 case glu::TYPE_FLOAT_VEC2:
346 case glu::TYPE_INT_VEC2:
347 case glu::TYPE_UINT_VEC2:
348 case glu::TYPE_BOOL_VEC2:
349 return static_cast<int>(2 * sizeof(deUint32));
351 case glu::TYPE_FLOAT_VEC3:
352 case glu::TYPE_INT_VEC3:
353 case glu::TYPE_UINT_VEC3:
354 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4
356 case glu::TYPE_FLOAT_VEC4:
357 case glu::TYPE_INT_VEC4:
358 case glu::TYPE_UINT_VEC4:
359 case glu::TYPE_BOOL_VEC4:
360 return static_cast<int>(4 * sizeof(deUint32));
368 int getDataTypeArrayStride(glu::DataType type)
370 DE_ASSERT(!glu::isDataTypeMatrix(type));
372 int baseStride = getDataTypeByteSize(type);
373 int vec4Alignment = static_cast<int>(sizeof(deUint32) * 4);
375 DE_ASSERT(baseStride <= vec4Alignment);
376 return de::max(baseStride, vec4Alignment); // Really? See rule 4.
379 static inline int deRoundUp32(int a, int b)
382 return d * b == a ? a : (d + 1) * b;
385 int computeStd140BaseAlignment(const VarType& type)
387 const int vec4Alignment = static_cast<int>(sizeof(deUint32) * 4);
389 if (type.isBasicType())
391 glu::DataType basicType = type.getBasicType();
393 if (glu::isDataTypeMatrix(basicType))
395 bool isRowMajor = !!(type.getFlags() & LAYOUT_ROW_MAJOR);
397 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
399 return getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
402 return getDataTypeByteAlignment(basicType);
404 else if (type.isArrayType())
406 int elemAlignment = computeStd140BaseAlignment(type.getElementType());
408 // Round up to alignment of vec4
409 return deRoundUp32(elemAlignment, vec4Alignment);
413 DE_ASSERT(type.isStructType());
415 int maxBaseAlignment = 0;
417 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
419 maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType()));
421 return deRoundUp32(maxBaseAlignment, vec4Alignment);
425 inline deUint32 mergeLayoutFlags(deUint32 prevFlags, deUint32 newFlags)
427 const deUint32 packingMask = LAYOUT_PACKED | LAYOUT_SHARED | LAYOUT_STD140;
428 const deUint32 matrixMask = LAYOUT_ROW_MAJOR | LAYOUT_COLUMN_MAJOR;
430 deUint32 mergedFlags = 0;
432 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
433 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
438 void computeStd140Layout(UniformLayout& layout, int& curOffset, int curBlockNdx, const std::string& curPrefix,
439 const VarType& type, deUint32 layoutFlags)
441 int baseAlignment = computeStd140BaseAlignment(type);
443 curOffset = deAlign32(curOffset, baseAlignment);
445 if (type.isBasicType())
447 glu::DataType basicType = type.getBasicType();
448 UniformLayoutEntry entry;
450 entry.name = curPrefix;
451 entry.type = basicType;
453 entry.arrayStride = 0;
454 entry.matrixStride = 0;
455 entry.blockNdx = curBlockNdx;
457 if (glu::isDataTypeMatrix(basicType))
459 // Array of vectors as specified in rules 5 & 7.
460 bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
462 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
464 isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) : glu::getDataTypeMatrixNumColumns(basicType);
465 int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
467 entry.offset = curOffset;
468 entry.matrixStride = stride;
469 entry.isRowMajor = isRowMajor;
471 curOffset += numVecs * stride;
476 entry.offset = curOffset;
478 curOffset += getDataTypeByteSize(basicType);
481 layout.uniforms.push_back(entry);
483 else if (type.isArrayType())
485 const VarType& elemType = type.getElementType();
487 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
489 // Array of scalars or vectors.
490 glu::DataType elemBasicType = elemType.getBasicType();
491 UniformLayoutEntry entry;
492 int stride = getDataTypeArrayStride(elemBasicType);
494 entry.name = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
495 entry.type = elemBasicType;
496 entry.blockNdx = curBlockNdx;
497 entry.offset = curOffset;
498 entry.size = type.getArraySize();
499 entry.arrayStride = stride;
500 entry.matrixStride = 0;
502 curOffset += stride * type.getArraySize();
504 layout.uniforms.push_back(entry);
506 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
508 // Array of matrices.
509 glu::DataType elemBasicType = elemType.getBasicType();
510 bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
511 int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) :
512 glu::getDataTypeMatrixNumRows(elemBasicType);
513 int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) :
514 glu::getDataTypeMatrixNumColumns(elemBasicType);
515 int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
516 UniformLayoutEntry entry;
518 entry.name = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
519 entry.type = elemBasicType;
520 entry.blockNdx = curBlockNdx;
521 entry.offset = curOffset;
522 entry.size = type.getArraySize();
523 entry.arrayStride = stride * numVecs;
524 entry.matrixStride = stride;
525 entry.isRowMajor = isRowMajor;
527 curOffset += numVecs * type.getArraySize() * stride;
529 layout.uniforms.push_back(entry);
533 DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
535 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
536 computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "[" + de::toString(elemNdx) + "]",
537 type.getElementType(), layoutFlags);
542 DE_ASSERT(type.isStructType());
544 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
546 computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "." + memberIter->getName(),
547 memberIter->getType(), layoutFlags);
549 curOffset = deAlign32(curOffset, baseAlignment);
553 void computeStd140Layout(UniformLayout& layout, const ShaderInterface& interface)
555 // \todo [2012-01-23 pyry] Uniforms in default block.
557 int numUniformBlocks = interface.getNumUniformBlocks();
559 for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
561 const UniformBlock& block = interface.getUniformBlock(blockNdx);
562 bool hasInstanceName = block.getInstanceName() != DE_NULL;
563 std::string blockPrefix = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
565 int activeBlockNdx = (int)layout.blocks.size();
566 int firstUniformNdx = (int)layout.uniforms.size();
568 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
570 const Uniform& uniform = *uniformIter;
571 computeStd140Layout(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(),
572 mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
575 int uniformIndicesEnd = (int)layout.uniforms.size();
576 int blockSize = curOffset;
577 int numInstances = block.isArray() ? block.getArraySize() : 1;
579 // Create block layout entries for each instance.
580 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
582 // Allocate entry for instance.
583 layout.blocks.push_back(BlockLayoutEntry());
584 BlockLayoutEntry& blockEntry = layout.blocks.back();
586 blockEntry.name = block.getBlockName();
587 blockEntry.size = blockSize;
589 // Compute active uniform set for block.
590 for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
591 blockEntry.activeUniformIndices.push_back(uniformNdx);
594 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
601 void generateValue(const UniformLayoutEntry& entry, void* basePtr, de::Random& rnd)
603 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
604 int scalarSize = glu::getDataTypeScalarSize(entry.type);
605 bool isMatrix = glu::isDataTypeMatrix(entry.type);
606 int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) :
607 glu::getDataTypeMatrixNumColumns(entry.type)) :
609 int vecSize = scalarSize / numVecs;
610 bool isArray = entry.size > 1;
611 const int compSize = sizeof(deUint32);
613 DE_ASSERT(scalarSize % numVecs == 0);
615 for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
617 deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx * entry.arrayStride : 0);
619 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
621 deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx * entry.matrixStride : 0);
623 for (int compNdx = 0; compNdx < vecSize; compNdx++)
625 deUint8* compPtr = vecPtr + compSize * compNdx;
629 case glu::TYPE_FLOAT:
630 *((float*)compPtr) = (float)rnd.getInt(-9, 9);
633 *((int*)compPtr) = rnd.getInt(-9, 9);
636 *((deUint32*)compPtr) = (deUint32)rnd.getInt(0, 9);
638 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
639 // interpreted as true but some implementations fail this.
641 *((deUint32*)compPtr) = rnd.getBool() ? rnd.getUint32() | 1u : 0u;
651 void generateValues(const UniformLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed)
653 de::Random rnd(seed);
654 int numBlocks = (int)layout.blocks.size();
656 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
658 void* basePtr = blockPointers.find(blockNdx)->second;
659 int numEntries = (int)layout.blocks[blockNdx].activeUniformIndices.size();
661 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
663 const UniformLayoutEntry& entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
664 generateValue(entry, basePtr, rnd);
671 static const char* s_compareFuncs =
672 "mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n"
673 "mediump float compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, "
674 "b.x)*compare_float(a.y, b.y); }\n"
675 "mediump float compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, "
676 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n"
677 "mediump float compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, "
678 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n"
679 "mediump float compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], "
680 "b[0])*compare_vec2(a[1], b[1]); }\n"
681 "mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], "
682 "b[0])*compare_vec3(a[1], b[1]); }\n"
683 "mediump float compare_mat2x4 (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], "
684 "b[0])*compare_vec4(a[1], b[1]); }\n"
685 "mediump float compare_mat3x2 (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], "
686 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n"
687 "mediump float compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], "
688 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n"
689 "mediump float compare_mat3x4 (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], "
690 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n"
691 "mediump float compare_mat4x2 (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], "
692 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n"
693 "mediump float compare_mat4x3 (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], "
694 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n"
695 "mediump float compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], "
696 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n"
697 "mediump float compare_int (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n"
698 "mediump float compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n"
699 "mediump float compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n"
700 "mediump float compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n"
701 "mediump float compare_uint (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n"
702 "mediump float compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n"
703 "mediump float compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n"
704 "mediump float compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n"
705 "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }\n"
706 "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }\n"
707 "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }\n"
708 "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }\n";
714 Indent(int level_) : level(level_)
719 std::ostream& operator<<(std::ostream& str, const Indent& indent)
721 for (int i = 0; i < indent.level; i++)
726 void generateDeclaration(std::ostringstream& src, const VarType& type, const char* name, int indentLevel,
727 deUint32 unusedHints);
728 void generateDeclaration(std::ostringstream& src, const Uniform& uniform, int indentLevel);
729 void generateDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
731 void generateLocalDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
732 void generateFullDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
734 void generateDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel)
736 DE_ASSERT(structType.getTypeName() != DE_NULL);
737 generateFullDeclaration(src, structType, indentLevel);
741 void generateFullDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel)
744 if (structType.getTypeName())
745 src << " " << structType.getTypeName();
746 src << "\n" << Indent(indentLevel) << "{\n";
748 for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
750 src << Indent(indentLevel + 1);
751 generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1,
752 memberIter->getFlags() & UNUSED_BOTH);
755 src << Indent(indentLevel) << "}";
758 void generateLocalDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel)
760 if (structType.getTypeName() == DE_NULL)
761 generateFullDeclaration(src, structType, indentLevel);
763 src << structType.getTypeName();
766 void generateDeclaration(std::ostringstream& src, const VarType& type, const char* name, int indentLevel,
767 deUint32 unusedHints)
769 deUint32 flags = type.getFlags();
771 if ((flags & LAYOUT_MASK) != 0)
772 src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK) << ") ";
774 if ((flags & PRECISION_MASK) != 0)
775 src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
777 if (type.isBasicType())
778 src << glu::getDataTypeName(type.getBasicType()) << " " << name;
779 else if (type.isArrayType())
781 std::vector<int> arraySizes;
782 const VarType* curType = &type;
783 while (curType->isArrayType())
785 arraySizes.push_back(curType->getArraySize());
786 curType = &curType->getElementType();
789 if (curType->isBasicType())
791 if ((curType->getFlags() & PRECISION_MASK) != 0)
792 src << PrecisionFlagsFmt(curType->getFlags() & PRECISION_MASK) << " ";
793 src << glu::getDataTypeName(curType->getBasicType());
797 DE_ASSERT(curType->isStructType());
798 generateLocalDeclaration(src, curType->getStruct(), indentLevel + 1);
803 for (std::vector<int>::const_reverse_iterator sizeIter = arraySizes.rbegin(); sizeIter != arraySizes.rend();
805 src << "[" << *sizeIter << "]";
809 generateLocalDeclaration(src, type.getStruct(), indentLevel + 1);
815 // Print out unused hints.
816 if (unusedHints != 0)
817 src << " // unused in "
818 << (unusedHints == UNUSED_BOTH ?
820 unusedHints == UNUSED_VERTEX ? "vertex shader" :
821 unusedHints == UNUSED_FRAGMENT ? "fragment shader" : "???");
826 void generateDeclaration(std::ostringstream& src, const Uniform& uniform, int indentLevel)
828 if ((uniform.getFlags() & LAYOUT_MASK) != 0)
829 src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
831 generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH);
834 void generateDeclaration(std::ostringstream& src, const UniformBlock& block)
836 if ((block.getFlags() & LAYOUT_MASK) != 0)
837 src << "layout(" << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ") ";
839 src << "uniform " << block.getBlockName();
842 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
845 generateDeclaration(src, *uniformIter, 1 /* indent level */);
850 if (block.getInstanceName() != DE_NULL)
852 src << " " << block.getInstanceName();
854 src << "[" << block.getArraySize() << "]";
857 DE_ASSERT(!block.isArray());
862 void generateValueSrc(std::ostringstream& src, const UniformLayoutEntry& entry, const void* basePtr, int elementNdx)
864 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
865 int scalarSize = glu::getDataTypeScalarSize(entry.type);
866 bool isArray = entry.size > 1;
867 const deUint8* elemPtr = (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
868 const int compSize = sizeof(deUint32);
871 src << glu::getDataTypeName(entry.type) << "(";
873 if (glu::isDataTypeMatrix(entry.type))
875 int numRows = glu::getDataTypeMatrixNumRows(entry.type);
876 int numCols = glu::getDataTypeMatrixNumColumns(entry.type);
878 DE_ASSERT(scalarType == glu::TYPE_FLOAT);
880 // Constructed in column-wise order.
881 for (int colNdx = 0; colNdx < numCols; colNdx++)
883 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
885 const deUint8* compPtr = elemPtr + (entry.isRowMajor ? rowNdx * entry.matrixStride + colNdx * compSize :
886 colNdx * entry.matrixStride + rowNdx * compSize);
888 if (colNdx > 0 || rowNdx > 0)
891 src << de::floatToString(*((const float*)compPtr), 1);
897 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
899 const deUint8* compPtr = elemPtr + scalarNdx * compSize;
906 case glu::TYPE_FLOAT:
907 src << de::floatToString(*((const float*)compPtr), 1);
910 src << *((const int*)compPtr);
913 src << *((const deUint32*)compPtr) << "u";
916 src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");
928 void generateCompareSrc(std::ostringstream& src, const char* resultVar, const VarType& type, const char* srcName,
929 const char* apiName, const UniformLayout& layout, const void* basePtr, deUint32 unusedMask)
931 if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
933 // Basic type or array of basic types.
934 bool isArray = type.isArrayType();
935 glu::DataType elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType();
936 const char* typeName = glu::getDataTypeName(elementType);
937 std::string fullApiName = string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
938 int uniformNdx = layout.getUniformIndex(fullApiName.c_str());
939 const UniformLayoutEntry& entry = layout.uniforms[uniformNdx];
943 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
945 src << "\tresult *= compare_" << typeName << "(" << srcName << "[" << elemNdx << "], ";
946 generateValueSrc(src, entry, basePtr, elemNdx);
952 src << "\tresult *= compare_" << typeName << "(" << srcName << ", ";
953 generateValueSrc(src, entry, basePtr, 0);
957 else if (type.isArrayType())
959 const VarType& elementType = type.getElementType();
960 DE_ASSERT(!elementType.isArrayType());
962 for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
964 std::string op = string("[") + de::toString(elementNdx) + "]";
965 generateCompareSrc(src, resultVar, elementType, (string(srcName) + op).c_str(),
966 (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
971 DE_ASSERT(type.isStructType());
973 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
976 if (memberIter->getFlags() & unusedMask)
977 continue; // Skip member.
979 string op = string(".") + memberIter->getName();
980 generateCompareSrc(src, resultVar, memberIter->getType(), (string(srcName) + op).c_str(),
981 (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
986 void generateCompareSrc(std::ostringstream& src, const char* resultVar, const ShaderInterface& interface,
987 const UniformLayout& layout, const std::map<int, void*>& blockPointers, bool isVertex)
989 deUint32 unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
991 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
993 const UniformBlock& block = interface.getUniformBlock(blockNdx);
995 if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
998 bool hasInstanceName = block.getInstanceName() != DE_NULL;
999 bool isArray = block.isArray();
1000 int numInstances = isArray ? block.getArraySize() : 1;
1001 std::string apiPrefix = hasInstanceName ? string(block.getBlockName()) + "." : string("");
1003 DE_ASSERT(!isArray || hasInstanceName);
1005 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1007 std::string instancePostfix = isArray ? string("[") + de::toString(instanceNdx) + "]" : string("");
1008 std::string blockInstanceName = block.getBlockName() + instancePostfix;
1009 std::string srcPrefix =
1010 hasInstanceName ? string(block.getInstanceName()) + instancePostfix + "." : string("");
1011 int activeBlockNdx = layout.getBlockIndex(blockInstanceName.c_str());
1012 void* basePtr = blockPointers.find(activeBlockNdx)->second;
1014 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
1016 const Uniform& uniform = *uniformIter;
1018 if (uniform.getFlags() & unusedMask)
1019 continue; // Don't read from that uniform.
1021 generateCompareSrc(src, resultVar, uniform.getType(), (srcPrefix + uniform.getName()).c_str(),
1022 (apiPrefix + uniform.getName()).c_str(), layout, basePtr, unusedMask);
1028 void generateVertexShader(std::ostringstream& src, glu::GLSLVersion glslVersion, const ShaderInterface& interface,
1029 const UniformLayout& layout, const std::map<int, void*>& blockPointers)
1031 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
1032 de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
1034 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1035 src << "in highp vec4 a_position;\n";
1036 src << "out mediump float v_vtxResult;\n";
1039 std::vector<const StructType*> namedStructs;
1040 interface.getNamedStructs(namedStructs);
1041 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin();
1042 structIter != namedStructs.end(); structIter++)
1043 generateDeclaration(src, **structIter, 0);
1045 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1047 const UniformBlock& block = interface.getUniformBlock(blockNdx);
1048 if (block.getFlags() & DECLARE_VERTEX)
1049 generateDeclaration(src, block);
1052 // Comparison utilities.
1053 src << "\n" << s_compareFuncs;
1056 "void main (void)\n"
1058 " gl_Position = a_position;\n"
1059 " mediump float result = 1.0;\n";
1062 generateCompareSrc(src, "result", interface, layout, blockPointers, true);
1064 src << " v_vtxResult = result;\n"
1068 void generateFragmentShader(std::ostringstream& src, glu::GLSLVersion glslVersion, const ShaderInterface& interface,
1069 const UniformLayout& layout, const std::map<int, void*>& blockPointers)
1071 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
1072 de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
1074 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1075 src << "in mediump float v_vtxResult;\n";
1076 src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1079 std::vector<const StructType*> namedStructs;
1080 interface.getNamedStructs(namedStructs);
1081 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin();
1082 structIter != namedStructs.end(); structIter++)
1083 generateDeclaration(src, **structIter, 0);
1085 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1087 const UniformBlock& block = interface.getUniformBlock(blockNdx);
1088 if (block.getFlags() & DECLARE_FRAGMENT)
1089 generateDeclaration(src, block);
1092 // Comparison utilities.
1093 src << "\n" << s_compareFuncs;
1096 "void main (void)\n"
1098 " mediump float result = 1.0;\n";
1101 generateCompareSrc(src, "result", interface, layout, blockPointers, false);
1103 src << " dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
1107 void getGLUniformLayout(const glw::Functions& gl, UniformLayout& layout, deUint32 program)
1109 int numActiveUniforms = 0;
1110 int numActiveBlocks = 0;
1112 gl.getProgramiv(program, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
1113 gl.getProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveBlocks);
1115 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of uniforms and uniform blocks");
1118 layout.blocks.resize(numActiveBlocks);
1119 for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++)
1121 BlockLayoutEntry& entry = layout.blocks[blockNdx];
1124 int numBlockUniforms;
1126 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
1127 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLen);
1128 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numBlockUniforms);
1130 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
1132 // \note Some implementations incorrectly return 0 as name length even though the length should include null terminator.
1133 std::vector<char> nameBuf(nameLen > 0 ? nameLen : 1);
1134 gl.getActiveUniformBlockName(program, (deUint32)blockNdx, (glw::GLsizei)nameBuf.size(), DE_NULL, &nameBuf[0]);
1136 entry.name = std::string(&nameBuf[0]);
1138 entry.activeUniformIndices.resize(numBlockUniforms);
1140 if (numBlockUniforms > 0)
1141 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
1142 &entry.activeUniformIndices[0]);
1144 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
1147 if (numActiveUniforms > 0)
1150 std::vector<deUint32> uniformIndices(numActiveUniforms);
1151 for (int i = 0; i < numActiveUniforms; i++)
1152 uniformIndices[i] = (deUint32)i;
1154 std::vector<int> types(numActiveUniforms);
1155 std::vector<int> sizes(numActiveUniforms);
1156 std::vector<int> nameLengths(numActiveUniforms);
1157 std::vector<int> blockIndices(numActiveUniforms);
1158 std::vector<int> offsets(numActiveUniforms);
1159 std::vector<int> arrayStrides(numActiveUniforms);
1160 std::vector<int> matrixStrides(numActiveUniforms);
1161 std::vector<int> rowMajorFlags(numActiveUniforms);
1164 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_TYPE,
1166 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_SIZE,
1168 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_NAME_LENGTH,
1170 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_BLOCK_INDEX,
1172 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_OFFSET,
1174 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1175 GL_UNIFORM_ARRAY_STRIDE, &arrayStrides[0]);
1176 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1177 GL_UNIFORM_MATRIX_STRIDE, &matrixStrides[0]);
1178 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1179 GL_UNIFORM_IS_ROW_MAJOR, &rowMajorFlags[0]);
1181 GLU_EXPECT_NO_ERROR(gl.getError(), "Active uniform query failed");
1183 // Translate to LayoutEntries
1184 layout.uniforms.resize(numActiveUniforms);
1185 for (int uniformNdx = 0; uniformNdx < numActiveUniforms; uniformNdx++)
1187 UniformLayoutEntry& entry = layout.uniforms[uniformNdx];
1188 std::vector<char> nameBuf(nameLengths[uniformNdx]);
1189 glw::GLsizei nameLen = 0;
1191 deUint32 type = GL_NONE;
1193 gl.getActiveUniform(program, (deUint32)uniformNdx, (glw::GLsizei)nameBuf.size(), &nameLen, &size, &type,
1196 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform name query failed");
1198 // \note glGetActiveUniform() returns length without \0 and glGetActiveUniformsiv() with \0
1199 if (nameLen + 1 != nameLengths[uniformNdx] || size != sizes[uniformNdx] ||
1200 type != (deUint32)types[uniformNdx])
1201 TCU_FAIL("Values returned by glGetActiveUniform() don't match with values queried with "
1202 "glGetActiveUniformsiv().");
1204 entry.name = std::string(&nameBuf[0]);
1205 entry.type = glu::getDataTypeFromGLType(types[uniformNdx]);
1206 entry.size = sizes[uniformNdx];
1207 entry.blockNdx = blockIndices[uniformNdx];
1208 entry.offset = offsets[uniformNdx];
1209 entry.arrayStride = arrayStrides[uniformNdx];
1210 entry.matrixStride = matrixStrides[uniformNdx];
1211 entry.isRowMajor = rowMajorFlags[uniformNdx] != GL_FALSE;
1216 void copyUniformData(const UniformLayoutEntry& dstEntry, void* dstBlockPtr, const UniformLayoutEntry& srcEntry,
1217 const void* srcBlockPtr)
1219 deUint8* dstBasePtr = (deUint8*)dstBlockPtr + dstEntry.offset;
1220 const deUint8* srcBasePtr = (const deUint8*)srcBlockPtr + srcEntry.offset;
1222 DE_ASSERT(dstEntry.size <= srcEntry.size);
1223 DE_ASSERT(dstEntry.type == srcEntry.type);
1225 int scalarSize = glu::getDataTypeScalarSize(dstEntry.type);
1226 bool isMatrix = glu::isDataTypeMatrix(dstEntry.type);
1227 const int compSize = sizeof(deUint32);
1229 for (int elementNdx = 0; elementNdx < dstEntry.size; elementNdx++)
1231 deUint8* dstElemPtr = dstBasePtr + elementNdx * dstEntry.arrayStride;
1232 const deUint8* srcElemPtr = srcBasePtr + elementNdx * srcEntry.arrayStride;
1236 int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
1237 int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
1239 for (int colNdx = 0; colNdx < numCols; colNdx++)
1241 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1243 deUint8* dstCompPtr =
1244 dstElemPtr + (dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize :
1245 colNdx * dstEntry.matrixStride + rowNdx * compSize);
1246 const deUint8* srcCompPtr =
1247 srcElemPtr + (srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize :
1248 colNdx * srcEntry.matrixStride + rowNdx * compSize);
1249 deMemcpy(dstCompPtr, srcCompPtr, compSize);
1254 deMemcpy(dstElemPtr, srcElemPtr, scalarSize * compSize);
1258 void copyUniformData(const UniformLayout& dstLayout, const std::map<int, void*>& dstBlockPointers,
1259 const UniformLayout& srcLayout, const std::map<int, void*>& srcBlockPointers)
1261 // \note Src layout is used as reference in case of activeUniforms happens to be incorrect in dstLayout blocks.
1262 int numBlocks = (int)srcLayout.blocks.size();
1264 for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1266 const BlockLayoutEntry& srcBlock = srcLayout.blocks[srcBlockNdx];
1267 const void* srcBlockPtr = srcBlockPointers.find(srcBlockNdx)->second;
1268 int dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name.c_str());
1269 void* dstBlockPtr = dstBlockNdx >= 0 ? dstBlockPointers.find(dstBlockNdx)->second : DE_NULL;
1271 if (dstBlockNdx < 0)
1274 for (vector<int>::const_iterator srcUniformNdxIter = srcBlock.activeUniformIndices.begin();
1275 srcUniformNdxIter != srcBlock.activeUniformIndices.end(); srcUniformNdxIter++)
1277 const UniformLayoutEntry& srcEntry = srcLayout.uniforms[*srcUniformNdxIter];
1278 int dstUniformNdx = dstLayout.getUniformIndex(srcEntry.name.c_str());
1280 if (dstUniformNdx < 0)
1283 copyUniformData(dstLayout.uniforms[dstUniformNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1288 } // anonymous (utilities)
1290 class UniformBufferManager
1293 UniformBufferManager(const glu::RenderContext& renderCtx);
1294 ~UniformBufferManager(void);
1296 deUint32 allocBuffer(void);
1299 UniformBufferManager(const UniformBufferManager& other);
1300 UniformBufferManager& operator=(const UniformBufferManager& other);
1302 const glu::RenderContext& m_renderCtx;
1303 std::vector<deUint32> m_buffers;
1306 UniformBufferManager::UniformBufferManager(const glu::RenderContext& renderCtx) : m_renderCtx(renderCtx)
1310 UniformBufferManager::~UniformBufferManager(void)
1312 if (!m_buffers.empty())
1313 m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
1316 deUint32 UniformBufferManager::allocBuffer(void)
1320 m_buffers.reserve(m_buffers.size() + 1);
1321 m_renderCtx.getFunctions().genBuffers(1, &buf);
1322 GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate uniform buffer");
1323 m_buffers.push_back(buf);
1332 // UniformBlockCase.
1334 UniformBlockCase::UniformBlockCase(Context& context, const char* name, const char* description,
1335 glu::GLSLVersion glslVersion, BufferMode bufferMode)
1336 : TestCase(context, name, description), m_glslVersion(glslVersion), m_bufferMode(bufferMode)
1338 // \todo [2013-05-25 pyry] Support other versions as well.
1339 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_330);
1342 UniformBlockCase::~UniformBlockCase(void)
1346 UniformBlockCase::IterateResult UniformBlockCase::iterate(void)
1348 TestLog& log = m_testCtx.getLog();
1349 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1350 UniformLayout refLayout; //!< std140 layout.
1351 vector<deUint8> data; //!< Data.
1352 map<int, void*> blockPointers; //!< Reference block pointers.
1354 // Initialize result to pass.
1355 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1357 // Compute reference layout.
1358 computeStd140Layout(refLayout, m_interface);
1360 // Assign storage for reference values.
1363 for (vector<BlockLayoutEntry>::const_iterator blockIter = refLayout.blocks.begin();
1364 blockIter != refLayout.blocks.end(); blockIter++)
1365 totalSize += blockIter->size;
1366 data.resize(totalSize);
1368 // Pointers for each block.
1370 for (int blockNdx = 0; blockNdx < (int)refLayout.blocks.size(); blockNdx++)
1372 blockPointers[blockNdx] = &data[0] + curOffset;
1373 curOffset += refLayout.blocks[blockNdx].size;
1378 generateValues(refLayout, blockPointers, 1 /* seed */);
1380 // Generate shaders and build program.
1381 std::ostringstream vtxSrc;
1382 std::ostringstream fragSrc;
1384 generateVertexShader(vtxSrc, m_glslVersion, m_interface, refLayout, blockPointers);
1385 generateFragmentShader(fragSrc, m_glslVersion, m_interface, refLayout, blockPointers);
1387 glu::ShaderProgram program(m_context.getRenderContext(),
1388 glu::makeVtxFragSources(vtxSrc.str().c_str(), fragSrc.str().c_str()));
1391 if (!program.isOk())
1394 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
1398 // Query layout from GL.
1399 UniformLayout glLayout;
1400 getGLUniformLayout(gl, glLayout, program.getProgram());
1402 // Print layout to log.
1403 log << TestLog::Section("ActiveUniformBlocks", "Active Uniform Blocks");
1404 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
1405 log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage;
1406 log << TestLog::EndSection;
1408 log << TestLog::Section("ActiveUniforms", "Active Uniforms");
1409 for (int uniformNdx = 0; uniformNdx < (int)glLayout.uniforms.size(); uniformNdx++)
1410 log << TestLog::Message << uniformNdx << ": " << glLayout.uniforms[uniformNdx] << TestLog::EndMessage;
1411 log << TestLog::EndSection;
1413 // Check that we can even try rendering with given layout.
1414 if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout))
1416 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout");
1417 return STOP; // It is not safe to use the given layout.
1420 // Verify all std140 blocks.
1421 if (!compareStd140Blocks(refLayout, glLayout))
1422 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 layout");
1424 // Verify all shared blocks - all uniforms should be active, and certain properties match.
1425 if (!compareSharedBlocks(refLayout, glLayout))
1426 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout");
1428 // Check consistency with index queries
1429 if (!checkIndexQueries(program.getProgram(), glLayout))
1430 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results");
1433 gl.useProgram(program.getProgram());
1435 // Assign binding points to all active uniform blocks.
1436 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
1438 deUint32 binding = (deUint32)blockNdx; // \todo [2012-01-25 pyry] Randomize order?
1439 gl.uniformBlockBinding(program.getProgram(), (deUint32)blockNdx, binding);
1442 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set uniform block bindings");
1444 // Allocate buffers, write data and bind to targets.
1445 UniformBufferManager bufferManager(m_context.getRenderContext());
1446 if (m_bufferMode == BUFFERMODE_PER_BLOCK)
1448 int numBlocks = (int)glLayout.blocks.size();
1449 vector<vector<deUint8> > glData(numBlocks);
1450 map<int, void*> glBlockPointers;
1452 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1454 glData[blockNdx].resize(glLayout.blocks[blockNdx].size);
1455 glBlockPointers[blockNdx] = &glData[blockNdx][0];
1458 copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
1460 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1462 deUint32 buffer = bufferManager.allocBuffer();
1463 deUint32 binding = (deUint32)blockNdx;
1465 gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
1466 gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData[blockNdx].size(), &glData[blockNdx][0],
1468 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
1470 gl.bindBufferBase(GL_UNIFORM_BUFFER, binding, buffer);
1471 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase(GL_UNIFORM_BUFFER) failed");
1476 DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE);
1480 int numBlocks = (int)glLayout.blocks.size();
1481 int bindingAlignment = m_context.getContextInfo().getInt(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
1482 map<int, int> glBlockOffsets;
1484 // Compute total size and offsets.
1486 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1488 if (bindingAlignment > 0)
1489 curOffset = deRoundUp32(curOffset, bindingAlignment);
1490 glBlockOffsets[blockNdx] = curOffset;
1491 curOffset += glLayout.blocks[blockNdx].size;
1493 totalSize = curOffset;
1495 // Assign block pointers.
1496 vector<deUint8> glData(totalSize);
1497 map<int, void*> glBlockPointers;
1499 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1500 glBlockPointers[blockNdx] = &glData[glBlockOffsets[blockNdx]];
1502 // Copy to gl format.
1503 copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
1505 // Allocate buffer and upload data.
1506 deUint32 buffer = bufferManager.allocBuffer();
1507 gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
1508 if (!glData.empty())
1509 gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData.size(), &glData[0], GL_STATIC_DRAW);
1511 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
1513 // Bind ranges to binding points.
1515 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1517 deUint32 binding = (deUint32)blockNdx;
1518 gl.bindBufferRange(GL_UNIFORM_BUFFER, binding, buffer, (glw::GLintptr)glBlockOffsets[blockNdx],
1519 (glw::GLsizeiptr)glLayout.blocks[blockNdx].size);
1520 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_UNIFORM_BUFFER) failed");
1521 curOffset += glLayout.blocks[blockNdx].size;
1525 bool renderOk = render(program);
1527 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed");
1532 bool UniformBlockCase::compareStd140Blocks(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const
1534 TestLog& log = m_testCtx.getLog();
1536 int numBlocks = m_interface.getNumUniformBlocks();
1538 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1540 const UniformBlock& block = m_interface.getUniformBlock(blockNdx);
1541 bool isArray = block.isArray();
1542 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
1543 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str());
1544 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str());
1545 bool isUsed = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
1547 if ((block.getFlags() & LAYOUT_STD140) == 0)
1548 continue; // Not std140 layout.
1550 DE_ASSERT(refBlockNdx >= 0);
1552 if (cmpBlockNdx < 0)
1554 // Not found, should it?
1557 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
1558 << TestLog::EndMessage;
1562 continue; // Skip block.
1565 const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx];
1566 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1568 // \todo [2012-01-24 pyry] Verify that activeUniformIndices is correct.
1569 // \todo [2012-01-24 pyry] Verify all instances.
1570 if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
1572 log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
1573 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
1574 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
1578 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
1579 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
1581 const UniformLayoutEntry& refEntry = refLayout.uniforms[*ndxIter];
1582 int cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str());
1584 if (cmpEntryNdx < 0)
1586 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
1591 const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
1593 if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
1594 refEntry.offset != cmpEntry.offset || refEntry.arrayStride != cmpEntry.arrayStride ||
1595 refEntry.matrixStride != cmpEntry.matrixStride || refEntry.isRowMajor != cmpEntry.isRowMajor)
1597 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
1598 << " expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
1599 << ", offset = " << refEntry.offset << ", array stride = " << refEntry.arrayStride
1600 << ", matrix stride = " << refEntry.matrixStride
1601 << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
1602 << " got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
1603 << ", offset = " << cmpEntry.offset << ", array stride = " << cmpEntry.arrayStride
1604 << ", matrix stride = " << cmpEntry.matrixStride
1605 << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
1614 bool UniformBlockCase::compareSharedBlocks(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const
1616 TestLog& log = m_testCtx.getLog();
1618 int numBlocks = m_interface.getNumUniformBlocks();
1620 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1622 const UniformBlock& block = m_interface.getUniformBlock(blockNdx);
1623 bool isArray = block.isArray();
1624 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
1625 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str());
1626 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str());
1627 bool isUsed = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
1629 if ((block.getFlags() & LAYOUT_SHARED) == 0)
1630 continue; // Not shared layout.
1632 DE_ASSERT(refBlockNdx >= 0);
1634 if (cmpBlockNdx < 0)
1636 // Not found, should it?
1639 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
1640 << TestLog::EndMessage;
1644 continue; // Skip block.
1647 const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx];
1648 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1650 if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
1652 log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
1653 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
1654 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
1658 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
1659 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
1661 const UniformLayoutEntry& refEntry = refLayout.uniforms[*ndxIter];
1662 int cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str());
1664 if (cmpEntryNdx < 0)
1666 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
1671 const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
1673 if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
1674 refEntry.isRowMajor != cmpEntry.isRowMajor)
1676 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
1677 << " expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
1678 << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
1679 << " got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
1680 << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
1689 bool UniformBlockCase::compareTypes(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const
1691 TestLog& log = m_testCtx.getLog();
1693 int numBlocks = m_interface.getNumUniformBlocks();
1695 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1697 const UniformBlock& block = m_interface.getUniformBlock(blockNdx);
1698 bool isArray = block.isArray();
1699 int numInstances = isArray ? block.getArraySize() : 1;
1701 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1703 std::ostringstream instanceName;
1705 instanceName << block.getBlockName();
1707 instanceName << "[" << instanceNdx << "]";
1709 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str());
1711 if (cmpBlockNdx < 0)
1714 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1716 for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeUniformIndices.begin();
1717 ndxIter != cmpBlockLayout.activeUniformIndices.end(); ndxIter++)
1719 const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[*ndxIter];
1720 int refEntryNdx = refLayout.getUniformIndex(cmpEntry.name.c_str());
1722 if (refEntryNdx < 0)
1724 log << TestLog::Message << "Error: Uniform '" << cmpEntry.name << "' not found in reference layout"
1725 << TestLog::EndMessage;
1730 const UniformLayoutEntry& refEntry = refLayout.uniforms[refEntryNdx];
1732 // \todo [2012-11-26 pyry] Should we check other properties as well?
1733 if (refEntry.type != cmpEntry.type)
1735 log << TestLog::Message << "Error: Uniform type mismatch in '" << refEntry.name << "':\n"
1736 << " expected: " << glu::getDataTypeName(refEntry.type) << "\n"
1737 << " got: " << glu::getDataTypeName(cmpEntry.type) << TestLog::EndMessage;
1747 bool UniformBlockCase::checkLayoutIndices(const UniformLayout& layout) const
1749 TestLog& log = m_testCtx.getLog();
1750 int numUniforms = (int)layout.uniforms.size();
1751 int numBlocks = (int)layout.blocks.size();
1754 // Check uniform block indices.
1755 for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
1757 const UniformLayoutEntry& uniform = layout.uniforms[uniformNdx];
1759 if (uniform.blockNdx < 0 || !deInBounds32(uniform.blockNdx, 0, numBlocks))
1761 log << TestLog::Message << "Error: Invalid block index in uniform '" << uniform.name << "'"
1762 << TestLog::EndMessage;
1767 // Check active uniforms.
1768 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1770 const BlockLayoutEntry& block = layout.blocks[blockNdx];
1772 for (vector<int>::const_iterator uniformIter = block.activeUniformIndices.begin();
1773 uniformIter != block.activeUniformIndices.end(); uniformIter++)
1775 if (!deInBounds32(*uniformIter, 0, numUniforms))
1777 log << TestLog::Message << "Error: Invalid active uniform index " << *uniformIter << " in block '"
1778 << block.name << "'" << TestLog::EndMessage;
1787 bool UniformBlockCase::checkLayoutBounds(const UniformLayout& layout) const
1789 TestLog& log = m_testCtx.getLog();
1790 int numUniforms = (int)layout.uniforms.size();
1793 for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
1795 const UniformLayoutEntry& uniform = layout.uniforms[uniformNdx];
1797 if (uniform.blockNdx < 0)
1800 const BlockLayoutEntry& block = layout.blocks[uniform.blockNdx];
1801 bool isMatrix = glu::isDataTypeMatrix(uniform.type);
1802 int numVecs = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumRows(uniform.type) :
1803 glu::getDataTypeMatrixNumColumns(uniform.type)) :
1805 int numComps = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumColumns(uniform.type) :
1806 glu::getDataTypeMatrixNumRows(uniform.type)) :
1807 glu::getDataTypeScalarSize(uniform.type);
1808 int numElements = uniform.size;
1809 const int compSize = sizeof(deUint32);
1810 int vecSize = numComps * compSize;
1815 // For negative strides.
1816 minOffset = de::min(minOffset, (numVecs - 1) * uniform.matrixStride);
1817 minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride);
1818 minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride);
1820 maxOffset = de::max(maxOffset, vecSize);
1821 maxOffset = de::max(maxOffset, (numVecs - 1) * uniform.matrixStride + vecSize);
1822 maxOffset = de::max(maxOffset, (numElements - 1) * uniform.arrayStride + vecSize);
1823 maxOffset = de::max(maxOffset,
1824 (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride + vecSize);
1826 if (uniform.offset + minOffset < 0 || uniform.offset + maxOffset > block.size)
1828 log << TestLog::Message << "Error: Uniform '" << uniform.name << "' out of block bounds"
1829 << TestLog::EndMessage;
1837 bool UniformBlockCase::checkIndexQueries(deUint32 program, const UniformLayout& layout) const
1839 tcu::TestLog& log = m_testCtx.getLog();
1840 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1843 // \note Spec mandates that uniform blocks are assigned consecutive locations from 0
1844 // to ACTIVE_UNIFORM_BLOCKS. BlockLayoutEntries are stored in that order in UniformLayout.
1845 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1847 const BlockLayoutEntry& block = layout.blocks[blockNdx];
1848 const int queriedNdx = gl.getUniformBlockIndex(program, block.name.c_str());
1850 if (queriedNdx != blockNdx)
1852 log << TestLog::Message << "ERROR: glGetUniformBlockIndex(" << block.name << ") returned " << queriedNdx
1853 << ", expected " << blockNdx << "!" << TestLog::EndMessage;
1857 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()");
1863 bool UniformBlockCase::render(glu::ShaderProgram& program) const
1865 tcu::TestLog& log = m_testCtx.getLog();
1866 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1867 de::Random rnd(deStringHash(getName()));
1868 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
1869 const int viewportW = de::min(renderTarget.getWidth(), 128);
1870 const int viewportH = de::min(renderTarget.getHeight(), 128);
1871 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - viewportW);
1872 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - viewportH);
1876 const float position[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f,
1877 +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f };
1878 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
1880 gl.viewport(viewportX, viewportY, viewportW, viewportH);
1882 glu::VertexArrayBinding posArray = glu::va::Float("a_position", 4, 4, 0, &position[0]);
1883 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posArray,
1884 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1885 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1888 // Verify that all pixels are white.
1890 tcu::Surface pixels(viewportW, viewportH);
1891 int numFailedPixels = 0;
1893 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, pixels.getAccess());
1894 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
1896 for (int y = 0; y < pixels.getHeight(); y++)
1898 for (int x = 0; x < pixels.getWidth(); x++)
1900 if (pixels.getPixel(x, y) != tcu::RGBA::white())
1901 numFailedPixels += 1;
1905 if (numFailedPixels > 0)
1907 log << TestLog::Image("Image", "Rendered image", pixels);
1908 log << TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels"
1909 << TestLog::EndMessage;
1912 return numFailedPixels == 0;