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