1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Uniform block case.
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktUniformBlockCase.hpp"
27
28 #include "vkPrograms.hpp"
29
30 #include "gluVarType.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuSurface.hpp"
33 #include "deInt32.h"
34 #include "deRandom.hpp"
35 #include "deStringUtil.hpp"
36
37 #include "tcuTextureUtil.hpp"
38 #include "deSharedPtr.hpp"
39 #include "tcuFloat.hpp"
40
41 #include "vkMemUtil.hpp"
42 #include "vkQueryUtil.hpp"
43 #include "vkTypeUtil.hpp"
44 #include "vkRef.hpp"
45 #include "vkRefUtil.hpp"
46 #include "vkBuilderUtil.hpp"
47 #include "vkCmdUtil.hpp"
48 #include "vkObjUtil.hpp"
49 #include "vkImageUtil.hpp"
50
51 #include <map>
52 #include <set>
53
54 namespace vkt
55 {
56 namespace ubo
57 {
58
59 using namespace vk;
60
61 // VarType implementation.
62
VarType(void)63 VarType::VarType(void) : m_type(TYPE_LAST), m_flags(0)
64 {
65 }
66
VarType(const VarType & other)67 VarType::VarType(const VarType &other) : m_type(TYPE_LAST), m_flags(0)
68 {
69 *this = other;
70 }
71
VarType(glu::DataType basicType,uint32_t flags)72 VarType::VarType(glu::DataType basicType, uint32_t flags) : m_type(TYPE_BASIC), m_flags(flags)
73 {
74 m_data.basicType = basicType;
75 }
76
VarType(const VarType & elementType,int arraySize)77 VarType::VarType(const VarType &elementType, int arraySize) : m_type(TYPE_ARRAY), m_flags(0)
78 {
79 m_data.array.size = arraySize;
80 m_data.array.elementType = new VarType(elementType);
81 }
82
VarType(const StructType * structPtr,uint32_t flags)83 VarType::VarType(const StructType *structPtr, uint32_t flags) : m_type(TYPE_STRUCT), m_flags(flags)
84 {
85 m_data.structPtr = structPtr;
86 }
87
~VarType(void)88 VarType::~VarType(void)
89 {
90 if (m_type == TYPE_ARRAY)
91 delete m_data.array.elementType;
92 }
93
operator =(const VarType & other)94 VarType &VarType::operator=(const VarType &other)
95 {
96 if (this == &other)
97 return *this; // Self-assignment.
98
99 VarType *oldElementType = m_type == TYPE_ARRAY ? m_data.array.elementType : DE_NULL;
100
101 m_type = other.m_type;
102 m_flags = other.m_flags;
103 m_data = Data();
104
105 if (m_type == TYPE_ARRAY)
106 {
107 m_data.array.elementType = new VarType(*other.m_data.array.elementType);
108 m_data.array.size = other.m_data.array.size;
109 }
110 else
111 m_data = other.m_data;
112
113 delete oldElementType;
114
115 return *this;
116 }
117
118 // StructType implementation.
119
addMember(const std::string & name,const VarType & type,uint32_t flags)120 void StructType::addMember(const std::string &name, const VarType &type, uint32_t flags)
121 {
122 m_members.push_back(StructMember(name, type, flags));
123 }
124
125 // Uniform implementation.
126
Uniform(const std::string & name,const VarType & type,uint32_t flags)127 Uniform::Uniform(const std::string &name, const VarType &type, uint32_t flags)
128 : m_name(name)
129 , m_type(type)
130 , m_flags(flags)
131 {
132 }
133
134 // UniformBlock implementation.
135
UniformBlock(const std::string & blockName)136 UniformBlock::UniformBlock(const std::string &blockName) : m_blockName(blockName), m_arraySize(0), m_flags(0)
137 {
138 }
139
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)140 std::ostream &operator<<(std::ostream &stream, const BlockLayoutEntry &entry)
141 {
142 stream << entry.name << " { name = " << entry.name << ", size = " << entry.size << ", activeUniformIndices = [";
143
144 for (std::vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end();
145 i++)
146 {
147 if (i != entry.activeUniformIndices.begin())
148 stream << ", ";
149 stream << *i;
150 }
151
152 stream << "] }";
153 return stream;
154 }
155
operator <<(std::ostream & stream,const UniformLayoutEntry & entry)156 std::ostream &operator<<(std::ostream &stream, const UniformLayoutEntry &entry)
157 {
158 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) << ", size = " << entry.size
159 << ", blockNdx = " << entry.blockNdx << ", offset = " << entry.offset
160 << ", arrayStride = " << entry.arrayStride << ", matrixStride = " << entry.matrixStride
161 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") << " }";
162 return stream;
163 }
164
getUniformLayoutIndex(int blockNdx,const std::string & name) const165 int UniformLayout::getUniformLayoutIndex(int blockNdx, const std::string &name) const
166 {
167 for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
168 {
169 if (blocks[uniforms[ndx].blockNdx].blockDeclarationNdx == blockNdx && uniforms[ndx].name == name)
170 return ndx;
171 }
172
173 return -1;
174 }
175
getBlockLayoutIndex(int blockNdx,int instanceNdx) const176 int UniformLayout::getBlockLayoutIndex(int blockNdx, int instanceNdx) const
177 {
178 for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
179 {
180 if (blocks[ndx].blockDeclarationNdx == blockNdx && blocks[ndx].instanceNdx == instanceNdx)
181 return ndx;
182 }
183
184 return -1;
185 }
186
187 // ShaderInterface implementation.
188
ShaderInterface(void)189 ShaderInterface::ShaderInterface(void)
190 {
191 }
192
~ShaderInterface(void)193 ShaderInterface::~ShaderInterface(void)
194 {
195 }
196
allocStruct(const std::string & name)197 StructType &ShaderInterface::allocStruct(const std::string &name)
198 {
199 m_structs.push_back(StructTypeSP(new StructType(name)));
200 return *m_structs.back();
201 }
202
203 struct StructNameEquals
204 {
205 std::string name;
206
StructNameEqualsvkt::ubo::StructNameEquals207 StructNameEquals(const std::string &name_) : name(name_)
208 {
209 }
210
operator ()vkt::ubo::StructNameEquals211 bool operator()(const StructTypeSP type) const
212 {
213 return type->hasTypeName() && name == type->getTypeName();
214 }
215 };
216
getNamedStructs(std::vector<const StructType * > & structs) const217 void ShaderInterface::getNamedStructs(std::vector<const StructType *> &structs) const
218 {
219 for (std::vector<StructTypeSP>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
220 {
221 if ((*i)->hasTypeName())
222 structs.push_back((*i).get());
223 }
224 }
225
allocBlock(const std::string & name)226 UniformBlock &ShaderInterface::allocBlock(const std::string &name)
227 {
228 m_uniformBlocks.push_back(UniformBlockSP(new UniformBlock(name)));
229 return *m_uniformBlocks.back();
230 }
231
usesBlockLayout(UniformFlags layoutFlag) const232 bool ShaderInterface::usesBlockLayout(UniformFlags layoutFlag) const
233 {
234 for (int i = 0, num_blocks = getNumUniformBlocks(); i < num_blocks; i++)
235 {
236 if (m_uniformBlocks[i]->getFlags() & layoutFlag)
237 return true;
238 }
239 return false;
240 }
241
242 namespace // Utilities
243 {
244
245 struct PrecisionFlagsFmt
246 {
247 uint32_t flags;
PrecisionFlagsFmtvkt::ubo::__anond31054860111::PrecisionFlagsFmt248 PrecisionFlagsFmt(uint32_t flags_) : flags(flags_)
249 {
250 }
251 };
252
operator <<(std::ostream & str,const PrecisionFlagsFmt & fmt)253 std::ostream &operator<<(std::ostream &str, const PrecisionFlagsFmt &fmt)
254 {
255 // Precision.
256 DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW | PRECISION_MEDIUM | PRECISION_HIGH)) <= 1);
257 str << (fmt.flags & PRECISION_LOW ? "lowp" :
258 fmt.flags & PRECISION_MEDIUM ? "mediump" :
259 fmt.flags & PRECISION_HIGH ? "highp" :
260 "");
261 return str;
262 }
263
264 struct LayoutFlagsFmt
265 {
266 uint32_t flags;
267 uint32_t offset;
LayoutFlagsFmtvkt::ubo::__anond31054860111::LayoutFlagsFmt268 LayoutFlagsFmt(uint32_t flags_, uint32_t offset_ = 0u) : flags(flags_), offset(offset_)
269 {
270 }
271 };
272
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)273 std::ostream &operator<<(std::ostream &str, const LayoutFlagsFmt &fmt)
274 {
275 static const struct
276 {
277 uint32_t bit;
278 const char *token;
279 } bitDesc[] = {
280 {LAYOUT_STD140, "std140"},
281 {LAYOUT_STD430, "std430"},
282 {LAYOUT_SCALAR, "scalar"},
283 {LAYOUT_ROW_MAJOR, "row_major"},
284 {LAYOUT_COLUMN_MAJOR, "column_major"},
285 {LAYOUT_OFFSET, "offset"},
286 };
287
288 uint32_t remBits = fmt.flags;
289 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
290 {
291 if (remBits & bitDesc[descNdx].bit)
292 {
293 if (remBits != fmt.flags)
294 str << ", ";
295 str << bitDesc[descNdx].token;
296 if (bitDesc[descNdx].bit == LAYOUT_OFFSET)
297 str << " = " << fmt.offset;
298 remBits &= ~bitDesc[descNdx].bit;
299 }
300 }
301 DE_ASSERT(remBits == 0);
302 return str;
303 }
304
305 // Layout computation.
306
getDataTypeByteSize(glu::DataType type)307 int getDataTypeByteSize(glu::DataType type)
308 {
309 if (deInRange32(type, glu::TYPE_UINT8, glu::TYPE_UINT8_VEC4) ||
310 deInRange32(type, glu::TYPE_INT8, glu::TYPE_INT8_VEC4))
311 {
312 return glu::getDataTypeScalarSize(type) * (int)sizeof(uint8_t);
313 }
314 if (deInRange32(type, glu::TYPE_UINT16, glu::TYPE_UINT16_VEC4) ||
315 deInRange32(type, glu::TYPE_INT16, glu::TYPE_INT16_VEC4) ||
316 deInRange32(type, glu::TYPE_FLOAT16, glu::TYPE_FLOAT16_VEC4))
317 {
318 return glu::getDataTypeScalarSize(type) * (int)sizeof(uint16_t);
319 }
320 else
321 {
322 return glu::getDataTypeScalarSize(type) * (int)sizeof(uint32_t);
323 }
324 }
325
getDataTypeByteAlignment(glu::DataType type)326 int getDataTypeByteAlignment(glu::DataType type)
327 {
328 switch (type)
329 {
330 case glu::TYPE_FLOAT:
331 case glu::TYPE_INT:
332 case glu::TYPE_UINT:
333 case glu::TYPE_BOOL:
334 return 1 * (int)sizeof(uint32_t);
335
336 case glu::TYPE_FLOAT_VEC2:
337 case glu::TYPE_INT_VEC2:
338 case glu::TYPE_UINT_VEC2:
339 case glu::TYPE_BOOL_VEC2:
340 return 2 * (int)sizeof(uint32_t);
341
342 case glu::TYPE_FLOAT_VEC3:
343 case glu::TYPE_INT_VEC3:
344 case glu::TYPE_UINT_VEC3:
345 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4
346
347 case glu::TYPE_FLOAT_VEC4:
348 case glu::TYPE_INT_VEC4:
349 case glu::TYPE_UINT_VEC4:
350 case glu::TYPE_BOOL_VEC4:
351 return 4 * (int)sizeof(uint32_t);
352
353 case glu::TYPE_UINT8:
354 case glu::TYPE_INT8:
355 return 1 * (int)sizeof(uint8_t);
356
357 case glu::TYPE_UINT8_VEC2:
358 case glu::TYPE_INT8_VEC2:
359 return 2 * (int)sizeof(uint8_t);
360
361 case glu::TYPE_UINT8_VEC3:
362 case glu::TYPE_INT8_VEC3: // Fall-through to vec4
363
364 case glu::TYPE_UINT8_VEC4:
365 case glu::TYPE_INT8_VEC4:
366 return 4 * (int)sizeof(uint8_t);
367
368 case glu::TYPE_UINT16:
369 case glu::TYPE_INT16:
370 case glu::TYPE_FLOAT16:
371 return 1 * (int)sizeof(uint16_t);
372
373 case glu::TYPE_UINT16_VEC2:
374 case glu::TYPE_INT16_VEC2:
375 case glu::TYPE_FLOAT16_VEC2:
376 return 2 * (int)sizeof(uint16_t);
377
378 case glu::TYPE_UINT16_VEC3:
379 case glu::TYPE_INT16_VEC3:
380 case glu::TYPE_FLOAT16_VEC3: // Fall-through to vec4
381
382 case glu::TYPE_UINT16_VEC4:
383 case glu::TYPE_INT16_VEC4:
384 case glu::TYPE_FLOAT16_VEC4:
385 return 4 * (int)sizeof(uint16_t);
386
387 default:
388 DE_ASSERT(false);
389 return 0;
390 }
391 }
392
getminUniformBufferOffsetAlignment(Context & ctx)393 int32_t getminUniformBufferOffsetAlignment(Context &ctx)
394 {
395 VkPhysicalDeviceProperties properties;
396 ctx.getInstanceInterface().getPhysicalDeviceProperties(ctx.getPhysicalDevice(), &properties);
397 VkDeviceSize align = properties.limits.minUniformBufferOffsetAlignment;
398 DE_ASSERT(align == (VkDeviceSize)(int32_t)align);
399 return (int32_t)align;
400 }
401
computeStd140BaseAlignment(const VarType & type,uint32_t layoutFlags)402 int computeStd140BaseAlignment(const VarType &type, uint32_t layoutFlags)
403 {
404 const int vec4Alignment = (int)sizeof(uint32_t) * 4;
405
406 if (type.isBasicType())
407 {
408 glu::DataType basicType = type.getBasicType();
409
410 if (glu::isDataTypeMatrix(basicType))
411 {
412 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
413 const int vecSize =
414 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
415 const int vecAlign = deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
416
417 return vecAlign;
418 }
419 else
420 return getDataTypeByteAlignment(basicType);
421 }
422 else if (type.isArrayType())
423 {
424 int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
425
426 // Round up to alignment of vec4
427 return deAlign32(elemAlignment, vec4Alignment);
428 }
429 else
430 {
431 DE_ASSERT(type.isStructType());
432
433 int maxBaseAlignment = 0;
434
435 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
436 memberIter != type.getStructPtr()->end(); memberIter++)
437 maxBaseAlignment =
438 de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
439
440 return deAlign32(maxBaseAlignment, vec4Alignment);
441 }
442 }
443
computeStd430BaseAlignment(const VarType & type,uint32_t layoutFlags)444 int computeStd430BaseAlignment(const VarType &type, uint32_t layoutFlags)
445 {
446 // Otherwise identical to std140 except that alignment of structures and arrays
447 // are not rounded up to alignment of vec4.
448
449 if (type.isBasicType())
450 {
451 glu::DataType basicType = type.getBasicType();
452
453 if (glu::isDataTypeMatrix(basicType))
454 {
455 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
456 const int vecSize =
457 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
458 const int vecAlign = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
459 return vecAlign;
460 }
461 else
462 return getDataTypeByteAlignment(basicType);
463 }
464 else if (type.isArrayType())
465 {
466 return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
467 }
468 else
469 {
470 DE_ASSERT(type.isStructType());
471
472 int maxBaseAlignment = 0;
473
474 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
475 memberIter != type.getStructPtr()->end(); memberIter++)
476 maxBaseAlignment =
477 de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
478
479 return maxBaseAlignment;
480 }
481 }
482
computeRelaxedBlockBaseAlignment(const VarType & type,uint32_t layoutFlags)483 int computeRelaxedBlockBaseAlignment(const VarType &type, uint32_t layoutFlags)
484 {
485 if (type.isBasicType())
486 {
487 glu::DataType basicType = type.getBasicType();
488
489 if (glu::isDataTypeVector(basicType))
490 return getDataTypeByteAlignment(glu::getDataTypeScalarType(basicType));
491
492 if (glu::isDataTypeMatrix(basicType))
493 {
494 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
495 const int vecSize =
496 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
497 const int vecAlign = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
498 return vecAlign;
499 }
500 else
501 return getDataTypeByteAlignment(basicType);
502 }
503 else if (type.isArrayType())
504 return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
505 else
506 {
507 DE_ASSERT(type.isStructType());
508
509 int maxBaseAlignment = 0;
510 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
511 memberIter != type.getStructPtr()->end(); memberIter++)
512 maxBaseAlignment =
513 de::max(maxBaseAlignment, computeRelaxedBlockBaseAlignment(memberIter->getType(), layoutFlags));
514
515 return maxBaseAlignment;
516 }
517 }
518
computeScalarBlockAlignment(const VarType & type,uint32_t layoutFlags)519 int computeScalarBlockAlignment(const VarType &type, uint32_t layoutFlags)
520 {
521 if (type.isBasicType())
522 {
523 return getDataTypeByteAlignment(glu::getDataTypeScalarType(type.getBasicType()));
524 }
525 else if (type.isArrayType())
526 return computeScalarBlockAlignment(type.getElementType(), layoutFlags);
527 else
528 {
529 DE_ASSERT(type.isStructType());
530
531 int maxBaseAlignment = 0;
532 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
533 memberIter != type.getStructPtr()->end(); memberIter++)
534 maxBaseAlignment =
535 de::max(maxBaseAlignment, computeScalarBlockAlignment(memberIter->getType(), layoutFlags));
536
537 return maxBaseAlignment;
538 }
539 }
540
mergeLayoutFlags(uint32_t prevFlags,uint32_t newFlags)541 inline uint32_t mergeLayoutFlags(uint32_t prevFlags, uint32_t newFlags)
542 {
543 const uint32_t packingMask = LAYOUT_STD140 | LAYOUT_STD430 | LAYOUT_SCALAR;
544 const uint32_t matrixMask = LAYOUT_ROW_MAJOR | LAYOUT_COLUMN_MAJOR;
545
546 uint32_t mergedFlags = 0;
547
548 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
549 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
550
551 return mergedFlags;
552 }
553
554 //! Appends all child elements to layout, returns value that should be appended to offset.
computeReferenceLayout(UniformLayout & layout,int curBlockNdx,int baseOffset,const std::string & curPrefix,const VarType & type,uint32_t layoutFlags)555 int computeReferenceLayout(UniformLayout &layout, int curBlockNdx, int baseOffset, const std::string &curPrefix,
556 const VarType &type, uint32_t layoutFlags)
557 {
558 // HACK to make code match SSBO tests
559 const int LAYOUT_RELAXED = 0;
560 // Reference layout uses std140 rules by default. std430 rules are
561 // choosen only for blocks that have std140 layout.
562 const int baseAlignment = (layoutFlags & LAYOUT_SCALAR) != 0 ? computeScalarBlockAlignment(type, layoutFlags) :
563 (layoutFlags & LAYOUT_STD430) != 0 ? computeStd430BaseAlignment(type, layoutFlags) :
564 (layoutFlags & LAYOUT_RELAXED) != 0 ?
565 computeRelaxedBlockBaseAlignment(type, layoutFlags) :
566 computeStd140BaseAlignment(type, layoutFlags);
567 int curOffset = deAlign32(baseOffset, baseAlignment);
568 const int topLevelArraySize = 1; // Default values
569 const int topLevelArrayStride = 0;
570
571 if (type.isBasicType())
572 {
573 const glu::DataType basicType = type.getBasicType();
574 UniformLayoutEntry entry;
575
576 entry.name = curPrefix;
577 entry.type = basicType;
578 entry.arraySize = 1;
579 entry.arrayStride = 0;
580 entry.matrixStride = 0;
581 entry.topLevelArraySize = topLevelArraySize;
582 entry.topLevelArrayStride = topLevelArrayStride;
583 entry.blockNdx = curBlockNdx;
584
585 if (glu::isDataTypeMatrix(basicType))
586 {
587 // Array of vectors as specified in rules 5 & 7.
588 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
589 const int vecSize =
590 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
591 const glu::DataType vecType = glu::getDataTypeFloatVec(vecSize);
592 const int numVecs =
593 isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) : glu::getDataTypeMatrixNumColumns(basicType);
594 const int vecStride = (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment;
595
596 entry.offset = curOffset;
597 entry.matrixStride = vecStride;
598 entry.isRowMajor = isRowMajor;
599
600 curOffset += numVecs * entry.matrixStride;
601 }
602 else
603 {
604 if (!(layoutFlags & LAYOUT_SCALAR) && (layoutFlags & LAYOUT_RELAXED) && glu::isDataTypeVector(basicType) &&
605 (getDataTypeByteSize(basicType) <= 16 ?
606 curOffset / 16 != (curOffset + getDataTypeByteSize(basicType) - 1) / 16 :
607 curOffset % 16 != 0))
608 curOffset = deIntRoundToPow2(curOffset, 16);
609
610 // Scalar or vector.
611 entry.offset = curOffset;
612
613 curOffset += getDataTypeByteSize(basicType);
614 }
615
616 layout.uniforms.push_back(entry);
617 }
618 else if (type.isArrayType())
619 {
620 const VarType &elemType = type.getElementType();
621
622 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
623 {
624 // Array of scalars or vectors.
625 const glu::DataType elemBasicType = elemType.getBasicType();
626 const int stride = (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(elemBasicType) : baseAlignment;
627 UniformLayoutEntry entry;
628
629 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0]
630 entry.type = elemBasicType;
631 entry.blockNdx = curBlockNdx;
632 entry.offset = curOffset;
633 entry.arraySize = type.getArraySize();
634 entry.arrayStride = stride;
635 entry.matrixStride = 0;
636 entry.topLevelArraySize = topLevelArraySize;
637 entry.topLevelArrayStride = topLevelArrayStride;
638
639 curOffset += stride * type.getArraySize();
640
641 layout.uniforms.push_back(entry);
642 }
643 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
644 {
645 // Array of matrices.
646 const glu::DataType elemBasicType = elemType.getBasicType();
647 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
648 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) :
649 glu::getDataTypeMatrixNumRows(elemBasicType);
650 const glu::DataType vecType = glu::getDataTypeFloatVec(vecSize);
651 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) :
652 glu::getDataTypeMatrixNumColumns(elemBasicType);
653 const int vecStride = (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment;
654 UniformLayoutEntry entry;
655
656 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0]
657 entry.type = elemBasicType;
658 entry.blockNdx = curBlockNdx;
659 entry.offset = curOffset;
660 entry.arraySize = type.getArraySize();
661 entry.arrayStride = vecStride * numVecs;
662 entry.matrixStride = vecStride;
663 entry.isRowMajor = isRowMajor;
664 entry.topLevelArraySize = topLevelArraySize;
665 entry.topLevelArrayStride = topLevelArrayStride;
666
667 curOffset += entry.arrayStride * type.getArraySize();
668
669 layout.uniforms.push_back(entry);
670 }
671 else
672 {
673 DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
674
675 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
676 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset,
677 curPrefix + "[" + de::toString(elemNdx) + "]",
678 type.getElementType(), layoutFlags);
679 }
680 }
681 else
682 {
683 DE_ASSERT(type.isStructType());
684
685 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin();
686 memberIter != type.getStructPtr()->end(); memberIter++)
687 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(),
688 memberIter->getType(), layoutFlags);
689
690 if (!(layoutFlags & LAYOUT_SCALAR))
691 curOffset = deAlign32(curOffset, baseAlignment);
692 }
693
694 return curOffset - baseOffset;
695 }
696
computeReferenceLayout(UniformLayout & layout,const ShaderInterface & interface)697 void computeReferenceLayout(UniformLayout &layout, const ShaderInterface &interface)
698 {
699 int numUniformBlocks = interface.getNumUniformBlocks();
700
701 for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
702 {
703 const UniformBlock &block = interface.getUniformBlock(blockNdx);
704 bool hasInstanceName = block.hasInstanceName();
705 std::string blockPrefix = hasInstanceName ? (block.getBlockName() + ".") : "";
706 int curOffset = 0;
707 int activeBlockNdx = (int)layout.blocks.size();
708 int firstUniformNdx = (int)layout.uniforms.size();
709
710 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
711 {
712 const Uniform &uniform = *uniformIter;
713 curOffset +=
714 computeReferenceLayout(layout, activeBlockNdx, curOffset, blockPrefix + uniform.getName(),
715 uniform.getType(), mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
716 }
717
718 int uniformIndicesEnd = (int)layout.uniforms.size();
719 int blockSize = curOffset;
720 int numInstances = block.isArray() ? block.getArraySize() : 1;
721
722 // Create block layout entries for each instance.
723 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
724 {
725 // Allocate entry for instance.
726 layout.blocks.push_back(BlockLayoutEntry());
727 BlockLayoutEntry &blockEntry = layout.blocks.back();
728
729 blockEntry.name = block.getBlockName();
730 blockEntry.size = blockSize;
731 blockEntry.bindingNdx = blockNdx;
732 blockEntry.blockDeclarationNdx = blockNdx;
733 blockEntry.instanceNdx = instanceNdx;
734
735 // Compute active uniform set for block.
736 for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
737 blockEntry.activeUniformIndices.push_back(uniformNdx);
738
739 if (block.isArray())
740 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
741 }
742 }
743 }
744
745 // Value generator.
746
generateValue(const UniformLayoutEntry & entry,void * basePtr,de::Random & rnd)747 void generateValue(const UniformLayoutEntry &entry, void *basePtr, de::Random &rnd)
748 {
749 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
750 int scalarSize = glu::getDataTypeScalarSize(entry.type);
751 bool isMatrix = glu::isDataTypeMatrix(entry.type);
752 int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) :
753 glu::getDataTypeMatrixNumColumns(entry.type)) :
754 1;
755 int vecSize = scalarSize / numVecs;
756 bool isArray = entry.size > 1;
757 const size_t compSize = getDataTypeByteSize(scalarType);
758
759 using float16_ptr_t = std::add_pointer_t<tcu::float16_t>;
760
761 DE_ASSERT(scalarSize % numVecs == 0);
762
763 for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
764 {
765 uint8_t *elemPtr = (uint8_t *)basePtr + entry.offset + (isArray ? elemNdx * entry.arrayStride : 0);
766
767 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
768 {
769 uint8_t *vecPtr = elemPtr + (isMatrix ? vecNdx * entry.matrixStride : 0);
770
771 for (int compNdx = 0; compNdx < vecSize; compNdx++)
772 {
773 uint8_t *compPtr = vecPtr + compSize * compNdx;
774
775 switch (scalarType)
776 {
777 case glu::TYPE_FLOAT:
778 *((float *)compPtr) = (float)rnd.getInt(-9, 9);
779 break;
780 case glu::TYPE_INT:
781 *((int *)compPtr) = rnd.getInt(-9, 9);
782 break;
783 case glu::TYPE_UINT:
784 *((uint32_t *)compPtr) = (uint32_t)rnd.getInt(0, 9);
785 break;
786 case glu::TYPE_INT8:
787 *((int8_t *)compPtr) = (int8_t)rnd.getInt(-9, 9);
788 break;
789 case glu::TYPE_UINT8:
790 *((uint8_t *)compPtr) = (uint8_t)rnd.getInt(0, 9);
791 break;
792 case glu::TYPE_INT16:
793 *((int16_t *)compPtr) = (int16_t)rnd.getInt(-9, 9);
794 break;
795 case glu::TYPE_UINT16:
796 *((uint16_t *)compPtr) = (uint16_t)rnd.getInt(0, 9);
797 break;
798 case glu::TYPE_FLOAT16:
799 *reinterpret_cast<float16_ptr_t>(compPtr) = tcu::Float16((float)rnd.getInt(-9, 9)).bits();
800 break;
801 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
802 // interpreted as true but some implementations fail this.
803 case glu::TYPE_BOOL:
804 *((uint32_t *)compPtr) = rnd.getBool() ? rnd.getUint32() | 1u : 0u;
805 break;
806 default:
807 DE_ASSERT(false);
808 }
809 }
810 }
811 }
812 }
813
generateValues(const UniformLayout & layout,const std::map<int,void * > & blockPointers,uint32_t seed)814 void generateValues(const UniformLayout &layout, const std::map<int, void *> &blockPointers, uint32_t seed)
815 {
816 de::Random rnd(seed);
817 int numBlocks = (int)layout.blocks.size();
818
819 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
820 {
821 void *basePtr = blockPointers.find(blockNdx)->second;
822 int numEntries = (int)layout.blocks[blockNdx].activeUniformIndices.size();
823
824 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
825 {
826 const UniformLayoutEntry &entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
827 generateValue(entry, basePtr, rnd);
828 }
829 }
830 }
831
832 // Shader generator.
833
getCompareFuncForType(glu::DataType type)834 const char *getCompareFuncForType(glu::DataType type)
835 {
836 switch (type)
837 {
838 case glu::TYPE_FLOAT:
839 return "mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; "
840 "}\n";
841 case glu::TYPE_FLOAT_VEC2:
842 return "mediump float compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, "
843 "b.x)*compare_float(a.y, b.y); }\n";
844 case glu::TYPE_FLOAT_VEC3:
845 return "mediump float compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, "
846 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n";
847 case glu::TYPE_FLOAT_VEC4:
848 return "mediump float compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, "
849 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n";
850 case glu::TYPE_FLOAT_MAT2:
851 return "mediump float compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], "
852 "b[0])*compare_vec2(a[1], b[1]); }\n";
853 case glu::TYPE_FLOAT_MAT2X3:
854 return "mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], "
855 "b[0])*compare_vec3(a[1], b[1]); }\n";
856 case glu::TYPE_FLOAT_MAT2X4:
857 return "mediump float compare_mat2x4 (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], "
858 "b[0])*compare_vec4(a[1], b[1]); }\n";
859 case glu::TYPE_FLOAT_MAT3X2:
860 return "mediump float compare_mat3x2 (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], "
861 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n";
862 case glu::TYPE_FLOAT_MAT3:
863 return "mediump float compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], "
864 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n";
865 case glu::TYPE_FLOAT_MAT3X4:
866 return "mediump float compare_mat3x4 (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], "
867 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n";
868 case glu::TYPE_FLOAT_MAT4X2:
869 return "mediump float compare_mat4x2 (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], "
870 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n";
871 case glu::TYPE_FLOAT_MAT4X3:
872 return "mediump float compare_mat4x3 (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], "
873 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n";
874 case glu::TYPE_FLOAT_MAT4:
875 return "mediump float compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], "
876 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n";
877 case glu::TYPE_INT:
878 return "mediump float compare_int (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n";
879 case glu::TYPE_INT_VEC2:
880 return "mediump float compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n";
881 case glu::TYPE_INT_VEC3:
882 return "mediump float compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n";
883 case glu::TYPE_INT_VEC4:
884 return "mediump float compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n";
885 case glu::TYPE_UINT:
886 return "mediump float compare_uint (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n";
887 case glu::TYPE_UINT_VEC2:
888 return "mediump float compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n";
889 case glu::TYPE_UINT_VEC3:
890 return "mediump float compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n";
891 case glu::TYPE_UINT_VEC4:
892 return "mediump float compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n";
893 case glu::TYPE_BOOL:
894 return "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }\n";
895 case glu::TYPE_BOOL_VEC2:
896 return "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }\n";
897 case glu::TYPE_BOOL_VEC3:
898 return "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }\n";
899 case glu::TYPE_BOOL_VEC4:
900 return "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }\n";
901 case glu::TYPE_FLOAT16:
902 return "mediump float compare_float16_t(highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; "
903 "}\n";
904 case glu::TYPE_FLOAT16_VEC2:
905 return "mediump float compare_f16vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, "
906 "b.x)*compare_float(a.y, b.y); }\n";
907 case glu::TYPE_FLOAT16_VEC3:
908 return "mediump float compare_f16vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, "
909 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n";
910 case glu::TYPE_FLOAT16_VEC4:
911 return "mediump float compare_f16vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, "
912 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n";
913 case glu::TYPE_INT8:
914 return "mediump float compare_int8_t (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n";
915 case glu::TYPE_INT8_VEC2:
916 return "mediump float compare_i8vec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n";
917 case glu::TYPE_INT8_VEC3:
918 return "mediump float compare_i8vec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n";
919 case glu::TYPE_INT8_VEC4:
920 return "mediump float compare_i8vec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n";
921 case glu::TYPE_UINT8:
922 return "mediump float compare_uint8_t (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n";
923 case glu::TYPE_UINT8_VEC2:
924 return "mediump float compare_u8vec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n";
925 case glu::TYPE_UINT8_VEC3:
926 return "mediump float compare_u8vec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n";
927 case glu::TYPE_UINT8_VEC4:
928 return "mediump float compare_u8vec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n";
929 case glu::TYPE_INT16:
930 return "mediump float compare_int16_t (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n";
931 case glu::TYPE_INT16_VEC2:
932 return "mediump float compare_i16vec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n";
933 case glu::TYPE_INT16_VEC3:
934 return "mediump float compare_i16vec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n";
935 case glu::TYPE_INT16_VEC4:
936 return "mediump float compare_i16vec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n";
937 case glu::TYPE_UINT16:
938 return "mediump float compare_uint16_t (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n";
939 case glu::TYPE_UINT16_VEC2:
940 return "mediump float compare_u16vec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n";
941 case glu::TYPE_UINT16_VEC3:
942 return "mediump float compare_u16vec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n";
943 case glu::TYPE_UINT16_VEC4:
944 return "mediump float compare_u16vec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n";
945 default:
946 DE_ASSERT(false);
947 return DE_NULL;
948 }
949 }
950
getCompareDependencies(std::set<glu::DataType> & compareFuncs,glu::DataType basicType)951 void getCompareDependencies(std::set<glu::DataType> &compareFuncs, glu::DataType basicType)
952 {
953 switch (basicType)
954 {
955 case glu::TYPE_FLOAT_VEC2:
956 case glu::TYPE_FLOAT_VEC3:
957 case glu::TYPE_FLOAT_VEC4:
958 case glu::TYPE_FLOAT16_VEC2:
959 case glu::TYPE_FLOAT16_VEC3:
960 case glu::TYPE_FLOAT16_VEC4:
961 compareFuncs.insert(glu::TYPE_FLOAT);
962 compareFuncs.insert(basicType);
963 break;
964
965 case glu::TYPE_FLOAT_MAT2:
966 case glu::TYPE_FLOAT_MAT2X3:
967 case glu::TYPE_FLOAT_MAT2X4:
968 case glu::TYPE_FLOAT_MAT3X2:
969 case glu::TYPE_FLOAT_MAT3:
970 case glu::TYPE_FLOAT_MAT3X4:
971 case glu::TYPE_FLOAT_MAT4X2:
972 case glu::TYPE_FLOAT_MAT4X3:
973 case glu::TYPE_FLOAT_MAT4:
974 compareFuncs.insert(glu::TYPE_FLOAT);
975 compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
976 compareFuncs.insert(basicType);
977 break;
978
979 default:
980 compareFuncs.insert(basicType);
981 break;
982 }
983 }
984
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const VarType & type)985 void collectUniqueBasicTypes(std::set<glu::DataType> &basicTypes, const VarType &type)
986 {
987 if (type.isStructType())
988 {
989 for (StructType::ConstIterator iter = type.getStruct().begin(); iter != type.getStruct().end(); ++iter)
990 collectUniqueBasicTypes(basicTypes, iter->getType());
991 }
992 else if (type.isArrayType())
993 collectUniqueBasicTypes(basicTypes, type.getElementType());
994 else
995 {
996 DE_ASSERT(type.isBasicType());
997 basicTypes.insert(type.getBasicType());
998 }
999 }
1000
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const UniformBlock & uniformBlock)1001 void collectUniqueBasicTypes(std::set<glu::DataType> &basicTypes, const UniformBlock &uniformBlock)
1002 {
1003 for (UniformBlock::ConstIterator iter = uniformBlock.begin(); iter != uniformBlock.end(); ++iter)
1004 collectUniqueBasicTypes(basicTypes, iter->getType());
1005 }
1006
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const ShaderInterface & interface)1007 void collectUniqueBasicTypes(std::set<glu::DataType> &basicTypes, const ShaderInterface &interface)
1008 {
1009 for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
1010 collectUniqueBasicTypes(basicTypes, interface.getUniformBlock(ndx));
1011 }
1012
generateCompareFuncs(std::ostream & str,const ShaderInterface & interface)1013 void generateCompareFuncs(std::ostream &str, const ShaderInterface &interface)
1014 {
1015 std::set<glu::DataType> types;
1016 std::set<glu::DataType> compareFuncs;
1017
1018 // Collect unique basic types
1019 collectUniqueBasicTypes(types, interface);
1020
1021 // Set of compare functions required
1022 for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
1023 {
1024 getCompareDependencies(compareFuncs, *iter);
1025 }
1026
1027 for (int type = 0; type < glu::TYPE_LAST; ++type)
1028 {
1029 if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
1030 str << getCompareFuncForType(glu::DataType(type));
1031 }
1032 }
1033
1034 struct Indent
1035 {
1036 int level;
Indentvkt::ubo::__anond31054860111::Indent1037 Indent(int level_) : level(level_)
1038 {
1039 }
1040 };
1041
operator <<(std::ostream & str,const Indent & indent)1042 std::ostream &operator<<(std::ostream &str, const Indent &indent)
1043 {
1044 for (int i = 0; i < indent.level; i++)
1045 str << "\t";
1046 return str;
1047 }
1048
1049 void generateDeclaration(std::ostringstream &src, const VarType &type, const std::string &name, int indentLevel,
1050 uint32_t unusedHints, uint32_t flagsMask, uint32_t offset);
1051 void generateDeclaration(std::ostringstream &src, const Uniform &uniform, int indentLevel, uint32_t offset);
1052 void generateDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
1053
1054 void generateLocalDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
1055 void generateFullDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
1056
generateDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)1057 void generateDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
1058 {
1059 DE_ASSERT(structType.hasTypeName());
1060 generateFullDeclaration(src, structType, indentLevel);
1061 src << ";\n";
1062 }
1063
generateFullDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)1064 void generateFullDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
1065 {
1066 src << "struct";
1067 if (structType.hasTypeName())
1068 src << " " << structType.getTypeName();
1069 src << "\n" << Indent(indentLevel) << "{\n";
1070
1071 for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
1072 {
1073 src << Indent(indentLevel + 1);
1074 generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1,
1075 memberIter->getFlags() & UNUSED_BOTH, ~LAYOUT_OFFSET, 0u);
1076 }
1077
1078 src << Indent(indentLevel) << "}";
1079 }
1080
generateLocalDeclaration(std::ostringstream & src,const StructType & structType,int)1081 void generateLocalDeclaration(std::ostringstream &src, const StructType &structType, int /* indentLevel */)
1082 {
1083 src << structType.getTypeName();
1084 }
1085
generateLayoutAndPrecisionDeclaration(std::ostringstream & src,uint32_t flags,uint32_t offset)1086 void generateLayoutAndPrecisionDeclaration(std::ostringstream &src, uint32_t flags, uint32_t offset)
1087 {
1088 if ((flags & LAYOUT_MASK) != 0)
1089 src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK, offset) << ") ";
1090
1091 if ((flags & PRECISION_MASK) != 0)
1092 src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
1093 }
1094
generateDeclaration(std::ostringstream & src,const VarType & type,const std::string & name,int indentLevel,uint32_t unusedHints,uint32_t flagsMask,uint32_t offset)1095 void generateDeclaration(std::ostringstream &src, const VarType &type, const std::string &name, int indentLevel,
1096 uint32_t unusedHints, uint32_t flagsMask, uint32_t offset)
1097 {
1098 generateLayoutAndPrecisionDeclaration(src, type.getFlags() & flagsMask, offset);
1099
1100 if (type.isBasicType())
1101 src << glu::getDataTypeName(type.getBasicType()) << " " << name;
1102 else if (type.isArrayType())
1103 {
1104 std::vector<int> arraySizes;
1105 const VarType *curType = &type;
1106 while (curType->isArrayType())
1107 {
1108 arraySizes.push_back(curType->getArraySize());
1109 curType = &curType->getElementType();
1110 }
1111
1112 generateLayoutAndPrecisionDeclaration(src, curType->getFlags() & flagsMask, offset);
1113
1114 if (curType->isBasicType())
1115 src << glu::getDataTypeName(curType->getBasicType());
1116 else
1117 {
1118 DE_ASSERT(curType->isStructType());
1119 generateLocalDeclaration(src, curType->getStruct(), indentLevel + 1);
1120 }
1121
1122 src << " " << name;
1123
1124 for (std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++)
1125 src << "[" << *sizeIter << "]";
1126 }
1127 else
1128 {
1129 generateLocalDeclaration(src, type.getStruct(), indentLevel + 1);
1130 src << " " << name;
1131 }
1132
1133 src << ";";
1134
1135 // Print out unused hints.
1136 if (unusedHints != 0)
1137 src << " // unused in "
1138 << (unusedHints == UNUSED_BOTH ? "both shaders" :
1139 unusedHints == UNUSED_VERTEX ? "vertex shader" :
1140 unusedHints == UNUSED_FRAGMENT ? "fragment shader" :
1141 "???");
1142
1143 src << "\n";
1144 }
1145
generateDeclaration(std::ostringstream & src,const Uniform & uniform,int indentLevel,uint32_t offset)1146 void generateDeclaration(std::ostringstream &src, const Uniform &uniform, int indentLevel, uint32_t offset)
1147 {
1148 if ((uniform.getFlags() & LAYOUT_MASK) != 0)
1149 src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
1150
1151 generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH, ~0u,
1152 offset);
1153 }
1154
getBlockMemberOffset(int blockNdx,const UniformBlock & block,const Uniform & uniform,const UniformLayout & layout)1155 uint32_t getBlockMemberOffset(int blockNdx, const UniformBlock &block, const Uniform &uniform,
1156 const UniformLayout &layout)
1157 {
1158 std::ostringstream name;
1159 const VarType *curType = &uniform.getType();
1160
1161 if (block.getInstanceName().length() != 0)
1162 name << block.getBlockName() << "."; // \note UniformLayoutEntry uses block name rather than instance name
1163
1164 name << uniform.getName();
1165
1166 while (!curType->isBasicType())
1167 {
1168 if (curType->isArrayType())
1169 {
1170 name << "[0]";
1171 curType = &curType->getElementType();
1172 }
1173
1174 if (curType->isStructType())
1175 {
1176 const StructType::ConstIterator firstMember = curType->getStruct().begin();
1177 name << "." << firstMember->getName();
1178 curType = &firstMember->getType();
1179 }
1180 }
1181
1182 const int uniformNdx = layout.getUniformLayoutIndex(blockNdx, name.str());
1183 DE_ASSERT(uniformNdx >= 0);
1184
1185 return layout.uniforms[uniformNdx].offset;
1186 }
1187
1188 template <typename T>
semiShuffle(std::vector<T> & v)1189 void semiShuffle(std::vector<T> &v)
1190 {
1191 const std::vector<T> src = v;
1192 int i = -1;
1193 int n = static_cast<int>(src.size());
1194
1195 v.clear();
1196
1197 while (n)
1198 {
1199 i += n;
1200 v.push_back(src[i]);
1201 n = (n > 0 ? 1 - n : -1 - n);
1202 }
1203 }
1204
1205 template <typename T>
1206 //! \note Stores pointers to original elements
1207 class Traverser
1208 {
1209 public:
1210 template <typename Iter>
Traverser(const Iter beg,const Iter end,const bool shuffled)1211 Traverser(const Iter beg, const Iter end, const bool shuffled)
1212 {
1213 for (Iter it = beg; it != end; ++it)
1214 m_elements.push_back(&(*it));
1215
1216 if (shuffled)
1217 semiShuffle(m_elements);
1218
1219 m_next = m_elements.begin();
1220 }
1221
next(void)1222 T *next(void)
1223 {
1224 if (m_next != m_elements.end())
1225 return *m_next++;
1226 else
1227 return DE_NULL;
1228 }
1229
1230 private:
1231 typename std::vector<T *> m_elements;
1232 typename std::vector<T *>::const_iterator m_next;
1233 };
1234
getPromoteType(glu::DataType type)1235 glu::DataType getPromoteType(glu::DataType type)
1236 {
1237 switch (type)
1238 {
1239 case glu::TYPE_UINT8:
1240 return glu::TYPE_UINT;
1241 case glu::TYPE_UINT8_VEC2:
1242 return glu::TYPE_UINT_VEC2;
1243 case glu::TYPE_UINT8_VEC3:
1244 return glu::TYPE_UINT_VEC3;
1245 case glu::TYPE_UINT8_VEC4:
1246 return glu::TYPE_UINT_VEC4;
1247 case glu::TYPE_INT8:
1248 return glu::TYPE_INT;
1249 case glu::TYPE_INT8_VEC2:
1250 return glu::TYPE_INT_VEC2;
1251 case glu::TYPE_INT8_VEC3:
1252 return glu::TYPE_INT_VEC3;
1253 case glu::TYPE_INT8_VEC4:
1254 return glu::TYPE_INT_VEC4;
1255 case glu::TYPE_UINT16:
1256 return glu::TYPE_UINT;
1257 case glu::TYPE_UINT16_VEC2:
1258 return glu::TYPE_UINT_VEC2;
1259 case glu::TYPE_UINT16_VEC3:
1260 return glu::TYPE_UINT_VEC3;
1261 case glu::TYPE_UINT16_VEC4:
1262 return glu::TYPE_UINT_VEC4;
1263 case glu::TYPE_INT16:
1264 return glu::TYPE_INT;
1265 case glu::TYPE_INT16_VEC2:
1266 return glu::TYPE_INT_VEC2;
1267 case glu::TYPE_INT16_VEC3:
1268 return glu::TYPE_INT_VEC3;
1269 case glu::TYPE_INT16_VEC4:
1270 return glu::TYPE_INT_VEC4;
1271 case glu::TYPE_FLOAT16:
1272 return glu::TYPE_FLOAT;
1273 case glu::TYPE_FLOAT16_VEC2:
1274 return glu::TYPE_FLOAT_VEC2;
1275 case glu::TYPE_FLOAT16_VEC3:
1276 return glu::TYPE_FLOAT_VEC3;
1277 case glu::TYPE_FLOAT16_VEC4:
1278 return glu::TYPE_FLOAT_VEC4;
1279 default:
1280 return type;
1281 }
1282 }
1283
generateDeclaration(std::ostringstream & src,int blockNdx,const UniformBlock & block,const UniformLayout & layout,bool shuffleUniformMembers)1284 void generateDeclaration(std::ostringstream &src, int blockNdx, const UniformBlock &block, const UniformLayout &layout,
1285 bool shuffleUniformMembers)
1286 {
1287 src << "layout(set = 0, binding = " << blockNdx;
1288 if ((block.getFlags() & LAYOUT_MASK) != 0)
1289 src << ", " << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK);
1290 src << ") ";
1291
1292 src << "uniform " << block.getBlockName();
1293 src << "\n{\n";
1294
1295 Traverser<const Uniform> uniforms(block.begin(), block.end(), shuffleUniformMembers);
1296
1297 while (const Uniform *pUniform = uniforms.next())
1298 {
1299 src << Indent(1);
1300 generateDeclaration(src, *pUniform, 1 /* indent level */,
1301 getBlockMemberOffset(blockNdx, block, *pUniform, layout));
1302 }
1303
1304 src << "}";
1305
1306 if (block.hasInstanceName())
1307 {
1308 src << " " << block.getInstanceName();
1309 if (block.isArray())
1310 {
1311 if (block.getFlags() & LAYOUT_DESCRIPTOR_INDEXING)
1312 src << "[]";
1313 else
1314 src << "[" << block.getArraySize() << "]";
1315 }
1316 }
1317 else
1318 DE_ASSERT(!block.isArray());
1319
1320 src << ";\n";
1321 }
1322
generateValueSrc(std::ostringstream & src,const UniformLayoutEntry & entry,const void * basePtr,int elementNdx)1323 void generateValueSrc(std::ostringstream &src, const UniformLayoutEntry &entry, const void *basePtr, int elementNdx)
1324 {
1325 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
1326 int scalarSize = glu::getDataTypeScalarSize(entry.type);
1327 bool isArray = entry.size > 1;
1328 const uint8_t *elemPtr = (const uint8_t *)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
1329 const size_t compSize = getDataTypeByteSize(scalarType);
1330
1331 using float16_cptr_t = std::add_pointer_t<std::add_const_t<typename tcu::Float16::StorageType>>;
1332
1333 if (scalarSize > 1)
1334 src << glu::getDataTypeName(getPromoteType(entry.type)) << "(";
1335
1336 if (glu::isDataTypeMatrix(entry.type))
1337 {
1338 int numRows = glu::getDataTypeMatrixNumRows(entry.type);
1339 int numCols = glu::getDataTypeMatrixNumColumns(entry.type);
1340
1341 DE_ASSERT(scalarType == glu::TYPE_FLOAT);
1342
1343 // Constructed in column-wise order.
1344 for (int colNdx = 0; colNdx < numCols; colNdx++)
1345 {
1346 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1347 {
1348 const uint8_t *compPtr =
1349 elemPtr + (entry.isRowMajor ? (rowNdx * entry.matrixStride + colNdx * compSize) :
1350 (colNdx * entry.matrixStride + rowNdx * compSize));
1351
1352 if (colNdx > 0 || rowNdx > 0)
1353 src << ", ";
1354
1355 src << de::floatToString(*((const float *)compPtr), 1);
1356 }
1357 }
1358 }
1359 else
1360 {
1361 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1362 {
1363 const uint8_t *compPtr = elemPtr + scalarNdx * compSize;
1364
1365 if (scalarNdx > 0)
1366 src << ", ";
1367
1368 switch (scalarType)
1369 {
1370 case glu::TYPE_INT8:
1371 src << (uint32_t) * ((const int8_t *)compPtr);
1372 break;
1373 case glu::TYPE_INT16:
1374 src << *((const int16_t *)compPtr);
1375 break;
1376 case glu::TYPE_INT:
1377 src << *((const int *)compPtr);
1378 break;
1379 case glu::TYPE_UINT8:
1380 src << (uint32_t) * ((const uint8_t *)compPtr) << "u";
1381 break;
1382 case glu::TYPE_UINT16:
1383 src << *((const uint16_t *)compPtr) << "u";
1384 break;
1385 case glu::TYPE_UINT:
1386 src << *((const uint32_t *)compPtr) << "u";
1387 break;
1388 case glu::TYPE_BOOL:
1389 src << (*((const uint32_t *)compPtr) != 0u ? "true" : "false");
1390 break;
1391 case glu::TYPE_FLOAT:
1392 src << de::floatToString(*((const float *)compPtr), 1);
1393 break;
1394 case glu::TYPE_FLOAT16:
1395 src << de::floatToString(tcu::Float16(*reinterpret_cast<float16_cptr_t>(compPtr)).asFloat(), 1);
1396 break;
1397 default:
1398 DE_ASSERT(false);
1399 }
1400 }
1401 }
1402
1403 if (scalarSize > 1)
1404 src << ")";
1405 }
1406
isMatrix(glu::DataType elementType)1407 bool isMatrix(glu::DataType elementType)
1408 {
1409 return (elementType >= glu::TYPE_FLOAT_MAT2) && (elementType <= glu::TYPE_FLOAT_MAT4);
1410 }
1411
writeMatrixTypeSrc(int columnCount,int rowCount,std::string compare,std::string compareType,std::ostringstream & src,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,bool vector)1412 void writeMatrixTypeSrc(int columnCount, int rowCount, std::string compare, std::string compareType,
1413 std::ostringstream &src, const std::string &srcName, const void *basePtr,
1414 const UniformLayoutEntry &entry, bool vector)
1415 {
1416 if (vector) // generateTestSrcMatrixPerVec
1417 {
1418 for (int colNdex = 0; colNdex < columnCount; colNdex++)
1419 {
1420 src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "], ";
1421
1422 if (glu::isDataTypeMatrix(entry.type))
1423 {
1424 int scalarSize = glu::getDataTypeScalarSize(entry.type);
1425 const uint8_t *elemPtr = (const uint8_t *)basePtr + entry.offset;
1426 const int compSize = sizeof(uint32_t);
1427
1428 if (scalarSize > 1)
1429 src << compareType << "(";
1430 for (int rowNdex = 0; rowNdex < rowCount; rowNdex++)
1431 {
1432 const uint8_t *compPtr =
1433 elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize) :
1434 (colNdex * entry.matrixStride + rowNdex * compSize));
1435 src << de::floatToString(*((const float *)compPtr), 1);
1436
1437 if (rowNdex < rowCount - 1)
1438 src << ", ";
1439 }
1440 src << "));\n";
1441 }
1442 else
1443 {
1444 generateValueSrc(src, entry, basePtr, 0);
1445 src << "[" << colNdex << "]);\n";
1446 }
1447 }
1448 }
1449 else // generateTestSrcMatrixPerElement
1450 {
1451 for (int colNdex = 0; colNdex < columnCount; colNdex++)
1452 {
1453 for (int rowNdex = 0; rowNdex < rowCount; rowNdex++)
1454 {
1455 src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "][" << rowNdex
1456 << "], ";
1457 if (glu::isDataTypeMatrix(entry.type))
1458 {
1459 const uint8_t *elemPtr = (const uint8_t *)basePtr + entry.offset;
1460 const int compSize = sizeof(uint32_t);
1461 const uint8_t *compPtr =
1462 elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize) :
1463 (colNdex * entry.matrixStride + rowNdex * compSize));
1464
1465 src << de::floatToString(*((const float *)compPtr), 1) << ");\n";
1466 }
1467 else
1468 {
1469 generateValueSrc(src, entry, basePtr, 0);
1470 src << "[" << colNdex << "][" << rowNdex << "]);\n";
1471 }
1472 }
1473 }
1474 }
1475 }
1476
generateTestSrcMatrixPerVec(glu::DataType elementType,std::ostringstream & src,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,bool vector)1477 void generateTestSrcMatrixPerVec(glu::DataType elementType, std::ostringstream &src, const std::string &srcName,
1478 const void *basePtr, const UniformLayoutEntry &entry, bool vector)
1479 {
1480 std::string compare = "compare_";
1481 switch (elementType)
1482 {
1483 case glu::TYPE_FLOAT_MAT2:
1484 writeMatrixTypeSrc(2, 2, compare, "vec2", src, srcName, basePtr, entry, vector);
1485 break;
1486
1487 case glu::TYPE_FLOAT_MAT2X3:
1488 writeMatrixTypeSrc(2, 3, compare, "vec3", src, srcName, basePtr, entry, vector);
1489 break;
1490
1491 case glu::TYPE_FLOAT_MAT2X4:
1492 writeMatrixTypeSrc(2, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
1493 break;
1494
1495 case glu::TYPE_FLOAT_MAT3X4:
1496 writeMatrixTypeSrc(3, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
1497 break;
1498
1499 case glu::TYPE_FLOAT_MAT4:
1500 writeMatrixTypeSrc(4, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
1501 break;
1502
1503 case glu::TYPE_FLOAT_MAT4X2:
1504 writeMatrixTypeSrc(4, 2, compare, "vec2", src, srcName, basePtr, entry, vector);
1505 break;
1506
1507 case glu::TYPE_FLOAT_MAT4X3:
1508 writeMatrixTypeSrc(4, 3, compare, "vec3", src, srcName, basePtr, entry, vector);
1509 break;
1510
1511 default:
1512 break;
1513 }
1514 }
1515
generateTestSrcMatrixPerElement(glu::DataType elementType,std::ostringstream & src,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,bool vector)1516 void generateTestSrcMatrixPerElement(glu::DataType elementType, std::ostringstream &src, const std::string &srcName,
1517 const void *basePtr, const UniformLayoutEntry &entry, bool vector)
1518 {
1519 std::string compare = "compare_";
1520 std::string compareType = "float";
1521 switch (elementType)
1522 {
1523 case glu::TYPE_FLOAT_MAT2:
1524 writeMatrixTypeSrc(2, 2, compare, compareType, src, srcName, basePtr, entry, vector);
1525 break;
1526
1527 case glu::TYPE_FLOAT_MAT2X3:
1528 writeMatrixTypeSrc(2, 3, compare, compareType, src, srcName, basePtr, entry, vector);
1529 break;
1530
1531 case glu::TYPE_FLOAT_MAT2X4:
1532 writeMatrixTypeSrc(2, 4, compare, compareType, src, srcName, basePtr, entry, vector);
1533 break;
1534
1535 case glu::TYPE_FLOAT_MAT3X4:
1536 writeMatrixTypeSrc(3, 4, compare, compareType, src, srcName, basePtr, entry, vector);
1537 break;
1538
1539 case glu::TYPE_FLOAT_MAT4:
1540 writeMatrixTypeSrc(4, 4, compare, compareType, src, srcName, basePtr, entry, vector);
1541 break;
1542
1543 case glu::TYPE_FLOAT_MAT4X2:
1544 writeMatrixTypeSrc(4, 2, compare, compareType, src, srcName, basePtr, entry, vector);
1545 break;
1546
1547 case glu::TYPE_FLOAT_MAT4X3:
1548 writeMatrixTypeSrc(4, 3, compare, compareType, src, srcName, basePtr, entry, vector);
1549 break;
1550
1551 default:
1552 break;
1553 }
1554 }
1555
generateSingleCompare(std::ostringstream & src,glu::DataType elementType,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,MatrixLoadFlags matrixLoadFlag)1556 void generateSingleCompare(std::ostringstream &src, glu::DataType elementType, const std::string &srcName,
1557 const void *basePtr, const UniformLayoutEntry &entry, MatrixLoadFlags matrixLoadFlag)
1558 {
1559 if (matrixLoadFlag == LOAD_FULL_MATRIX)
1560 {
1561 const char *typeName = glu::getDataTypeName(elementType);
1562 const char *castName = "";
1563 glu::DataType promoteType = getPromoteType(elementType);
1564 if (elementType != promoteType)
1565 {
1566 castName = glu::getDataTypeName(promoteType);
1567 }
1568
1569 src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "), ";
1570 generateValueSrc(src, entry, basePtr, 0);
1571 src << ");\n";
1572 }
1573 else
1574 {
1575 if (isMatrix(elementType))
1576 {
1577 generateTestSrcMatrixPerVec(elementType, src, srcName, basePtr, entry, true);
1578 generateTestSrcMatrixPerElement(elementType, src, srcName, basePtr, entry, false);
1579 }
1580 }
1581 }
1582
generateCompareSrc(std::ostringstream & src,const char * resultVar,const VarType & type,const std::string & srcName,const std::string & apiName,const UniformLayout & layout,int blockNdx,const void * basePtr,uint32_t unusedMask,MatrixLoadFlags matrixLoadFlag)1583 void generateCompareSrc(std::ostringstream &src, const char *resultVar, const VarType &type, const std::string &srcName,
1584 const std::string &apiName, const UniformLayout &layout, int blockNdx, const void *basePtr,
1585 uint32_t unusedMask, MatrixLoadFlags matrixLoadFlag)
1586 {
1587 if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
1588 {
1589 // Basic type or array of basic types.
1590 bool isArray = type.isArrayType();
1591 glu::DataType elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType();
1592 const char *typeName = glu::getDataTypeName(elementType);
1593 std::string fullApiName = std::string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
1594 int uniformNdx = layout.getUniformLayoutIndex(blockNdx, fullApiName);
1595 const UniformLayoutEntry &entry = layout.uniforms[uniformNdx];
1596
1597 const char *castName = "";
1598 glu::DataType promoteType = getPromoteType(elementType);
1599 if (elementType != promoteType)
1600 {
1601 castName = glu::getDataTypeName(promoteType);
1602 }
1603
1604 if (isArray)
1605 {
1606 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
1607 {
1608 src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "[" << elemNdx
1609 << "]), ";
1610 generateValueSrc(src, entry, basePtr, elemNdx);
1611 src << ");\n";
1612 }
1613 }
1614 else
1615 {
1616 generateSingleCompare(src, elementType, srcName, basePtr, entry, matrixLoadFlag);
1617 }
1618 }
1619 else if (type.isArrayType())
1620 {
1621 const VarType &elementType = type.getElementType();
1622
1623 for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
1624 {
1625 std::string op = std::string("[") + de::toString(elementNdx) + "]";
1626 std::string elementSrcName = std::string(srcName) + op;
1627 std::string elementApiName = std::string(apiName) + op;
1628 generateCompareSrc(src, resultVar, elementType, elementSrcName, elementApiName, layout, blockNdx, basePtr,
1629 unusedMask, LOAD_FULL_MATRIX);
1630 }
1631 }
1632 else
1633 {
1634 DE_ASSERT(type.isStructType());
1635
1636 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
1637 memberIter++)
1638 {
1639 if (memberIter->getFlags() & unusedMask)
1640 continue; // Skip member.
1641
1642 std::string op = std::string(".") + memberIter->getName();
1643 std::string memberSrcName = std::string(srcName) + op;
1644 std::string memberApiName = std::string(apiName) + op;
1645 generateCompareSrc(src, resultVar, memberIter->getType(), memberSrcName, memberApiName, layout, blockNdx,
1646 basePtr, unusedMask, LOAD_FULL_MATRIX);
1647 }
1648 }
1649 }
1650
generateCompareSrc(std::ostringstream & src,const char * resultVar,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,bool isVertex,MatrixLoadFlags matrixLoadFlag)1651 void generateCompareSrc(std::ostringstream &src, const char *resultVar, const ShaderInterface &interface,
1652 const UniformLayout &layout, const std::map<int, void *> &blockPointers, bool isVertex,
1653 MatrixLoadFlags matrixLoadFlag)
1654 {
1655 uint32_t unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
1656
1657 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1658 {
1659 const UniformBlock &block = interface.getUniformBlock(blockNdx);
1660
1661 if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
1662 continue; // Skip.
1663
1664 bool hasInstanceName = block.hasInstanceName();
1665 bool isArray = block.isArray();
1666 int numInstances = isArray ? block.getArraySize() : 1;
1667 std::string apiPrefix = hasInstanceName ? block.getBlockName() + "." : std::string("");
1668
1669 DE_ASSERT(!isArray || hasInstanceName);
1670
1671 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1672 {
1673 std::string instancePostfix = "";
1674 if (isArray)
1675 {
1676 std::string indexStr = de::toString(instanceNdx);
1677 if (interface.usesBlockLayout(LAYOUT_DESCRIPTOR_INDEXING))
1678 indexStr = std::string("nonuniformEXT(") + indexStr + ")";
1679 instancePostfix = std::string("[") + indexStr + "]";
1680 }
1681
1682 std::string blockInstanceName = block.getBlockName() + instancePostfix;
1683 std::string srcPrefix = hasInstanceName ? block.getInstanceName() + instancePostfix + "." : std::string("");
1684 int blockLayoutNdx = layout.getBlockLayoutIndex(blockNdx, instanceNdx);
1685 void *basePtr = blockPointers.find(blockLayoutNdx)->second;
1686
1687 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
1688 {
1689 const Uniform &uniform = *uniformIter;
1690
1691 if (uniform.getFlags() & unusedMask)
1692 continue; // Don't read from that uniform.
1693
1694 std::string srcName = srcPrefix + uniform.getName();
1695 std::string apiName = apiPrefix + uniform.getName();
1696 generateCompareSrc(src, resultVar, uniform.getType(), srcName, apiName, layout, blockNdx, basePtr,
1697 unusedMask, matrixLoadFlag);
1698 }
1699 }
1700 }
1701 }
1702
generateVertexShader(const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,MatrixLoadFlags matrixLoadFlag,bool shuffleUniformMembers)1703 std::string generateVertexShader(const ShaderInterface &interface, const UniformLayout &layout,
1704 const std::map<int, void *> &blockPointers, MatrixLoadFlags matrixLoadFlag,
1705 bool shuffleUniformMembers)
1706 {
1707 std::ostringstream src;
1708 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
1709 src << "#extension GL_EXT_shader_16bit_storage : enable\n";
1710 src << "#extension GL_EXT_shader_8bit_storage : enable\n";
1711 src << "#extension GL_EXT_scalar_block_layout : enable\n";
1712 src << "#extension GL_EXT_nonuniform_qualifier : enable\n";
1713
1714 src << "layout(location = 0) in highp vec4 a_position;\n";
1715 src << "layout(location = 0) out mediump float v_vtxResult;\n";
1716 src << "\n";
1717
1718 std::vector<const StructType *> namedStructs;
1719 interface.getNamedStructs(namedStructs);
1720 for (std::vector<const StructType *>::const_iterator structIter = namedStructs.begin();
1721 structIter != namedStructs.end(); structIter++)
1722 generateDeclaration(src, **structIter, 0);
1723
1724 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1725 {
1726 const UniformBlock &block = interface.getUniformBlock(blockNdx);
1727 if (block.getFlags() & DECLARE_VERTEX)
1728 generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers);
1729 }
1730
1731 // Comparison utilities.
1732 src << "\n";
1733 generateCompareFuncs(src, interface);
1734
1735 src << "\n"
1736 "void main (void)\n"
1737 "{\n"
1738 " gl_Position = a_position;\n"
1739 " mediump float result = 1.0;\n";
1740
1741 // Value compare.
1742 generateCompareSrc(src, "result", interface, layout, blockPointers, true, matrixLoadFlag);
1743
1744 src << " v_vtxResult = result;\n"
1745 "}\n";
1746
1747 return src.str();
1748 }
1749
generateFragmentShader(const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,MatrixLoadFlags matrixLoadFlag,bool shuffleUniformMembers)1750 std::string generateFragmentShader(const ShaderInterface &interface, const UniformLayout &layout,
1751 const std::map<int, void *> &blockPointers, MatrixLoadFlags matrixLoadFlag,
1752 bool shuffleUniformMembers)
1753 {
1754 std::ostringstream src;
1755 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
1756 src << "#extension GL_EXT_shader_16bit_storage : enable\n";
1757 src << "#extension GL_EXT_shader_8bit_storage : enable\n";
1758 src << "#extension GL_EXT_scalar_block_layout : enable\n";
1759 src << "#extension GL_EXT_nonuniform_qualifier : enable\n";
1760
1761 src << "layout(location = 0) in mediump float v_vtxResult;\n";
1762 src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1763 src << "\n";
1764
1765 std::vector<const StructType *> namedStructs;
1766 interface.getNamedStructs(namedStructs);
1767 for (std::vector<const StructType *>::const_iterator structIter = namedStructs.begin();
1768 structIter != namedStructs.end(); structIter++)
1769 generateDeclaration(src, **structIter, 0);
1770
1771 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1772 {
1773 const UniformBlock &block = interface.getUniformBlock(blockNdx);
1774 if (block.getFlags() & DECLARE_FRAGMENT)
1775 generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers);
1776 }
1777
1778 // Comparison utilities.
1779 src << "\n";
1780 generateCompareFuncs(src, interface);
1781
1782 src << "\n"
1783 "void main (void)\n"
1784 "{\n"
1785 " mediump float result = 1.0;\n";
1786
1787 // Value compare.
1788 generateCompareSrc(src, "result", interface, layout, blockPointers, false, matrixLoadFlag);
1789
1790 src << " dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
1791 "}\n";
1792
1793 return src.str();
1794 }
1795
createBuffer(Context & context,VkDeviceSize bufferSize,vk::VkBufferUsageFlags usageFlags)1796 Move<VkBuffer> createBuffer(Context &context, VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
1797 {
1798 const VkDevice vkDevice = context.getDevice();
1799 const DeviceInterface &vk = context.getDeviceInterface();
1800 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1801
1802 const VkBufferCreateInfo bufferInfo = {
1803 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1804 DE_NULL, // const void* pNext;
1805 0u, // VkBufferCreateFlags flags;
1806 bufferSize, // VkDeviceSize size;
1807 usageFlags, // VkBufferUsageFlags usage;
1808 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1809 1u, // uint32_t queueFamilyIndexCount;
1810 &queueFamilyIndex // const uint32_t* pQueueFamilyIndices;
1811 };
1812
1813 return vk::createBuffer(vk, vkDevice, &bufferInfo);
1814 }
1815
createImage2D(Context & context,uint32_t width,uint32_t height,vk::VkFormat format,vk::VkImageTiling tiling,vk::VkImageUsageFlags usageFlags)1816 Move<vk::VkImage> createImage2D(Context &context, uint32_t width, uint32_t height, vk::VkFormat format,
1817 vk::VkImageTiling tiling, vk::VkImageUsageFlags usageFlags)
1818 {
1819 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1820 const vk::VkImageCreateInfo params = {
1821 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
1822 DE_NULL, // const void* pNext
1823 0u, // VkImageCreateFlags flags
1824 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType
1825 format, // VkFormat format
1826 {width, height, 1u}, // VkExtent3D extent
1827 1u, // uint32_t mipLevels
1828 1u, // uint32_t arrayLayers
1829 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
1830 tiling, // VkImageTiling tiling
1831 usageFlags, // VkImageUsageFlags usage
1832 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
1833 1u, // uint32_t queueFamilyIndexCount
1834 &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices
1835 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
1836 };
1837
1838 return vk::createImage(context.getDeviceInterface(), context.getDevice(), ¶ms);
1839 }
1840
allocateAndBindMemory(Context & context,vk::VkBuffer buffer,vk::MemoryRequirement memReqs)1841 de::MovePtr<vk::Allocation> allocateAndBindMemory(Context &context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
1842 {
1843 const vk::DeviceInterface &vkd = context.getDeviceInterface();
1844 const vk::VkMemoryRequirements bufReqs = vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
1845 de::MovePtr<vk::Allocation> memory = context.getDefaultAllocator().allocate(bufReqs, memReqs);
1846
1847 vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
1848
1849 return memory;
1850 }
1851
allocateAndBindMemory(Context & context,vk::VkImage image,vk::MemoryRequirement memReqs)1852 de::MovePtr<vk::Allocation> allocateAndBindMemory(Context &context, vk::VkImage image, vk::MemoryRequirement memReqs)
1853 {
1854 const vk::DeviceInterface &vkd = context.getDeviceInterface();
1855 const vk::VkMemoryRequirements imgReqs = vk::getImageMemoryRequirements(vkd, context.getDevice(), image);
1856 de::MovePtr<vk::Allocation> memory = context.getDefaultAllocator().allocate(imgReqs, memReqs);
1857
1858 vkd.bindImageMemory(context.getDevice(), image, memory->getMemory(), memory->getOffset());
1859
1860 return memory;
1861 }
1862
createAttachmentView(Context & context,vk::VkImage image,vk::VkFormat format)1863 Move<vk::VkImageView> createAttachmentView(Context &context, vk::VkImage image, vk::VkFormat format)
1864 {
1865 const vk::VkImageViewCreateInfo params = {
1866 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
1867 DE_NULL, // pNext
1868 0u, // flags
1869 image, // image
1870 vk::VK_IMAGE_VIEW_TYPE_2D, // viewType
1871 format, // format
1872 vk::makeComponentMappingRGBA(), // components
1873 {vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // subresourceRange
1874 };
1875
1876 return vk::createImageView(context.getDeviceInterface(), context.getDevice(), ¶ms);
1877 }
1878
createPipelineLayout(Context & context,vk::VkDescriptorSetLayout descriptorSetLayout)1879 Move<vk::VkPipelineLayout> createPipelineLayout(Context &context, vk::VkDescriptorSetLayout descriptorSetLayout)
1880 {
1881 const vk::VkPipelineLayoutCreateInfo params = {
1882 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
1883 DE_NULL, // pNext
1884 0u, // flags
1885 1u, // setLayoutCount
1886 &descriptorSetLayout, // pSetLayouts
1887 0u, // pushConstantRangeCount
1888 DE_NULL, // pPushConstantRanges
1889 };
1890
1891 return vk::createPipelineLayout(context.getDeviceInterface(), context.getDevice(), ¶ms);
1892 }
1893
createCmdPool(Context & context)1894 Move<vk::VkCommandPool> createCmdPool(Context &context)
1895 {
1896 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1897
1898 return vk::createCommandPool(context.getDeviceInterface(), context.getDevice(),
1899 vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
1900 }
1901
createCmdBuffer(Context & context,vk::VkCommandPool cmdPool)1902 Move<vk::VkCommandBuffer> createCmdBuffer(Context &context, vk::VkCommandPool cmdPool)
1903 {
1904 return vk::allocateCommandBuffer(context.getDeviceInterface(), context.getDevice(), cmdPool,
1905 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1906 }
1907
1908 // UniformBlockCaseInstance
1909
1910 class UniformBlockCaseInstance : public vkt::TestInstance
1911 {
1912 public:
1913 UniformBlockCaseInstance(Context &context, UniformBlockCase::BufferMode bufferMode, const UniformLayout &layout,
1914 const std::map<int, void *> &blockPointers);
1915 virtual ~UniformBlockCaseInstance(void);
1916 virtual tcu::TestStatus iterate(void);
1917
1918 private:
1919 enum
1920 {
1921 RENDER_WIDTH = 100,
1922 RENDER_HEIGHT = 100,
1923 };
1924
1925 vk::Move<VkRenderPass> createRenderPass(vk::VkFormat format) const;
1926 vk::Move<VkFramebuffer> createFramebuffer(vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const;
1927 vk::Move<VkDescriptorSetLayout> createDescriptorSetLayout(void) const;
1928 vk::Move<VkDescriptorPool> createDescriptorPool(void) const;
1929 vk::Move<VkPipeline> createPipeline(vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule,
1930 vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const;
1931
1932 vk::VkDescriptorBufferInfo addUniformData(uint32_t size, const void *dataPtr);
1933
1934 UniformBlockCase::BufferMode m_bufferMode;
1935 const UniformLayout &m_layout;
1936 const std::map<int, void *> &m_blockPointers;
1937
1938 typedef de::SharedPtr<vk::Unique<vk::VkBuffer>> VkBufferSp;
1939 typedef de::SharedPtr<vk::Allocation> AllocationSp;
1940
1941 std::vector<VkBufferSp> m_uniformBuffers;
1942 std::vector<AllocationSp> m_uniformAllocs;
1943 };
1944
UniformBlockCaseInstance(Context & ctx,UniformBlockCase::BufferMode bufferMode,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1945 UniformBlockCaseInstance::UniformBlockCaseInstance(Context &ctx, UniformBlockCase::BufferMode bufferMode,
1946 const UniformLayout &layout,
1947 const std::map<int, void *> &blockPointers)
1948 : vkt::TestInstance(ctx)
1949 , m_bufferMode(bufferMode)
1950 , m_layout(layout)
1951 , m_blockPointers(blockPointers)
1952 {
1953 }
1954
~UniformBlockCaseInstance(void)1955 UniformBlockCaseInstance::~UniformBlockCaseInstance(void)
1956 {
1957 }
1958
iterate(void)1959 tcu::TestStatus UniformBlockCaseInstance::iterate(void)
1960 {
1961 const vk::DeviceInterface &vk = m_context.getDeviceInterface();
1962 const vk::VkDevice device = m_context.getDevice();
1963 const vk::VkQueue queue = m_context.getUniversalQueue();
1964 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1965
1966 const float positions[] = {-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f,
1967 +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f};
1968
1969 const uint32_t indices[] = {0, 1, 2, 2, 1, 3};
1970
1971 vk::Unique<VkBuffer> positionsBuffer(
1972 createBuffer(m_context, sizeof(positions), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1973 de::UniquePtr<Allocation> positionsAlloc(
1974 allocateAndBindMemory(m_context, *positionsBuffer, MemoryRequirement::HostVisible));
1975 vk::Unique<VkBuffer> indicesBuffer(createBuffer(
1976 m_context, sizeof(indices), vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT | vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1977 de::UniquePtr<Allocation> indicesAlloc(
1978 allocateAndBindMemory(m_context, *indicesBuffer, MemoryRequirement::HostVisible));
1979
1980 int minUniformBufferOffsetAlignment = getminUniformBufferOffsetAlignment(m_context);
1981
1982 // Upload attrbiutes data
1983 {
1984 deMemcpy(positionsAlloc->getHostPtr(), positions, sizeof(positions));
1985 flushAlloc(vk, device, *positionsAlloc);
1986
1987 deMemcpy(indicesAlloc->getHostPtr(), indices, sizeof(indices));
1988 flushAlloc(vk, device, *indicesAlloc);
1989 }
1990
1991 vk::Unique<VkImage> colorImage(
1992 createImage2D(m_context, RENDER_WIDTH, RENDER_HEIGHT, vk::VK_FORMAT_R8G8B8A8_UNORM, vk::VK_IMAGE_TILING_OPTIMAL,
1993 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
1994 de::UniquePtr<Allocation> colorImageAlloc(allocateAndBindMemory(m_context, *colorImage, MemoryRequirement::Any));
1995 vk::Unique<VkImageView> colorImageView(createAttachmentView(m_context, *colorImage, vk::VK_FORMAT_R8G8B8A8_UNORM));
1996
1997 vk::Unique<VkDescriptorSetLayout> descriptorSetLayout(createDescriptorSetLayout());
1998 vk::Unique<VkDescriptorPool> descriptorPool(createDescriptorPool());
1999
2000 const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
2001 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
2002 DE_NULL, // const void* pNext;
2003 *descriptorPool, // VkDescriptorPool descriptorPool;
2004 1u, // uint32_t setLayoutCount;
2005 &descriptorSetLayout.get() // const VkDescriptorSetLayout* pSetLayouts;
2006 };
2007
2008 vk::Unique<VkDescriptorSet> descriptorSet(vk::allocateDescriptorSet(vk, device, &descriptorSetAllocateInfo));
2009 int numBlocks = (int)m_layout.blocks.size();
2010 std::vector<vk::VkDescriptorBufferInfo> descriptors(numBlocks);
2011
2012 // Upload uniform data
2013 {
2014 vk::DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
2015
2016 if (m_bufferMode == UniformBlockCase::BUFFERMODE_PER_BLOCK)
2017 {
2018 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2019 {
2020 const BlockLayoutEntry &block = m_layout.blocks[blockNdx];
2021 const void *srcPtr = m_blockPointers.find(blockNdx)->second;
2022
2023 descriptors[blockNdx] = addUniformData(block.size, srcPtr);
2024 descriptorSetUpdateBuilder.writeSingle(
2025 *descriptorSet,
2026 vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
2027 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptors[blockNdx]);
2028 }
2029 }
2030 else
2031 {
2032 int currentOffset = 0;
2033 std::map<int, int> offsets;
2034 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2035 {
2036 if (minUniformBufferOffsetAlignment > 0)
2037 currentOffset = deAlign32(currentOffset, minUniformBufferOffsetAlignment);
2038 offsets[blockNdx] = currentOffset;
2039 currentOffset += m_layout.blocks[blockNdx].size;
2040 }
2041
2042 uint32_t totalSize = currentOffset;
2043
2044 // Make a copy of the data that satisfies the device's min uniform buffer alignment
2045 std::vector<uint8_t> data;
2046 data.resize(totalSize);
2047 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2048 {
2049 deMemcpy(&data[offsets[blockNdx]], m_blockPointers.find(blockNdx)->second,
2050 m_layout.blocks[blockNdx].size);
2051 }
2052
2053 vk::VkBuffer buffer = addUniformData(totalSize, &data[0]).buffer;
2054
2055 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2056 {
2057 const BlockLayoutEntry &block = m_layout.blocks[blockNdx];
2058 uint32_t size = block.size;
2059
2060 const VkDescriptorBufferInfo descriptor = {
2061 buffer, // VkBuffer buffer;
2062 (uint32_t)offsets[blockNdx], // VkDeviceSize offset;
2063 size, // VkDeviceSize range;
2064 };
2065
2066 descriptors[blockNdx] = descriptor;
2067 descriptorSetUpdateBuilder.writeSingle(
2068 *descriptorSet,
2069 vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
2070 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptors[blockNdx]);
2071 }
2072 }
2073
2074 descriptorSetUpdateBuilder.update(vk, device);
2075 }
2076
2077 vk::Unique<VkRenderPass> renderPass(createRenderPass(vk::VK_FORMAT_R8G8B8A8_UNORM));
2078 vk::Unique<VkFramebuffer> framebuffer(createFramebuffer(*renderPass, *colorImageView));
2079 vk::Unique<VkPipelineLayout> pipelineLayout(createPipelineLayout(m_context, *descriptorSetLayout));
2080
2081 // Disable the watchdog to prevent long shader compilation failing tests due to time out
2082 // on certain hardware(s)
2083 m_context.getTestContext().touchWatchdogAndDisableIntervalTimeLimit();
2084
2085 vk::Unique<VkShaderModule> vtxShaderModule(
2086 vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
2087 vk::Unique<VkShaderModule> fragShaderModule(
2088 vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
2089 vk::Unique<VkPipeline> pipeline(createPipeline(*vtxShaderModule, *fragShaderModule, *pipelineLayout, *renderPass));
2090
2091 //Re-enable the watchdog
2092 m_context.getTestContext().touchWatchdogAndEnableIntervalTimeLimit();
2093
2094 vk::Unique<VkCommandPool> cmdPool(createCmdPool(m_context));
2095 vk::Unique<VkCommandBuffer> cmdBuffer(createCmdBuffer(m_context, *cmdPool));
2096 vk::Unique<VkBuffer> readImageBuffer(createBuffer(m_context, (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * 4),
2097 vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
2098 de::UniquePtr<Allocation> readImageAlloc(
2099 allocateAndBindMemory(m_context, *readImageBuffer, vk::MemoryRequirement::HostVisible));
2100
2101 // Record command buffer
2102 const vk::VkCommandBufferBeginInfo beginInfo = {
2103 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
2104 DE_NULL, // const void* pNext;
2105 0u, // VkCommandBufferUsageFlags flags;
2106 (const vk::VkCommandBufferInheritanceInfo *)DE_NULL,
2107 };
2108 VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &beginInfo));
2109
2110 // Add barrier for initializing image state
2111 {
2112 const vk::VkImageMemoryBarrier initializeBarrier = {
2113 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
2114 DE_NULL, // const void* pNext
2115 0, // VVkAccessFlags srcAccessMask;
2116 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
2117 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
2118 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
2119 queueFamilyIndex, // uint32_t srcQueueFamilyIndex;
2120 queueFamilyIndex, // uint32_t dstQueueFamilyIndex;
2121 *colorImage, // VkImage image;
2122 {
2123 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
2124 0u, // uint32_t baseMipLevel;
2125 1u, // uint32_t mipLevels;
2126 0u, // uint32_t baseArraySlice;
2127 1u, // uint32_t arraySize;
2128 } // VkImageSubresourceRange subresourceRange
2129 };
2130
2131 vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
2132 (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 0,
2133 (const vk::VkBufferMemoryBarrier *)DE_NULL, 1, &initializeBarrier);
2134 }
2135
2136 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT),
2137 tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
2138
2139 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2140 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet,
2141 0u, DE_NULL);
2142
2143 const vk::VkDeviceSize offsets[] = {0u};
2144 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &*positionsBuffer, offsets);
2145 vk.cmdBindIndexBuffer(*cmdBuffer, *indicesBuffer, (vk::VkDeviceSize)0, vk::VK_INDEX_TYPE_UINT32);
2146
2147 vk.cmdDrawIndexed(*cmdBuffer, DE_LENGTH_OF_ARRAY(indices), 1u, 0u, 0u, 0u);
2148 endRenderPass(vk, *cmdBuffer);
2149
2150 copyImageToBuffer(vk, *cmdBuffer, *colorImage, *readImageBuffer, tcu::IVec2(RENDER_WIDTH, RENDER_HEIGHT));
2151
2152 endCommandBuffer(vk, *cmdBuffer);
2153
2154 // Submit the command buffer
2155 submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
2156
2157 // Read back the results
2158 tcu::Surface surface(RENDER_WIDTH, RENDER_HEIGHT);
2159 {
2160 const tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
2161 const tcu::ConstPixelBufferAccess imgAccess(textureFormat, RENDER_WIDTH, RENDER_HEIGHT, 1,
2162 readImageAlloc->getHostPtr());
2163 invalidateAlloc(vk, device, *readImageAlloc);
2164
2165 tcu::copy(surface.getAccess(), imgAccess);
2166 }
2167
2168 // Check if the result image is all white
2169 tcu::RGBA white(tcu::RGBA::white());
2170 int numFailedPixels = 0;
2171
2172 for (int y = 0; y < surface.getHeight(); y++)
2173 {
2174 for (int x = 0; x < surface.getWidth(); x++)
2175 {
2176 if (surface.getPixel(x, y) != white)
2177 numFailedPixels += 1;
2178 }
2179 }
2180
2181 if (numFailedPixels > 0)
2182 {
2183 tcu::TestLog &log = m_context.getTestContext().getLog();
2184 log << tcu::TestLog::Image("Image", "Rendered image", surface);
2185 log << tcu::TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels"
2186 << tcu::TestLog::EndMessage;
2187
2188 for (size_t blockNdx = 0; blockNdx < m_layout.blocks.size(); blockNdx++)
2189 {
2190 const BlockLayoutEntry &block = m_layout.blocks[blockNdx];
2191 log << tcu::TestLog::Message << "Block index: " << blockNdx << " infos: " << block
2192 << tcu::TestLog::EndMessage;
2193 }
2194
2195 for (size_t uniformNdx = 0; uniformNdx < m_layout.uniforms.size(); uniformNdx++)
2196 {
2197 log << tcu::TestLog::Message << "Uniform index: " << uniformNdx
2198 << " infos: " << m_layout.uniforms[uniformNdx] << tcu::TestLog::EndMessage;
2199 }
2200
2201 return tcu::TestStatus::fail("Detected non-white pixels");
2202 }
2203 else
2204 return tcu::TestStatus::pass("Full white image ok");
2205 }
2206
addUniformData(uint32_t size,const void * dataPtr)2207 vk::VkDescriptorBufferInfo UniformBlockCaseInstance::addUniformData(uint32_t size, const void *dataPtr)
2208 {
2209 const VkDevice vkDevice = m_context.getDevice();
2210 const DeviceInterface &vk = m_context.getDeviceInterface();
2211
2212 Move<VkBuffer> buffer = createBuffer(m_context, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
2213 de::MovePtr<Allocation> alloc = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
2214
2215 deMemcpy(alloc->getHostPtr(), dataPtr, size);
2216 flushAlloc(vk, vkDevice, *alloc);
2217
2218 const VkDescriptorBufferInfo descriptor = {
2219 *buffer, // VkBuffer buffer;
2220 0u, // VkDeviceSize offset;
2221 size, // VkDeviceSize range;
2222
2223 };
2224
2225 m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
2226 m_uniformAllocs.push_back(AllocationSp(alloc.release()));
2227
2228 return descriptor;
2229 }
2230
createRenderPass(vk::VkFormat format) const2231 vk::Move<VkRenderPass> UniformBlockCaseInstance::createRenderPass(vk::VkFormat format) const
2232 {
2233 const VkDevice vkDevice = m_context.getDevice();
2234 const DeviceInterface &vk = m_context.getDeviceInterface();
2235
2236 return vk::makeRenderPass(vk, vkDevice, format);
2237 }
2238
createFramebuffer(vk::VkRenderPass renderPass,vk::VkImageView colorImageView) const2239 vk::Move<VkFramebuffer> UniformBlockCaseInstance::createFramebuffer(vk::VkRenderPass renderPass,
2240 vk::VkImageView colorImageView) const
2241 {
2242 const VkDevice vkDevice = m_context.getDevice();
2243 const DeviceInterface &vk = m_context.getDeviceInterface();
2244
2245 const VkFramebufferCreateInfo framebufferParams = {
2246 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
2247 DE_NULL, // const void* pNext;
2248 0u, // VkFramebufferCreateFlags flags;
2249 renderPass, // VkRenderPass renderPass;
2250 1u, // uint32_t attachmentCount;
2251 &colorImageView, // const VkImageView* pAttachments;
2252 RENDER_WIDTH, // uint32_t width;
2253 RENDER_HEIGHT, // uint32_t height;
2254 1u // uint32_t layers;
2255 };
2256
2257 return vk::createFramebuffer(vk, vkDevice, &framebufferParams);
2258 }
2259
createDescriptorSetLayout(void) const2260 vk::Move<VkDescriptorSetLayout> UniformBlockCaseInstance::createDescriptorSetLayout(void) const
2261 {
2262 int numBlocks = (int)m_layout.blocks.size();
2263 int lastBindingNdx = -1;
2264 std::vector<int> lengths;
2265
2266 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2267 {
2268 const BlockLayoutEntry &block = m_layout.blocks[blockNdx];
2269
2270 if (block.bindingNdx == lastBindingNdx)
2271 {
2272 lengths.back()++;
2273 }
2274 else
2275 {
2276 lengths.push_back(1);
2277 lastBindingNdx = block.bindingNdx;
2278 }
2279 }
2280
2281 vk::DescriptorSetLayoutBuilder layoutBuilder;
2282 for (size_t i = 0; i < lengths.size(); i++)
2283 {
2284 if (lengths[i] > 0)
2285 {
2286 layoutBuilder.addArrayBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, lengths[i], vk::VK_SHADER_STAGE_ALL);
2287 }
2288 else
2289 {
2290 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
2291 }
2292 }
2293
2294 return layoutBuilder.build(m_context.getDeviceInterface(), m_context.getDevice());
2295 }
2296
createDescriptorPool(void) const2297 vk::Move<VkDescriptorPool> UniformBlockCaseInstance::createDescriptorPool(void) const
2298 {
2299 vk::DescriptorPoolBuilder poolBuilder;
2300
2301 return poolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (int)m_layout.blocks.size())
2302 .build(m_context.getDeviceInterface(), m_context.getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
2303 1u);
2304 }
2305
createPipeline(vk::VkShaderModule vtxShaderModule,vk::VkShaderModule fragShaderModule,vk::VkPipelineLayout pipelineLayout,vk::VkRenderPass renderPass) const2306 vk::Move<VkPipeline> UniformBlockCaseInstance::createPipeline(vk::VkShaderModule vtxShaderModule,
2307 vk::VkShaderModule fragShaderModule,
2308 vk::VkPipelineLayout pipelineLayout,
2309 vk::VkRenderPass renderPass) const
2310 {
2311 const VkDevice vkDevice = m_context.getDevice();
2312 const DeviceInterface &vk = m_context.getDeviceInterface();
2313
2314 const std::vector<VkViewport> viewports(1, makeViewport(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT)));
2315 const std::vector<VkRect2D> scissors(1, makeRect2D(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT)));
2316
2317 return vk::makeGraphicsPipeline(vk, // const DeviceInterface& vk
2318 vkDevice, // const VkDevice device
2319 pipelineLayout, // const VkPipelineLayout pipelineLayout
2320 vtxShaderModule, // const VkShaderModule vertexShaderModule
2321 DE_NULL, // const VkShaderModule tessellationControlShaderModule
2322 DE_NULL, // const VkShaderModule tessellationEvalShaderModule
2323 DE_NULL, // const VkShaderModule geometryShaderModule
2324 fragShaderModule, // const VkShaderModule fragmentShaderModule
2325 renderPass, // const VkRenderPass renderPass
2326 viewports, // const std::vector<VkViewport>& viewports
2327 scissors); // const std::vector<VkRect2D>& scissors
2328 }
2329
2330 } // namespace
2331
2332 // UniformBlockCase.
2333
UniformBlockCase(tcu::TestContext & testCtx,const std::string & name,BufferMode bufferMode,MatrixLoadFlags matrixLoadFlag,bool shuffleUniformMembers)2334 UniformBlockCase::UniformBlockCase(tcu::TestContext &testCtx, const std::string &name, BufferMode bufferMode,
2335 MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers)
2336 : TestCase(testCtx, name)
2337 , m_bufferMode(bufferMode)
2338 , m_matrixLoadFlag(matrixLoadFlag)
2339 , m_shuffleUniformMembers(shuffleUniformMembers)
2340 {
2341 }
2342
~UniformBlockCase(void)2343 UniformBlockCase::~UniformBlockCase(void)
2344 {
2345 }
2346
initPrograms(vk::SourceCollections & programCollection) const2347 void UniformBlockCase::initPrograms(vk::SourceCollections &programCollection) const
2348 {
2349 DE_ASSERT(!m_vertShaderSource.empty());
2350 DE_ASSERT(!m_fragShaderSource.empty());
2351
2352 vk::ShaderBuildOptions::Flags flags = vk::ShaderBuildOptions::Flags(0);
2353 // TODO(dneto): If these tests ever use LAYOUT_RELAXED, then add support
2354 // here as well.
2355 if (usesBlockLayout(LAYOUT_SCALAR))
2356 flags = vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS;
2357 else if (usesBlockLayout(LAYOUT_STD430))
2358 flags = vk::ShaderBuildOptions::FLAG_ALLOW_STD430_UBOS;
2359
2360 programCollection.glslSources.add("vert")
2361 << glu::VertexSource(m_vertShaderSource)
2362 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion,
2363 vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
2364
2365 programCollection.glslSources.add("frag")
2366 << glu::FragmentSource(m_fragShaderSource)
2367 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion,
2368 vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
2369 }
2370
createInstance(Context & context) const2371 TestInstance *UniformBlockCase::createInstance(Context &context) const
2372 {
2373 if (!context.get16BitStorageFeatures().uniformAndStorageBuffer16BitAccess && usesBlockLayout(LAYOUT_16BIT_STORAGE))
2374 TCU_THROW(NotSupportedError, "uniformAndStorageBuffer16BitAccess not supported");
2375 if (!context.get8BitStorageFeatures().uniformAndStorageBuffer8BitAccess && usesBlockLayout(LAYOUT_8BIT_STORAGE))
2376 TCU_THROW(NotSupportedError, "uniformAndStorageBuffer8BitAccess not supported");
2377 if (!context.getScalarBlockLayoutFeatures().scalarBlockLayout &&
2378 !context.getUniformBufferStandardLayoutFeatures().uniformBufferStandardLayout && usesBlockLayout(LAYOUT_STD430))
2379 TCU_THROW(NotSupportedError, "std430 not supported");
2380 if (!context.getScalarBlockLayoutFeatures().scalarBlockLayout && usesBlockLayout(LAYOUT_SCALAR))
2381 TCU_THROW(NotSupportedError, "scalarBlockLayout not supported");
2382 if (usesBlockLayout(LAYOUT_DESCRIPTOR_INDEXING) &&
2383 (!context.getDescriptorIndexingFeatures().shaderUniformBufferArrayNonUniformIndexing ||
2384 !context.getDescriptorIndexingFeatures().runtimeDescriptorArray))
2385 TCU_THROW(NotSupportedError, "Descriptor indexing over uniform buffer not supported");
2386
2387 return new UniformBlockCaseInstance(context, m_bufferMode, m_uniformLayout, m_blockPointers);
2388 }
2389
delayedInit(void)2390 void UniformBlockCase::delayedInit(void)
2391 {
2392 const int vec4Alignment = (int)sizeof(uint32_t) * 4;
2393
2394 // Compute reference layout.
2395 computeReferenceLayout(m_uniformLayout, m_interface);
2396
2397 // Assign storage for reference values.
2398 {
2399 int totalSize = 0;
2400 for (std::vector<BlockLayoutEntry>::const_iterator blockIter = m_uniformLayout.blocks.begin();
2401 blockIter != m_uniformLayout.blocks.end(); blockIter++)
2402 {
2403 // Include enough space for alignment of individual blocks
2404 totalSize += deRoundUp32(blockIter->size, vec4Alignment);
2405 }
2406 m_data.resize(totalSize);
2407
2408 // Pointers for each block.
2409 int curOffset = 0;
2410 for (int blockNdx = 0; blockNdx < (int)m_uniformLayout.blocks.size(); blockNdx++)
2411 {
2412 m_blockPointers[blockNdx] = &m_data[0] + curOffset;
2413
2414 // Ensure each new block starts fully aligned to avoid unaligned host accesses
2415 curOffset += deRoundUp32(m_uniformLayout.blocks[blockNdx].size, vec4Alignment);
2416 }
2417 }
2418
2419 // Generate values.
2420 generateValues(m_uniformLayout, m_blockPointers, 1 /* seed */);
2421
2422 // Generate shaders.
2423 m_vertShaderSource =
2424 generateVertexShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag, m_shuffleUniformMembers);
2425 m_fragShaderSource = generateFragmentShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag,
2426 m_shuffleUniformMembers);
2427 }
2428
2429 } // namespace ubo
2430 } // namespace vkt
2431