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
31 #include <sstream>
32 #include <limits>
33 #include <utility>
34 #include <algorithm>
35 #include <map>
36 #include <set>
37
38 using namespace vk;
39
40 namespace vkt
41 {
42
43 namespace api
44 {
45
46 namespace
47 {
48 using ::std::string;
49 using ::std::vector;
50 using ::std::map;
51 using ::std::set;
52 using ::std::ostringstream;
53 using ::std::make_pair;
54
55 typedef vk::VkPhysicalDeviceProperties DevProp1;
56 typedef vk::VkPhysicalDeviceProperties2 DevProp2;
57 typedef vk::VkPhysicalDeviceMaintenance3Properties MaintDevProp3;
58 typedef vk::VkPhysicalDeviceFeatures2 DevFeat2;
59 #ifndef CTS_USES_VULKANSC
60 typedef vk::VkPhysicalDeviceInlineUniformBlockFeaturesEXT DevIubFeat;
61 typedef vk::VkPhysicalDeviceInlineUniformBlockPropertiesEXT DevIubProp;
62 #endif // CTS_USES_VULKANSC
63
64 // These variables are equal to minimal values for maxMemoryAllocationSize and maxPerSetDescriptors
65 constexpr deUint32 maxMemoryAllocationSize = 1073741824u;
66 constexpr deUint32 maxDescriptorsInSet = 1024u;
67 #ifndef CTS_USES_VULKANSC
68 constexpr deUint32 maxReasonableInlineUniformBlocks = 64u;
69 #else
70 constexpr deUint32 maxReasonableBindingCounts = 1024u;
71 #endif // CTS_USES_VULKANSC
72 using TypeSet = set<vk::VkDescriptorType>;
73
74 // Structure representing an implementation limit, like maxPerStageDescriptorSamplers. It has a maximum value
75 // obtained at runtime and a remaining number of descriptors, which starts with the same count and decreases
76 // as we assign descriptor counts to the different types. A limit is affected by (or itself affects) one or more
77 // descriptor types. Note a type may be involved in several limits, and a limit may affect several types.
78 struct Limit
79 {
Limitvkt::api::__anonf118a9b70111::Limit80 Limit(const string& name_, deUint32 maxValue_, const TypeSet& affectedTypes_)
81 : name(name_), maxValue(maxValue_), remaining(maxValue_), affectedTypes(affectedTypes_)
82 {}
83
84 const string name;
85 const deUint32 maxValue;
86 deUint32 remaining;
87 const TypeSet affectedTypes;
88 };
89
90 // Structure representing how many descriptors have been assigned to the given type. The type is "alive" during
91 // descriptor count assignment if more descriptors can be added to the type without hitting any limit affected
92 // by the type. Once at least one of the limits is reached, no more descriptors can be assigned to the type and
93 // the type is no longer considered "alive".
94 struct TypeState
95 {
TypeStatevkt::api::__anonf118a9b70111::TypeState96 TypeState(vk::VkDescriptorType type_)
97 : type(type_), alive(true), count(0u)
98 {}
99
100 const vk::VkDescriptorType type;
101 bool alive;
102 deUint32 count;
103 };
104
105 using TypeCounts = map<vk::VkDescriptorType, TypeState>;
106 using LimitsVector = vector<Limit>;
107
108 // Get the subset of alive types from the given map.
getAliveTypes(const TypeCounts & typeCounts)109 TypeSet getAliveTypes (const TypeCounts& typeCounts)
110 {
111 TypeSet aliveTypes;
112 for (const auto& typeCount : typeCounts)
113 {
114 if (typeCount.second.alive)
115 aliveTypes.insert(typeCount.first);
116 }
117 return aliveTypes;
118 }
119
120 // 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)121 TypeSet getAliveTypesForLimit (const Limit& limit, const TypeSet& aliveTypes)
122 {
123 TypeSet subset;
124 for (const auto& type : limit.affectedTypes)
125 {
126 if (aliveTypes.find(type) != aliveTypes.end())
127 subset.insert(type);
128 }
129 return subset;
130 }
131
132 // Distribute descriptor counts as evenly as possible among the given set of types, taking into account the
133 // given limits.
distributeCounts(LimitsVector & limits,TypeCounts & typeCounts)134 void distributeCounts (LimitsVector& limits, TypeCounts& typeCounts)
135 {
136 using IncrementsMap = map<vk::VkDescriptorType, deUint32>;
137 TypeSet aliveTypes;
138
139 while ((aliveTypes = getAliveTypes(typeCounts)).size() > 0u)
140 {
141 // Calculate the maximum increment per alive descriptor type. This involves iterating over the limits and
142 // finding out how many more descriptors can be distributed among the affected types that are still alive
143 // for the limit. For each type, remember the lowest possible increment.
144 IncrementsMap increments;
145 for (const auto& type : aliveTypes)
146 increments[type] = std::numeric_limits<deUint32>::max();
147
148 TypeSet aliveTypesForLimit;
149
150 for (const auto& limit : limits)
151 {
152 if (limit.remaining == 0u)
153 continue;
154
155 aliveTypesForLimit = getAliveTypesForLimit(limit, aliveTypes);
156 if (aliveTypesForLimit.empty())
157 continue;
158
159 // Distribute remaining count evenly among alive types.
160 deUint32 maxIncrement = limit.remaining / static_cast<deUint32>(aliveTypesForLimit.size());
161 if (maxIncrement == 0u)
162 {
163 // More types than remaining descriptors. Assign 1 to the first affected types and 0 to the rest.
164 deUint32 remaining = limit.remaining;
165 for (const auto& type : aliveTypesForLimit)
166 {
167 if (remaining > 0u && increments[type] > 0u)
168 {
169 increments[type] = 1u;
170 --remaining;
171 }
172 else
173 {
174 increments[type] = 0u;
175 }
176 }
177 }
178 else
179 {
180 // Find the lowest possible increment taking into account all limits.
181 for (const auto& type : aliveTypesForLimit)
182 {
183 if (increments[type] > maxIncrement)
184 increments[type] = maxIncrement;
185 }
186 }
187 }
188
189 // Apply the calculated increments per descriptor type, decreasing the remaining descriptors for each
190 // limit affected by the type, and switching types to the not-alive state when a limit is hit.
191 for (const auto& inc : increments)
192 {
193 const vk::VkDescriptorType& type = inc.first;
194 const deUint32& increment = inc.second;
195
196 // Increase type count.
197 auto iter = typeCounts.find(type);
198 DE_ASSERT(iter != typeCounts.end());
199 iter->second.count += increment;
200
201 for (auto& limit : limits)
202 {
203 // Decrease remaining descriptors for affected limits.
204 if (limit.affectedTypes.find(type) != limit.affectedTypes.end())
205 {
206 DE_ASSERT(increment <= limit.remaining);
207 limit.remaining -= increment;
208 }
209 if (limit.remaining == 0u)
210 {
211 // Limit hit, switch affected types to not-alive.
212 for (const auto& affectedType : limit.affectedTypes)
213 {
214 auto tc = typeCounts.find(affectedType);
215 if (tc != typeCounts.end())
216 tc->second.alive = false;
217 }
218 }
219 }
220 }
221 }
222 }
223
224 // Create a limits vector based on runtime limit information for the device.
buildLimitsVector(const DevProp1 & prop1,const DevIubProp & iubProp,const MaintDevProp3 & maintProp3)225 LimitsVector buildLimitsVector ( const DevProp1& prop1,
226 #ifndef CTS_USES_VULKANSC
227 const DevIubProp& iubProp,
228 #endif // CTS_USES_VULKANSC
229 const MaintDevProp3& maintProp3)
230 {
231 static const TypeSet samplerTypes = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLER };
232 static const TypeSet sampledImageTypes = { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER };
233 static const TypeSet uniformBufferTypes = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
234 static const TypeSet storageBufferTypes = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
235 static const TypeSet storageImageTypes = { vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER };
236 static const TypeSet inputAttachmentTypes = { vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT };
237 #ifndef CTS_USES_VULKANSC
238 static const TypeSet inlineUniformBlockTypes = { vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT };
239 #endif // CTS_USES_VULKANSC
240 static const TypeSet dynamicUniformBuffer = { vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC };
241 static const TypeSet dynamicStorageBuffer = { vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC };
242 static const TypeSet allTypesButIUB = {
243 vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
244 vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
245 vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
246 vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
247 vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
248 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
249 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
250 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
251 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
252 vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
253 };
254 static const TypeSet allTypes = {
255 vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
256 vk::VK_DESCRIPTOR_TYPE_SAMPLER,
257 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
258 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
259 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
260 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
261 vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
262 vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
263 vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
264 vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
265 vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
266 #ifndef CTS_USES_VULKANSC
267 vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
268 #endif // CTS_USES_VULKANSC
269 };
270
271 LimitsVector limits = {
272 {
273 "maxPerStageDescriptorSamplers",
274 prop1.limits.maxPerStageDescriptorSamplers,
275 samplerTypes
276 },
277 {
278 "maxDescriptorSetSamplers",
279 prop1.limits.maxDescriptorSetSamplers,
280 samplerTypes
281 },
282 {
283 "maxPerStageDescriptorSampledImages",
284 prop1.limits.maxPerStageDescriptorSampledImages,
285 sampledImageTypes
286 },
287 {
288 "maxDescriptorSetSampledImages",
289 prop1.limits.maxDescriptorSetSampledImages,
290 sampledImageTypes
291 },
292 {
293 "maxPerStageDescriptorUniformBuffers",
294 prop1.limits.maxPerStageDescriptorUniformBuffers,
295 uniformBufferTypes
296 },
297 {
298 "maxDescriptorSetUniformBuffers",
299 prop1.limits.maxDescriptorSetUniformBuffers,
300 uniformBufferTypes
301 },
302 {
303 "maxPerStageDescriptorStorageBuffers",
304 prop1.limits.maxPerStageDescriptorStorageBuffers,
305 storageBufferTypes
306 },
307 {
308 "maxDescriptorSetStorageBuffers",
309 prop1.limits.maxDescriptorSetStorageBuffers,
310 storageBufferTypes
311 },
312 {
313 "maxPerStageDescriptorStorageImages",
314 prop1.limits.maxPerStageDescriptorStorageImages,
315 storageImageTypes
316 },
317 {
318 "maxDescriptorSetStorageImages",
319 prop1.limits.maxDescriptorSetStorageImages,
320 storageImageTypes
321 },
322 {
323 "maxPerStageDescriptorInputAttachments",
324 prop1.limits.maxPerStageDescriptorInputAttachments,
325 inputAttachmentTypes
326 },
327 {
328 "maxDescriptorSetInputAttachments",
329 prop1.limits.maxDescriptorSetInputAttachments,
330 inputAttachmentTypes
331 },
332 {
333 "maxDescriptorSetUniformBuffersDynamic",
334 prop1.limits.maxDescriptorSetUniformBuffersDynamic,
335 dynamicUniformBuffer
336 },
337 {
338 "maxDescriptorSetStorageBuffersDynamic",
339 prop1.limits.maxDescriptorSetStorageBuffersDynamic,
340 dynamicStorageBuffer
341 },
342 #ifndef CTS_USES_VULKANSC
343 // Removed from Vulkan SC test set: VK_EXT_inline_uniform_block extension removed from Vulkan SC
344 {
345 "maxPerStageDescriptorInlineUniformBlocks",
346 iubProp.maxPerStageDescriptorInlineUniformBlocks,
347 inlineUniformBlockTypes
348 },
349 {
350 "maxDescriptorSetInlineUniformBlocks",
351 iubProp.maxDescriptorSetInlineUniformBlocks,
352 inlineUniformBlockTypes
353 },
354 #endif // CTS_USES_VULKANSC
355 {
356 "maxPerStageResources",
357 prop1.limits.maxPerStageResources,
358 allTypesButIUB
359 },
360 {
361 "maxPerSetDescriptors",
362 maintProp3.maxPerSetDescriptors,
363 allTypes
364 },
365 };
366
367 return limits;
368 }
369
370 // 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)371 vector<vk::VkDescriptorSetLayoutBinding> calculateBindings( const DevProp1& prop1,
372 #ifndef CTS_USES_VULKANSC
373 const DevIubProp& iubProp,
374 #endif // CTS_USES_VULKANSC
375 const MaintDevProp3& maintProp3,
376 const vector<vk::VkDescriptorType> &types)
377 {
378 LimitsVector limits = buildLimitsVector(prop1,
379 #ifndef CTS_USES_VULKANSC
380 iubProp,
381 #endif // CTS_USES_VULKANSC
382 maintProp3);
383
384 TypeCounts typeCounts;
385
386 for (const auto& type : types)
387 typeCounts.emplace(make_pair(type, TypeState(type)));
388
389 distributeCounts(limits, typeCounts);
390
391 #ifdef CTS_USES_VULKANSC
392 // limit the number of binding counts, so that descriptorSetLayoutBindingRequestCount and descriptorSetLayoutBindingLimit won't be too big
393 for (auto& tc : typeCounts)
394 tc.second.count = de::min(tc.second.count, maxReasonableBindingCounts);
395 #endif // CTS_USES_VULKANSC
396
397 deUint32 bindingNumber = 0u;
398 vector<vk::VkDescriptorSetLayoutBinding> bindings;
399 for (const auto& tc : typeCounts)
400 {
401 #ifndef CTS_USES_VULKANSC
402 if (tc.first != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
403 #else
404 if (true)
405 #endif // CTS_USES_VULKANSC
406 {
407 vk::VkDescriptorSetLayoutBinding b;
408 b.binding = bindingNumber;
409 b.descriptorCount = tc.second.count;
410 b.descriptorType = tc.first;
411 b.pImmutableSamplers = DE_NULL;
412 b.stageFlags = vk::VK_SHADER_STAGE_ALL;
413
414 bindings.push_back(b);
415 }
416 else
417 {
418 // Inline uniform blocks are special because descriptorCount represents the size of that block.
419 // The only way of creating several blocks is by adding more structures to the list instead of creating an array.
420 size_t firstAdded = bindings.size();
421 bindings.resize(firstAdded + tc.second.count);
422 for (deUint32 i = 0u; i < tc.second.count; ++i)
423 {
424 vk::VkDescriptorSetLayoutBinding& b = bindings[firstAdded + i];
425 b.binding = bindingNumber + i;
426 b.descriptorCount = 4u; // For inline uniform blocks, this must be a multiple of 4 according to the spec.
427 b.descriptorType = tc.first;
428 b.pImmutableSamplers = DE_NULL;
429 b.stageFlags = vk::VK_SHADER_STAGE_ALL;
430 }
431 }
432 bindingNumber += tc.second.count;
433 }
434
435 return bindings;
436 }
437
438 // Get a textual description with descriptor counts per type.
getBindingsDescription(const vector<VkDescriptorSetLayoutBinding> & bindings)439 string getBindingsDescription (const vector<VkDescriptorSetLayoutBinding>& bindings)
440 {
441 map<vk::VkDescriptorType, deUint32> typeCount;
442 deUint32 totalCount = 0u;
443 deUint32 count;
444 for (const auto& b : bindings)
445 {
446 auto iter = typeCount.find(b.descriptorType);
447 if (iter == typeCount.end())
448 iter = typeCount.insert(make_pair(b.descriptorType, (deUint32)0)).first;
449 #ifndef CTS_USES_VULKANSC
450 count = ((b.descriptorType == vk::VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) ? 1u : b.descriptorCount);
451 #else
452 count = b.descriptorCount;
453 #endif // CTS_USES_VULKANSC
454 iter->second += count;
455 totalCount += count;
456 }
457
458 deUint32 i = 0;
459 ostringstream combStr;
460
461 combStr << "{ Descriptors: " << totalCount << ", [";
462 for (const auto& tc : typeCount)
463 combStr << (i++ ? ", " : " ") << tc.first << ": " << tc.second;
464 combStr << " ] }";
465
466 return combStr.str();
467 }
468
469 class Maintenance3StructTestInstance : public TestInstance
470 {
471 public:
Maintenance3StructTestInstance(Context & ctx)472 Maintenance3StructTestInstance (Context& ctx)
473 : TestInstance (ctx)
474 {}
iterate(void)475 virtual tcu::TestStatus iterate (void)
476 {
477 tcu::TestLog& log = m_context.getTestContext().getLog();
478
479 // set values to be a bit smaller than required minimum values
480 MaintDevProp3 maintProp3 =
481 {
482 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
483 DE_NULL, //void* pNext;
484 maxDescriptorsInSet - 1u, //deUint32 maxPerSetDescriptors;
485 maxMemoryAllocationSize - 1u //VkDeviceSize maxMemoryAllocationSize;
486 };
487
488 DevProp2 prop2;
489 deMemset(&prop2, 0, sizeof(prop2)); // zero the structure
490 prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
491 prop2.pNext = &maintProp3;
492
493 m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &prop2);
494
495 if (maintProp3.maxMemoryAllocationSize < maxMemoryAllocationSize)
496 return tcu::TestStatus::fail("Fail");
497
498 if (maintProp3.maxPerSetDescriptors < maxDescriptorsInSet)
499 return tcu::TestStatus::fail("Fail");
500
501 log << tcu::TestLog::Message << "maxMemoryAllocationSize: " << maintProp3.maxMemoryAllocationSize << tcu::TestLog::EndMessage;
502 log << tcu::TestLog::Message << "maxPerSetDescriptors: " << maintProp3.maxPerSetDescriptors << tcu::TestLog::EndMessage;
503 return tcu::TestStatus::pass("Pass");
504 }
505 };
506
507 class Maintenance3StructTestCase : public TestCase
508 {
509 public:
Maintenance3StructTestCase(tcu::TestContext & testCtx)510 Maintenance3StructTestCase (tcu::TestContext& testCtx)
511 : TestCase(testCtx, "maintenance3_properties", "tests VkPhysicalDeviceMaintenance3Properties struct")
512 {}
513
~Maintenance3StructTestCase(void)514 virtual ~Maintenance3StructTestCase (void)
515 {}
checkSupport(Context & ctx) const516 virtual void checkSupport (Context& ctx) const
517 {
518 ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
519 }
createInstance(Context & ctx) const520 virtual TestInstance* createInstance (Context& ctx) const
521 {
522 return new Maintenance3StructTestInstance(ctx);
523 }
524
525 private:
526 };
527
528 class Maintenance3DescriptorTestInstance : public TestInstance
529 {
530 public:
Maintenance3DescriptorTestInstance(Context & ctx)531 Maintenance3DescriptorTestInstance (Context& ctx)
532 : TestInstance(ctx)
533 {}
iterate(void)534 virtual tcu::TestStatus iterate (void)
535 {
536 const auto& vki = m_context.getInstanceInterface();
537 const auto& vkd = m_context.getDeviceInterface();
538 const auto& physicalDevice = m_context.getPhysicalDevice();
539 const auto& device = m_context.getDevice();
540 auto& log = m_context.getTestContext().getLog();
541
542 #ifndef CTS_USES_VULKANSC
543 bool iubSupported = false;
544
545 if (m_context.isDeviceFunctionalitySupported("VK_EXT_inline_uniform_block"))
546 {
547 DevIubFeat iubFeatures =
548 {
549 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
550 DE_NULL,
551 0u,
552 0u
553 };
554
555 DevFeat2 features2 =
556 {
557 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
558 &iubFeatures,
559 VkPhysicalDeviceFeatures()
560 };
561
562 vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
563 iubSupported = (iubFeatures.inlineUniformBlock == VK_TRUE);
564 }
565
566 DevIubProp devIubProp =
567 {
568 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT, // VkStructureType sType;
569 DE_NULL, // void* pNext;
570 0u, // deUint32 maxInlineUniformBlockSize;
571 0u, // deUint32 maxPerStageDescriptorInlineUniformBlocks;
572 0u, // deUint32 maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
573 0u, // deUint32 maxDescriptorSetInlineUniformBlocks;
574 0u // deUint32 maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
575 };
576 #endif // CTS_USES_VULKANSC
577
578 MaintDevProp3 maintProp3 =
579 {
580 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, //VkStructureType sType;
581 #ifndef CTS_USES_VULKANSC
582 (iubSupported ? &devIubProp : DE_NULL), //void* pNext;
583 #else
584 DE_NULL, //void* pNext;
585 #endif // CTS_USES_VULKANSC
586 maxDescriptorsInSet, //deUint32 maxPerSetDescriptors;
587 maxMemoryAllocationSize //VkDeviceSize maxMemoryAllocationSize;
588 };
589
590 DevProp2 prop2 =
591 {
592 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, //VkStructureType sType;
593 &maintProp3, //void* pNext;
594 VkPhysicalDeviceProperties() //VkPhysicalDeviceProperties properties;
595 };
596
597 vki.getPhysicalDeviceProperties2(physicalDevice, &prop2);
598
599 vector<VkDescriptorType> descriptorTypes = {
600 VK_DESCRIPTOR_TYPE_SAMPLER,
601 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
602 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
603 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
604 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
605 VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
606 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
607 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
608 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
609 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
610 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
611 };
612 #ifndef CTS_USES_VULKANSC
613 if (iubSupported)
614 descriptorTypes.push_back(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
615 #endif // CTS_USES_VULKANSC
616
617 // VkDescriptorSetLayoutCreateInfo setup
618 vk::VkDescriptorSetLayoutCreateInfo pCreateInfo =
619 {
620 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, //VkStructureType sType;
621 DE_NULL, //const void* pNext;
622 0u, //VkDescriptorSetLayoutCreateFlags flags;
623 0u, //deUint32 bindingCount;
624 DE_NULL //const VkDescriptorSetLayoutBinding* pBindings;
625 };
626
627 // VkDescriptorSetLayoutSupport setup
628 vk::VkDescriptorSetLayoutSupport pSupport =
629 {
630 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, //VkStructureType sType;
631 DE_NULL, //void* pNext;
632 VK_FALSE //VkBool32 supported;
633 };
634
635 // Check every combination maximizing descriptor counts.
636 for (size_t combSize = 1; combSize <= descriptorTypes.size(); ++combSize)
637 {
638 // Create a vector of selectors with combSize elements set to true.
639 vector<bool> selectors(descriptorTypes.size(), false);
640 std::fill(begin(selectors), begin(selectors) + combSize, true);
641
642 // Iterate over every permutation of selectors for that combination size.
643 do
644 {
645 vector<vk::VkDescriptorType> types;
646 for (size_t i = 0; i < selectors.size(); ++i)
647 {
648 if (selectors[i])
649 types.push_back(descriptorTypes[i]);
650 }
651
652 #ifndef CTS_USES_VULKANSC
653 // Due to inline uniform blocks being unable to form arrays and each one of them needing its own
654 // VkDescriptorSetLayoutBinding structure, we will limit when to test them.
655 if (std::find(begin(types), end(types), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) != types.end() &&
656 devIubProp.maxPerStageDescriptorInlineUniformBlocks > maxReasonableInlineUniformBlocks &&
657 combSize > 1u && combSize < descriptorTypes.size())
658 {
659 continue;
660 }
661 #endif // CTS_USES_VULKANSC
662
663 vector<vk::VkDescriptorSetLayoutBinding> bindings = calculateBindings(prop2.properties,
664 #ifndef CTS_USES_VULKANSC
665 devIubProp,
666 #endif
667 maintProp3, types);
668 string description = getBindingsDescription(bindings);
669 log << tcu::TestLog::Message << "Testing combination: " << description << tcu::TestLog::EndMessage;
670
671 pCreateInfo.bindingCount = static_cast<deUint32>(bindings.size());
672 pCreateInfo.pBindings = bindings.data();
673
674 vkd.getDescriptorSetLayoutSupport(device, &pCreateInfo, &pSupport);
675 if (pSupport.supported == VK_FALSE)
676 {
677 ostringstream msg;
678 msg << "Failed to use the following descriptor type counts: " << description;
679 return tcu::TestStatus::fail(msg.str());
680 }
681 } while (std::prev_permutation(begin(selectors), end(selectors)));
682 }
683
684 return tcu::TestStatus::pass("Pass");
685 }
686
687 };
688
689 class Maintenance3DescriptorTestCase : public TestCase
690 {
691
692 public:
Maintenance3DescriptorTestCase(tcu::TestContext & testCtx)693 Maintenance3DescriptorTestCase (tcu::TestContext& testCtx)
694 : TestCase(testCtx, "descriptor_set", "tests vkGetDescriptorSetLayoutSupport struct")
695 {}
~Maintenance3DescriptorTestCase(void)696 virtual ~Maintenance3DescriptorTestCase (void)
697 {}
checkSupport(Context & ctx) const698 virtual void checkSupport (Context& ctx) const
699 {
700 ctx.requireDeviceFunctionality("VK_KHR_maintenance3");
701 }
createInstance(Context & ctx) const702 virtual TestInstance* createInstance (Context& ctx) const
703 {
704 return new Maintenance3DescriptorTestInstance(ctx);
705 }
706 };
707
708 } // anonymous
709
createMaintenance3Tests(tcu::TestContext & testCtx)710 tcu::TestCaseGroup* createMaintenance3Tests (tcu::TestContext& testCtx)
711 {
712 de::MovePtr<tcu::TestCaseGroup> main3Tests(new tcu::TestCaseGroup(testCtx, "maintenance3_check", "Maintenance3 Tests"));
713 main3Tests->addChild(new Maintenance3StructTestCase(testCtx));
714 main3Tests->addChild(new Maintenance3DescriptorTestCase(testCtx));
715
716 return main3Tests.release();
717 }
718
719 } // api
720 } // vkt
721