• 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 #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