• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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