1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Khronos Group
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief API Maintenance3 Check test - checks structs and function from VK_KHR_maintenance3
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuTestLog.hpp"
25
26 #include "vkQueryUtil.hpp"
27
28 #include "vktApiMaintenance3Check.hpp"
29 #include "vktTestCase.hpp"
30 #include "vktTestCaseUtil.hpp"
31
32 #include <sstream>
33 #include <limits>
34 #include <utility>
35 #include <algorithm>
36 #include <map>
37 #include <set>
38
39 using namespace vk;
40
41 namespace vkt
42 {
43
44 namespace api
45 {
46
47 namespace
48 {
49 using ::std::string;
50 using ::std::vector;
51 using ::std::map;
52 using ::std::set;
53 using ::std::ostringstream;
54 using ::std::make_pair;
55
56 typedef vk::VkPhysicalDeviceProperties DevProp1;
57 typedef vk::VkPhysicalDeviceProperties2 DevProp2;
58 typedef vk::VkPhysicalDeviceMaintenance3Properties MaintDevProp3;
59 typedef vk::VkPhysicalDeviceFeatures2 DevFeat2;
60 #ifndef CTS_USES_VULKANSC
61 typedef vk::VkPhysicalDeviceInlineUniformBlockFeaturesEXT DevIubFeat;
62 typedef vk::VkPhysicalDeviceInlineUniformBlockPropertiesEXT DevIubProp;
63 #endif // CTS_USES_VULKANSC
64
65 // These variables are equal to minimal values for maxMemoryAllocationSize and maxPerSetDescriptors
66 constexpr deUint32 maxMemoryAllocationSize = 1073741824u;
67 constexpr deUint32 maxDescriptorsInSet = 1024u;
68 #ifndef CTS_USES_VULKANSC
69 constexpr deUint32 maxReasonableInlineUniformBlocks = 64u;
70 #else
71 constexpr deUint32 maxReasonableBindingCounts = 1024u;
72 #endif // CTS_USES_VULKANSC
73 using TypeSet = set<vk::VkDescriptorType>;
74
75 // Structure representing an implementation limit, like maxPerStageDescriptorSamplers. It has a maximum value
76 // obtained at runtime and a remaining number of descriptors, which starts with the same count and decreases
77 // as we assign descriptor counts to the different types. A limit is affected by (or itself affects) one or more
78 // descriptor types. Note a type may be involved in several limits, and a limit may affect several types.
79 struct Limit
80 {
Limitvkt::api::__anonc32e75cb0111::Limit81 Limit(const string& name_, deUint32 maxValue_, const TypeSet& affectedTypes_)
82 : name(name_), maxValue(maxValue_), remaining(maxValue_), affectedTypes(affectedTypes_)
83 {}
84
85 const string name;
86 const deUint32 maxValue;
87 deUint32 remaining;
88 const TypeSet affectedTypes;
89 };
90
91 // Structure representing how many descriptors have been assigned to the given type. The type is "alive" during
92 // descriptor count assignment if more descriptors can be added to the type without hitting any limit affected
93 // by the type. Once at least one of the limits is reached, no more descriptors can be assigned to the type and
94 // the type is no longer considered "alive".
95 struct TypeState
96 {
TypeStatevkt::api::__anonc32e75cb0111::TypeState97 TypeState(vk::VkDescriptorType type_)
98 : type(type_), alive(true), count(0u)
99 {}
100
101 const vk::VkDescriptorType type;
102 bool alive;
103 deUint32 count;
104 };
105
106 using TypeCounts = map<vk::VkDescriptorType, TypeState>;
107 using LimitsVector = vector<Limit>;
108
109 // Get the subset of alive types from the given map.
getAliveTypes(const TypeCounts & typeCounts)110 TypeSet getAliveTypes (const TypeCounts& typeCounts)
111 {
112 TypeSet aliveTypes;
113 for (const auto& typeCount : typeCounts)
114 {
115 if (typeCount.second.alive)
116 aliveTypes.insert(typeCount.first);
117 }
118 return aliveTypes;
119 }
120
121 // Get the subset of alive types for a specific limit, among the set of types affected by the limit.
getAliveTypesForLimit(const Limit & limit,const TypeSet & aliveTypes)122 TypeSet getAliveTypesForLimit (const Limit& limit, const TypeSet& aliveTypes)
123 {
124 TypeSet subset;
125 for (const auto& type : limit.affectedTypes)
126 {
127 if (aliveTypes.find(type) != aliveTypes.end())
128 subset.insert(type);
129 }
130 return subset;
131 }
132
133 // Distribute descriptor counts as evenly as possible among the given set of types, taking into account the
134 // given limits.
distributeCounts(LimitsVector & limits,TypeCounts & typeCounts)135 void distributeCounts (LimitsVector& limits, TypeCounts& typeCounts)
136 {
137 using IncrementsMap = map<vk::VkDescriptorType, deUint32>;
138 TypeSet aliveTypes;
139
140 while ((aliveTypes = getAliveTypes(typeCounts)).size() > 0u)
141 {
142 // Calculate the maximum increment per alive descriptor type. This involves iterating over the limits and
143 // finding out how many more descriptors can be distributed among the affected types that are still alive
144 // for the limit. For each type, remember the lowest possible increment.
145 IncrementsMap increments;
146 for (const auto& type : aliveTypes)
147 increments[type] = std::numeric_limits<deUint32>::max();
148
149 TypeSet aliveTypesForLimit;
150
151 for (const auto& limit : limits)
152 {
153 if (limit.remaining == 0u)
154 continue;
155
156 aliveTypesForLimit = getAliveTypesForLimit(limit, aliveTypes);
157 if (aliveTypesForLimit.empty())
158 continue;
159
160 // Distribute remaining count evenly among alive types.
161 deUint32 maxIncrement = limit.remaining / static_cast<deUint32>(aliveTypesForLimit.size());
162 if (maxIncrement == 0u)
163 {
164 // More types than remaining descriptors. Assign 1 to the first affected types and 0 to the rest.
165 deUint32 remaining = limit.remaining;
166 for (const auto& type : aliveTypesForLimit)
167 {
168 if (remaining > 0u && increments[type] > 0u)
169 {
170 increments[type] = 1u;
171 --remaining;
172 }
173 else
174 {
175 increments[type] = 0u;
176 }
177 }
178 }
179 else
180 {
181 // Find the lowest possible increment taking into account all limits.
182 for (const auto& type : aliveTypesForLimit)
183 {
184 if (increments[type] > maxIncrement)
185 increments[type] = maxIncrement;
186 }
187 }
188 }
189
190 // Apply the calculated increments per descriptor type, decreasing the remaining descriptors for each
191 // limit affected by the type, and switching types to the not-alive state when a limit is hit.
192 for (const auto& inc : increments)
193 {
194 const vk::VkDescriptorType& type = inc.first;
195 const deUint32& increment = inc.second;
196
197 // Increase type count.
198 auto iter = typeCounts.find(type);
199 DE_ASSERT(iter != typeCounts.end());
200 iter->second.count += increment;
201
202 for (auto& limit : limits)
203 {
204 // Decrease remaining descriptors for affected limits.
205 if (limit.affectedTypes.find(type) != limit.affectedTypes.end())
206 {
207 DE_ASSERT(increment <= limit.remaining);
208 limit.remaining -= increment;
209 }
210 if (limit.remaining == 0u)
211 {
212 // Limit hit, switch affected types to not-alive.
213 for (const auto& affectedType : limit.affectedTypes)
214 {
215 auto tc = typeCounts.find(affectedType);
216 if (tc != typeCounts.end())
217 tc->second.alive = false;
218 }
219 }
220 }
221 }
222 }
223 }
224
225 // Create a limits vector based on runtime limit information for the device.
buildLimitsVector(const DevProp1 & prop1,const DevIubProp & iubProp,const MaintDevProp3 & maintProp3)226 LimitsVector buildLimitsVector ( const DevProp1& prop1,
227 #ifndef CTS_USES_VULKANSC
228 const DevIubProp& iubProp,
229 #endif // CTS_USES_VULKANSC
230 const MaintDevProp3& maintProp3)
231 {
232 static const TypeSet samplerTypes = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLER };
233 static const TypeSet sampledImageTypes = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER };
234 static const TypeSet uniformBufferTypes = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
235 static const TypeSet storageBufferTypes = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
236 static const TypeSet storageImageTypes = { vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER };
237 static const TypeSet inputAttachmentTypes = { vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT };
238 #ifndef CTS_USES_VULKANSC
239 static const TypeSet inlineUniformBlockTypes = { vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT };
240 #endif // CTS_USES_VULKANSC
241 static const TypeSet dynamicUniformBuffer = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
242 static const TypeSet dynamicStorageBuffer = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
243 static const TypeSet allTypesButIUB = {
244 vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
245 vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
246 vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
247 vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
248 vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
249 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
250 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
251 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
252 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
253 vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
254 };
255 static const TypeSet allTypes = {
256 vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
257 vk::VK_DESCRIPTOR_TYPE_SAMPLER,
258 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
259 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
260 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
261 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
262 vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
263 vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
264 vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
265 vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
266 vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
267 #ifndef CTS_USES_VULKANSC
268 vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
269 #endif // CTS_USES_VULKANSC
270 };
271
272 LimitsVector limits = {
273 {
274 "maxPerStageDescriptorSamplers",
275 prop1.limits.maxPerStageDescriptorSamplers,
276 samplerTypes
277 },
278 {
279 "maxDescriptorSetSamplers",
280 prop1.limits.maxDescriptorSetSamplers,
281 samplerTypes
282 },
283 {
284 "maxPerStageDescriptorSampledImages",
285 prop1.limits.maxPerStageDescriptorSampledImages,
286 sampledImageTypes
287 },
288 {
289 "maxDescriptorSetSampledImages",
290 prop1.limits.maxDescriptorSetSampledImages,
291 sampledImageTypes
292 },
293 {
294 "maxPerStageDescriptorUniformBuffers",
295 prop1.limits.maxPerStageDescriptorUniformBuffers,
296 uniformBufferTypes
297 },
298 {
299 "maxDescriptorSetUniformBuffers",
300 prop1.limits.maxDescriptorSetUniformBuffers,
301 uniformBufferTypes
302 },
303 {
304 "maxPerStageDescriptorStorageBuffers",
305 prop1.limits.maxPerStageDescriptorStorageBuffers,
306 storageBufferTypes
307 },
308 {
309 "maxDescriptorSetStorageBuffers",
310 prop1.limits.maxDescriptorSetStorageBuffers,
311 storageBufferTypes
312 },
313 {
314 "maxPerStageDescriptorStorageImages",
315 prop1.limits.maxPerStageDescriptorStorageImages,
316 storageImageTypes
317 },
318 {
319 "maxDescriptorSetStorageImages",
320 prop1.limits.maxDescriptorSetStorageImages,
321 storageImageTypes
322 },
323 {
324 "maxPerStageDescriptorInputAttachments",
325 prop1.limits.maxPerStageDescriptorInputAttachments,
326 inputAttachmentTypes
327 },
328 {
329 "maxDescriptorSetInputAttachments",
330 prop1.limits.maxDescriptorSetInputAttachments,
331 inputAttachmentTypes
332 },
333 {
334 "maxDescriptorSetUniformBuffersDynamic",
335 prop1.limits.maxDescriptorSetUniformBuffersDynamic,
336 dynamicUniformBuffer
337 },
338 {
339 "maxDescriptorSetStorageBuffersDynamic",
340 prop1.limits.maxDescriptorSetStorageBuffersDynamic,
341 dynamicStorageBuffer
342 },
343 #ifndef CTS_USES_VULKANSC
344 // Removed from Vulkan SC test set: VK_EXT_inline_uniform_block extension removed from Vulkan SC
345 {
346 "maxPerStageDescriptorInlineUniformBlocks",
347 iubProp.maxPerStageDescriptorInlineUniformBlocks,
348 inlineUniformBlockTypes
349 },
350 {
351 "maxDescriptorSetInlineUniformBlocks",
352 iubProp.maxDescriptorSetInlineUniformBlocks,
353 inlineUniformBlockTypes
354 },
355 #endif // CTS_USES_VULKANSC
356 {
357 "maxPerStageResources",
358 prop1.limits.maxPerStageResources,
359 allTypesButIUB
360 },
361 {
362 "maxPerSetDescriptors",
363 maintProp3.maxPerSetDescriptors,
364 allTypes
365 },
366 };
367
368 return limits;
369 }
370
371 // Create a vector of bindings by constructing the system limits and distributing descriptor counts.
calculateBindings(const DevProp1 & prop1,const DevIubProp & iubProp,const MaintDevProp3 & maintProp3,const vector<vk::VkDescriptorType> & types)372 vector<vk::VkDescriptorSetLayoutBinding> calculateBindings( const DevProp1& prop1,
373 #ifndef CTS_USES_VULKANSC
374 const DevIubProp& iubProp,
375 #endif // CTS_USES_VULKANSC
376 const MaintDevProp3& maintProp3,
377 const vector<vk::VkDescriptorType> &types)
378 {
379 LimitsVector limits = buildLimitsVector(prop1,
380 #ifndef CTS_USES_VULKANSC
381 iubProp,
382 #endif // CTS_USES_VULKANSC
383 maintProp3);
384
385 TypeCounts typeCounts;
386
387 for (const auto& type : types)
388 typeCounts.emplace(make_pair(type, TypeState(type)));
389
390 distributeCounts(limits, typeCounts);
391
392 #ifdef CTS_USES_VULKANSC
393 // limit the number of binding counts, so that descriptorSetLayoutBindingRequestCount and descriptorSetLayoutBindingLimit won't be too big
394 for (auto& tc : typeCounts)
395 tc.second.count = de::min(tc.second.count, maxReasonableBindingCounts);
396 #endif // CTS_USES_VULKANSC
397
398 deUint32 bindingNumber = 0u;
399 vector<vk::VkDescriptorSetLayoutBinding> bindings;
400 for (const auto& tc : typeCounts)
401 {
402 #ifndef CTS_USES_VULKANSC
403 if (tc.first != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
404 #else
405 if (true)
406 #endif // CTS_USES_VULKANSC
407 {
408 vk::VkDescriptorSetLayoutBinding b;
409 b.binding = bindingNumber;
410 b.descriptorCount = tc.second.count;
411 b.descriptorType = tc.first;
412 b.pImmutableSamplers = DE_NULL;
413 b.stageFlags = vk::VK_SHADER_STAGE_ALL;
414
415 bindings.push_back(b);
416 }
417 else
418 {
419 // Inline uniform blocks are special because descriptorCount represents the size of that block.
420 // The only way of creating several blocks is by adding more structures to the list instead of creating an array.
421 size_t firstAdded = bindings.size();
422 bindings.resize(firstAdded + tc.second.count);
423 for (deUint32 i = 0u; i < tc.second.count; ++i)
424 {
425 vk::VkDescriptorSetLayoutBinding& b = bindings[firstAdded + i];
426 b.binding = bindingNumber + i;
427 b.descriptorCount = 4u; // For inline uniform blocks, this must be a multiple of 4 according to the spec.
428 b.descriptorType = tc.first;
429 b.pImmutableSamplers = DE_NULL;
430 b.stageFlags = vk::VK_SHADER_STAGE_ALL;
431 }
432 }
433 bindingNumber += tc.second.count;
434 }
435
436 return bindings;
437 }
438
439 // Get a textual description with descriptor counts per type.
getBindingsDescription(const vector<VkDescriptorSetLayoutBinding> & bindings)440 string getBindingsDescription (const vector<VkDescriptorSetLayoutBinding>& bindings)
441 {
442 map<vk::VkDescriptorType, deUint32> typeCount;
443 deUint32 totalCount = 0u;
444 deUint32 count;
445 for (const auto& b : bindings)
446 {
447 auto iter = typeCount.find(b.descriptorType);
448 if (iter == typeCount.end())
449 iter = typeCount.insert(make_pair(b.descriptorType, (deUint32)0)).first;
450 #ifndef CTS_USES_VULKANSC
451 count = ((b.descriptorType == vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) ? 1u : b.descriptorCount);
452 #else
453 count = b.descriptorCount;
454 #endif // CTS_USES_VULKANSC
455 iter->second += count;
456 totalCount += count;
457 }
458
459 deUint32 i = 0;
460 ostringstream combStr;
461
462 combStr << "{ Descriptors: " << totalCount << ", [";
463 for (const auto& tc : typeCount)
464 combStr << (i++ ? ", " : " ") << tc.first << ": " << tc.second;
465 combStr << " ] }";
466
467 return combStr.str();
468 }
469
470 class Maintenance3StructTestInstance : public TestInstance
471 {
472 public:
Maintenance3StructTestInstance(Context & ctx)473 Maintenance3StructTestInstance (Context& ctx)
474 : TestInstance (ctx)
475 {}
iterate(void)476 virtual tcu::TestStatus iterate (void)
477 {
478 tcu::TestLog& log = m_context.getTestContext().getLog();
479
480 // set values to be a bit smaller than required minimum values
481 MaintDevProp3 maintProp3 =
482 {
483 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
484 DE_NULL, //void* pNext;
485 maxDescriptorsInSet - 1u, //deUint32 maxPerSetDescriptors;
486 maxMemoryAllocationSize - 1u //VkDeviceSize maxMemoryAllocationSize;
487 };
488
489 DevProp2 prop2;
490 deMemset(&prop2, 0, sizeof(prop2)); // zero the structure
491 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
492 prop2.pNext = &maintProp3;
493
494 m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &prop2);
495
496 if (maintProp3.maxMemoryAllocationSize < maxMemoryAllocationSize)
497 return tcu::TestStatus::fail("Fail");
498
499 if (maintProp3.maxPerSetDescriptors < maxDescriptorsInSet)
500 return tcu::TestStatus::fail("Fail");
501
502 log << tcu::TestLog::Message << "maxMemoryAllocationSize: " << maintProp3.maxMemoryAllocationSize << tcu::TestLog::EndMessage;
503 log << tcu::TestLog::Message << "maxPerSetDescriptors: " << maintProp3.maxPerSetDescriptors << tcu::TestLog::EndMessage;
504 return tcu::TestStatus::pass("Pass");
505 }
506 };
507
508 class Maintenance3StructTestCase : public TestCase
509 {
510 public:
Maintenance3StructTestCase(tcu::TestContext & testCtx)511 Maintenance3StructTestCase (tcu::TestContext& testCtx)
512 : TestCase(testCtx, "maintenance3_properties")
513 {}
514
~Maintenance3StructTestCase(void)515 virtual ~Maintenance3StructTestCase (void)
516 {}
checkSupport(Context & ctx) const517 virtual void checkSupport (Context& ctx) const
518 {
519 ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
520 }
createInstance(Context & ctx) const521 virtual TestInstance* createInstance (Context& ctx) const
522 {
523 return new Maintenance3StructTestInstance(ctx);
524 }
525
526 private:
527 };
528
529 class Maintenance3DescriptorTestInstance : public TestInstance
530 {
531 public:
Maintenance3DescriptorTestInstance(Context & ctx)532 Maintenance3DescriptorTestInstance (Context& ctx)
533 : TestInstance(ctx)
534 {}
iterate(void)535 virtual tcu::TestStatus iterate (void)
536 {
537 const auto& vki = m_context.getInstanceInterface();
538 const auto& vkd = m_context.getDeviceInterface();
539 const auto& physicalDevice = m_context.getPhysicalDevice();
540 const auto& device = m_context.getDevice();
541 auto& log = m_context.getTestContext().getLog();
542
543 #ifndef CTS_USES_VULKANSC
544 bool iubSupported = false;
545
546 if (m_context.isDeviceFunctionalitySupported("VK_EXT_inline_uniform_block"))
547 {
548 DevIubFeat iubFeatures =
549 {
550 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
551 DE_NULL,
552 0u,
553 0u
554 };
555
556 DevFeat2 features2 =
557 {
558 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
559 &iubFeatures,
560 VkPhysicalDeviceFeatures()
561 };
562
563 vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
564 iubSupported = (iubFeatures.inlineUniformBlock == VK_TRUE);
565 }
566
567 DevIubProp devIubProp =
568 {
569 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT, // VkStructureType sType;
570 DE_NULL, // void* pNext;
571 0u, // deUint32 maxInlineUniformBlockSize;
572 0u, // deUint32 maxPerStageDescriptorInlineUniformBlocks;
573 0u, // deUint32 maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
574 0u, // deUint32 maxDescriptorSetInlineUniformBlocks;
575 0u // deUint32 maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
576 };
577 #endif // CTS_USES_VULKANSC
578
579 MaintDevProp3 maintProp3 =
580 {
581 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
582 #ifndef CTS_USES_VULKANSC
583 (iubSupported ? &devIubProp : DE_NULL), //void* pNext;
584 #else
585 DE_NULL, //void* pNext;
586 #endif // CTS_USES_VULKANSC
587 maxDescriptorsInSet, //deUint32 maxPerSetDescriptors;
588 maxMemoryAllocationSize //VkDeviceSize maxMemoryAllocationSize;
589 };
590
591 DevProp2 prop2 =
592 {
593 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, //VkStructureType sType;
594 &maintProp3, //void* pNext;
595 VkPhysicalDeviceProperties() //VkPhysicalDeviceProperties properties;
596 };
597
598 vki.getPhysicalDeviceProperties2(physicalDevice, &prop2);
599
600 vector<VkDescriptorType> descriptorTypes = {
601 VK_DESCRIPTOR_TYPE_SAMPLER,
602 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
603 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
604 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
605 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
606 VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
607 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
608 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
609 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
610 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
611 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
612 };
613 #ifndef CTS_USES_VULKANSC
614 if (iubSupported)
615 descriptorTypes.push_back(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
616 #endif // CTS_USES_VULKANSC
617
618 // VkDescriptorSetLayoutCreateInfo setup
619 vk::VkDescriptorSetLayoutCreateInfo pCreateInfo =
620 {
621 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, //VkStructureType sType;
622 DE_NULL, //const void* pNext;
623 0u, //VkDescriptorSetLayoutCreateFlags flags;
624 0u, //deUint32 bindingCount;
625 DE_NULL //const VkDescriptorSetLayoutBinding* pBindings;
626 };
627
628 // VkDescriptorSetLayoutSupport setup
629 vk::VkDescriptorSetLayoutSupport pSupport =
630 {
631 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, //VkStructureType sType;
632 DE_NULL, //void* pNext;
633 VK_FALSE //VkBool32 supported;
634 };
635
636 // Check every combination maximizing descriptor counts.
637 for (size_t combSize = 1; combSize <= descriptorTypes.size(); ++combSize)
638 {
639 // Create a vector of selectors with combSize elements set to true.
640 vector<bool> selectors(descriptorTypes.size(), false);
641 std::fill(begin(selectors), begin(selectors) + combSize, true);
642
643 // Iterate over every permutation of selectors for that combination size.
644 do
645 {
646 vector<vk::VkDescriptorType> types;
647 for (size_t i = 0; i < selectors.size(); ++i)
648 {
649 if (selectors[i])
650 types.push_back(descriptorTypes[i]);
651 }
652
653 #ifndef CTS_USES_VULKANSC
654 // Due to inline uniform blocks being unable to form arrays and each one of them needing its own
655 // VkDescriptorSetLayoutBinding structure, we will limit when to test them.
656 if (std::find(begin(types), end(types), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) != types.end() &&
657 devIubProp.maxPerStageDescriptorInlineUniformBlocks > maxReasonableInlineUniformBlocks &&
658 combSize > 1u && combSize < descriptorTypes.size())
659 {
660 continue;
661 }
662 #endif // CTS_USES_VULKANSC
663
664 vector<vk::VkDescriptorSetLayoutBinding> bindings = calculateBindings(prop2.properties,
665 #ifndef CTS_USES_VULKANSC
666 devIubProp,
667 #endif
668 maintProp3, types);
669 string description = getBindingsDescription(bindings);
670 log << tcu::TestLog::Message << "Testing combination: " << description << tcu::TestLog::EndMessage;
671
672 pCreateInfo.bindingCount = static_cast<deUint32>(bindings.size());
673 pCreateInfo.pBindings = bindings.data();
674
675 vkd.getDescriptorSetLayoutSupport(device, &pCreateInfo, &pSupport);
676 if (pSupport.supported == VK_FALSE)
677 {
678 ostringstream msg;
679 msg << "Failed to use the following descriptor type counts: " << description;
680 return tcu::TestStatus::fail(msg.str());
681 }
682 } while (std::prev_permutation(begin(selectors), end(selectors)));
683 }
684
685 return tcu::TestStatus::pass("Pass");
686 }
687
688 };
689
690 class Maintenance3DescriptorTestCase : public TestCase
691 {
692
693 public:
Maintenance3DescriptorTestCase(tcu::TestContext & testCtx)694 Maintenance3DescriptorTestCase (tcu::TestContext& testCtx)
695 : TestCase(testCtx, "descriptor_set")
696 {}
~Maintenance3DescriptorTestCase(void)697 virtual ~Maintenance3DescriptorTestCase (void)
698 {}
checkSupport(Context & ctx) const699 virtual void checkSupport (Context& ctx) const
700 {
701 ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
702 }
createInstance(Context & ctx) const703 virtual TestInstance* createInstance (Context& ctx) const
704 {
705 return new Maintenance3DescriptorTestInstance(ctx);
706 }
707 };
708
709 struct CountLayoutSupportParams
710 {
711 const VkDescriptorType descriptorType;
712 const bool extraBindings;
713 const bool useVariableSize;
714 };
715
checkSupportCountLayoutSupport(Context & context,CountLayoutSupportParams params)716 void checkSupportCountLayoutSupport (Context& context, CountLayoutSupportParams params)
717 {
718 context.requireDeviceFunctionality("VK_KHR_maintenance3");
719 context.requireDeviceFunctionality("VK_EXT_descriptor_indexing");
720
721 if (params.useVariableSize)
722 {
723 const auto& indexingFeatures = context.getDescriptorIndexingFeatures();
724 if (!indexingFeatures.descriptorBindingVariableDescriptorCount)
725 TCU_THROW(NotSupportedError, "descriptorBindingVariableDescriptorCount not supported");
726 }
727
728 if (params.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
729 context.requireDeviceFunctionality("VK_EXT_inline_uniform_block");
730 }
731
732 struct SetLayoutSupportAndCount
733 {
734 const bool supported;
735 const uint32_t maxVariableDescriptorCount;
736 };
737
getSetLayoutSupportAndCount(Context & context,const VkDescriptorSetLayoutCreateInfo * setLayoutCreateInfo)738 SetLayoutSupportAndCount getSetLayoutSupportAndCount (Context& context, const VkDescriptorSetLayoutCreateInfo* setLayoutCreateInfo)
739 {
740 VkDescriptorSetVariableDescriptorCountLayoutSupport countLayoutSupport = initVulkanStructure();
741 VkDescriptorSetLayoutSupport setLayoutSupport = initVulkanStructure(&countLayoutSupport);
742
743 // Set a garbage value in the maxVariableDescriptorCount member, to verify it's not simply left untouched by the implementation.
744 countLayoutSupport.maxVariableDescriptorCount = std::numeric_limits<uint32_t>::max();
745 context.getDeviceInterface().getDescriptorSetLayoutSupport(context.getDevice(), setLayoutCreateInfo, &setLayoutSupport);
746 return SetLayoutSupportAndCount{ (setLayoutSupport.supported == VK_TRUE), countLayoutSupport.maxVariableDescriptorCount };
747 }
748
testCountLayoutSupport(Context & context,CountLayoutSupportParams params)749 tcu::TestStatus testCountLayoutSupport (Context& context, CountLayoutSupportParams params)
750 {
751 VkShaderStageFlags stages = 0u;
752
753 // The shader stages are probably not very relevant. This is an attempt at setting some varied but plausible stages anyway.
754 switch (params.descriptorType)
755 {
756 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
757 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
758 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
759 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
760 stages = VK_SHADER_STAGE_COMPUTE_BIT;
761 break;
762
763 case VK_DESCRIPTOR_TYPE_SAMPLER:
764 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
765 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
766 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
767 stages = VK_SHADER_STAGE_FRAGMENT_BIT;
768 break;
769
770 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
771 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
772 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
773 case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
774 stages = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
775 break;
776
777 default:
778 DE_ASSERT(false);
779 break;
780 };
781
782 std::vector<VkDescriptorSetLayoutBinding> bindings;
783 std::vector<VkDescriptorBindingFlags> bindingFlags;
784
785 if (params.extraBindings)
786 {
787 // Add a few uniform buffers to the mix.
788 const auto extraBindingCount = 3u;
789
790 for (uint32_t i = 0u; i < extraBindingCount; ++i)
791 {
792 bindings.emplace_back(
793 VkDescriptorSetLayoutBinding {
794 de::sizeU32(bindings), // uint32_t binding;
795 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // VkDescriptorType descriptorType;
796 1u, // uint32_t descriptorCount;
797 stages, // VkShaderStageFlags stageFlags;
798 nullptr, // const VkSampler* pImmutableSamplers;
799 });
800 bindingFlags.push_back(0u);
801 }
802 }
803
804 // VUID-VkDescriptorSetLayoutBinding-descriptorType-02209 mandates descriptorCount to be a multiple of 4 when using inline
805 // uniform blocks.
806 const auto descriptorCount = ((params.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ? 4u : 1u);
807
808 bindings.emplace_back(
809 VkDescriptorSetLayoutBinding {
810 de::sizeU32(bindings), // uint32_t binding;
811 params.descriptorType, // VkDescriptorType descriptorType;
812 descriptorCount, // uint32_t descriptorCount;
813 stages, // VkShaderStageFlags stageFlags;
814 nullptr, // const VkSampler* pImmutableSamplers;
815 });
816 bindingFlags.push_back(params.useVariableSize ? static_cast<VkDescriptorBindingFlags>(VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) : 0u);
817
818 const VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo =
819 {
820 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, // VkStructureType sType;
821 nullptr, // const void* pNext;
822 de::sizeU32(bindingFlags), // uint32_t bindingCount;
823 de::dataOrNull(bindingFlags), // const VkDescriptorBindingFlags* pBindingFlags;
824 };
825
826 const VkDescriptorSetLayoutCreateInfo layoutCreateInfo =
827 {
828 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
829 &bindingFlagsInfo, // const void* pNext;
830 0u, // VkDescriptorSetLayoutCreateFlags flags;
831 de::sizeU32(bindings), // uint32_t bindingCount;
832 de::dataOrNull(bindings), // const VkDescriptorSetLayoutBinding* pBindings;
833 };
834
835 // Check the layout is supported.
836 const auto normalValues = getSetLayoutSupportAndCount(context, &layoutCreateInfo);
837 if (!normalValues.supported)
838 TCU_THROW(NotSupportedError, "Set layout not supported");
839
840 if (!params.useVariableSize)
841 {
842 if (normalValues.maxVariableDescriptorCount != 0u)
843 TCU_FAIL("Nonzero maxVariableDescriptorCount when using no variable descriptor counts");
844 }
845 else
846 {
847 // Verify if we switch from one to zero descriptors we get the same reply back.
848 bindings.back().descriptorCount = 0u;
849 const auto zeroDescriptorValues = getSetLayoutSupportAndCount(context, &layoutCreateInfo);
850
851 if (!zeroDescriptorValues.supported)
852 TCU_FAIL("Implementation reports support with one descriptor and no support with zero descriptors");
853
854 if (zeroDescriptorValues.maxVariableDescriptorCount != normalValues.maxVariableDescriptorCount)
855 TCU_FAIL("Mismatch in maxVariableDescriptorCount when using zero and one as descriptor counts");
856
857 // Verify we can create a descriptor set with the promised amount of descriptors.
858 bindings.back().descriptorCount = normalValues.maxVariableDescriptorCount;
859 const auto maxDescriptorValues = getSetLayoutSupportAndCount(context, &layoutCreateInfo);
860
861 if (!maxDescriptorValues.supported)
862 TCU_FAIL("Implementation reports no support when using the maximum allowed size");
863
864 if (maxDescriptorValues.maxVariableDescriptorCount != normalValues.maxVariableDescriptorCount)
865 TCU_FAIL("Mismatch in maxVariableDescriptorCount when using one and the maximum descriptor counts");
866 }
867
868 return tcu::TestStatus::pass("Pass");
869 }
870
getDescriptorTypeShortName(const VkDescriptorType descType)871 std::string getDescriptorTypeShortName (const VkDescriptorType descType)
872 {
873 static const auto prefixLen = strlen("VK_DESCRIPTOR_TYPE_");
874 std::string name = getDescriptorTypeName(descType);
875
876 name = name.substr(prefixLen);
877 return de::toLower(name);
878 }
879
880 } // anonymous
881
createMaintenance3Tests(tcu::TestContext & testCtx)882 tcu::TestCaseGroup* createMaintenance3Tests (tcu::TestContext& testCtx)
883 {
884 de::MovePtr<tcu::TestCaseGroup> main3Tests(new tcu::TestCaseGroup(testCtx, "maintenance3_check"));
885 main3Tests->addChild(new Maintenance3StructTestCase(testCtx));
886 main3Tests->addChild(new Maintenance3DescriptorTestCase(testCtx));
887
888 {
889 const VkDescriptorType descriptorTypes[] =
890 {
891 VK_DESCRIPTOR_TYPE_SAMPLER,
892 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
893 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
894 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
895 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
896 VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
897 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
898 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
899 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
900 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
901 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
902 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK,
903 };
904
905 for (const auto& descriptorType : descriptorTypes)
906 for (const auto& extraBindings : { false, true })
907 for (const auto& useVariableSize : { false, true })
908 {
909 const auto extraBindingsSuffix = (extraBindings ? "_extra_bindings" : "");
910 const auto variableSizeSuffix = (useVariableSize ? "" : "_no_variable_size");
911 const auto caseName = "support_count_" + getDescriptorTypeShortName(descriptorType) + extraBindingsSuffix + variableSizeSuffix;
912 const CountLayoutSupportParams params { descriptorType, extraBindings, useVariableSize };
913
914 addFunctionCase(main3Tests.get(), caseName.c_str(), checkSupportCountLayoutSupport, testCountLayoutSupport, params);
915 }
916 }
917
918 return main3Tests.release();
919 }
920
921 } // api
922 } // vkt
923