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