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