1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
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 Descriptor pool tests
22 *//*--------------------------------------------------------------------*/
23
24#include "vktApiDescriptorPoolTests.hpp"
25#include "vktTestCaseUtil.hpp"
26
27#include "vkDefs.hpp"
28#include "vkRef.hpp"
29#include "vkRefUtil.hpp"
30#include "vkPlatform.hpp"
31#include "vkDeviceUtil.hpp"
32#include "vkQueryUtil.hpp"
33
34#include "tcuCommandLine.hpp"
35#include "tcuTestLog.hpp"
36#include "tcuPlatform.hpp"
37
38#include "deUniquePtr.hpp"
39#include "deSharedPtr.hpp"
40#include "deInt32.h"
41#include "deSTLUtil.hpp"
42
43#define VK_DESCRIPTOR_TYPE_LAST (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT + 1)
44
45namespace vkt
46{
47namespace api
48{
49
50namespace
51{
52
53using namespace std;
54using namespace vk;
55
56struct ResetDescriptorPoolTestParams
57{
58	ResetDescriptorPoolTestParams	(deUint32 numIterations, bool freeDescriptorSets = false)
59		: m_numIterations		(numIterations)
60		, m_freeDescriptorSets	(freeDescriptorSets)
61	{}
62
63	deUint32	m_numIterations;
64	bool		m_freeDescriptorSets;
65};
66
67void checkSupportFreeDescriptorSets (Context& context, const ResetDescriptorPoolTestParams params)
68{
69#ifdef CTS_USES_VULKANSC
70	if(params.m_freeDescriptorSets && context.getDeviceVulkanSC10Properties().recycleDescriptorSetMemory == VK_FALSE )
71		TCU_THROW(NotSupportedError, "vkFreeDescriptorSets not supported");
72#else
73	DE_UNREF(context);
74	DE_UNREF(params);
75#endif // CTS_USES_VULKANSC
76}
77
78tcu::TestStatus resetDescriptorPoolTest (Context& context, const ResetDescriptorPoolTestParams params)
79{
80#ifndef CTS_USES_VULKANSC
81	const deUint32				numDescriptorSetsPerIter = 2048;
82#else
83	const deUint32				numDescriptorSetsPerIter = 100;
84#endif // CTS_USES_VULKANSC
85	const DeviceInterface&		vkd						 = context.getDeviceInterface();
86	const VkDevice				device					 = context.getDevice();
87
88	const VkDescriptorPoolSize descriptorPoolSize =
89	{
90		VK_DESCRIPTOR_TYPE_SAMPLER, // type
91		numDescriptorSetsPerIter	// descriptorCount
92	};
93
94	const VkDescriptorPoolCreateInfo descriptorPoolInfo =
95	{
96		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,																			// sType
97		NULL,																													// pNext
98		(params.m_freeDescriptorSets) ? (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT : 0u,	// flags
99		numDescriptorSetsPerIter,																								// maxSets
100		1,																														// poolSizeCount
101		&descriptorPoolSize																										// pPoolSizes
102	};
103
104	{
105		const Unique<VkDescriptorPool> descriptorPool(
106			createDescriptorPool(vkd, device,
107								 &descriptorPoolInfo));
108
109		const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding =
110		{
111			0,							// binding
112			VK_DESCRIPTOR_TYPE_SAMPLER, // descriptorType
113			1,							// descriptorCount
114			VK_SHADER_STAGE_ALL,		// stageFlags
115			NULL						// pImmutableSamplers
116		};
117
118		const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo =
119		{
120			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,	// sType
121			NULL,													// pNext
122			0,														// flags
123			1,														// bindingCount
124			&descriptorSetLayoutBinding								// pBindings
125		};
126
127		{
128			typedef de::SharedPtr<Unique<VkDescriptorSetLayout> > DescriptorSetLayoutPtr;
129
130			vector<DescriptorSetLayoutPtr> descriptorSetLayouts;
131			descriptorSetLayouts.reserve(numDescriptorSetsPerIter);
132
133			for (deUint32 ndx = 0; ndx < numDescriptorSetsPerIter; ++ndx)
134			{
135				descriptorSetLayouts.push_back(
136					DescriptorSetLayoutPtr(
137						new Unique<VkDescriptorSetLayout>(
138							createDescriptorSetLayout(vkd, device,
139													  &descriptorSetLayoutInfo))));
140			}
141
142			vector<VkDescriptorSetLayout> descriptorSetLayoutsRaw(numDescriptorSetsPerIter);
143
144			for (deUint32 ndx = 0; ndx < numDescriptorSetsPerIter; ++ndx)
145			{
146				descriptorSetLayoutsRaw[ndx] = **descriptorSetLayouts[ndx];
147			}
148
149			const VkDescriptorSetAllocateInfo descriptorSetInfo =
150			{
151				VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // sType
152				NULL,											// pNext
153				*descriptorPool,								// descriptorPool
154				numDescriptorSetsPerIter,						// descriptorSetCount
155				&descriptorSetLayoutsRaw[0]						// pSetLayouts
156			};
157
158			vector<VkDescriptorSet> testSets(numDescriptorSetsPerIter);
159
160			for (deUint32 ndx = 0; ndx < params.m_numIterations; ++ndx)
161			{
162				if (ndx % 1024 == 0) context.getTestContext().touchWatchdog();
163				// The test should crash in this loop at some point if there is a memory leak
164				VK_CHECK(vkd.allocateDescriptorSets(device, &descriptorSetInfo, &testSets[0]));
165				if (params.m_freeDescriptorSets)
166					VK_CHECK(vkd.freeDescriptorSets(device, *descriptorPool, 1, &testSets[0]));
167				VK_CHECK(vkd.resetDescriptorPool(device, *descriptorPool, 0));
168			}
169
170		}
171	}
172
173	// If it didn't crash, pass
174	return tcu::TestStatus::pass("Pass");
175}
176
177tcu::TestStatus outOfPoolMemoryTest (Context& context)
178{
179	const DeviceInterface&	vkd							= context.getDeviceInterface();
180	const VkDevice			device						= context.getDevice();
181	const bool				expectOutOfPoolMemoryError	= context.isDeviceFunctionalitySupported("VK_KHR_maintenance1");
182	deUint32				numErrorsReturned			= 0;
183
184	const struct FailureCase
185	{
186		deUint32	poolDescriptorCount;		//!< total number of descriptors (of a given type) in the descriptor pool
187		deUint32	poolMaxSets;				//!< max number of descriptor sets that can be allocated from the pool
188		deUint32	bindingCount;				//!< number of bindings per descriptor set layout
189		deUint32	bindingDescriptorCount;		//!< number of descriptors in a binding (array size) (in all bindings)
190		deUint32	descriptorSetCount;			//!< number of descriptor sets to allocate
191		string		description;				//!< the log message for this failure condition
192	} failureCases[] =
193	{
194		//	pool			pool		binding		binding		alloc set
195		//	descr. count	max sets	count		array size	count
196		{	4u,				2u,			1u,			1u,			3u,		"Out of descriptor sets",											},
197		{	3u,				4u,			1u,			1u,			4u,		"Out of descriptors (due to the number of sets)",					},
198		{	2u,				1u,			3u,			1u,			1u,		"Out of descriptors (due to the number of bindings)",				},
199		{	3u,				2u,			1u,			2u,			2u,		"Out of descriptors (due to descriptor array size)",				},
200		{	5u,				1u,			2u,			3u,			1u,		"Out of descriptors (due to descriptor array size in all bindings)",},
201	};
202
203	context.getTestContext().getLog()
204		<< tcu::TestLog::Message
205		<< "Creating a descriptor pool with insufficient resources. Descriptor set allocation is likely to fail."
206		<< tcu::TestLog::EndMessage;
207
208	for (deUint32 failureCaseNdx = 0u; failureCaseNdx < DE_LENGTH_OF_ARRAY(failureCases); ++failureCaseNdx)
209	{
210		const FailureCase& params = failureCases[failureCaseNdx];
211		context.getTestContext().getLog() << tcu::TestLog::Message << "Checking: " << params.description << tcu::TestLog::EndMessage;
212
213		for (VkDescriptorType	descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
214								descriptorType < VK_DESCRIPTOR_TYPE_LAST;
215								descriptorType = static_cast<VkDescriptorType>(descriptorType + 1))
216		{
217			context.getTestContext().getLog() << tcu::TestLog::Message << "- " << getDescriptorTypeName(descriptorType) << tcu::TestLog::EndMessage;
218
219			const VkDescriptorPoolSize					descriptorPoolSize =
220			{
221				descriptorType,												// type
222				params.poolDescriptorCount,									// descriptorCount
223			};
224
225			const VkDescriptorPoolCreateInfo			descriptorPoolCreateInfo =
226			{
227				VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,				// VkStructureType                sType;
228				DE_NULL,													// const void*                    pNext;
229				(VkDescriptorPoolCreateFlags)0,								// VkDescriptorPoolCreateFlags    flags;
230				params.poolMaxSets,											// uint32_t                       maxSets;
231				1u,															// uint32_t                       poolSizeCount;
232				&descriptorPoolSize,										// const VkDescriptorPoolSize*    pPoolSizes;
233			};
234
235			const Unique<VkDescriptorPool>				descriptorPool(createDescriptorPool(vkd, device, &descriptorPoolCreateInfo));
236
237			VkShaderStageFlags stageFlags = (descriptorType != VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ? VK_SHADER_STAGE_ALL : VK_SHADER_STAGE_FRAGMENT_BIT;
238			const VkDescriptorSetLayoutBinding			descriptorSetLayoutBinding =
239			{
240				0u,															// uint32_t              binding;
241				descriptorType,												// VkDescriptorType      descriptorType;
242				params.bindingDescriptorCount,								// uint32_t              descriptorCount;
243				stageFlags,													// VkShaderStageFlags    stageFlags;
244				DE_NULL,													// const VkSampler*      pImmutableSamplers;
245			};
246
247			vector<VkDescriptorSetLayoutBinding>	descriptorSetLayoutBindings (params.bindingCount, descriptorSetLayoutBinding);
248
249			for (deUint32 binding = 0; binding < deUint32(descriptorSetLayoutBindings.size()); ++binding)
250			{
251				descriptorSetLayoutBindings[binding].binding = binding;
252			}
253
254			const VkDescriptorSetLayoutCreateInfo		descriptorSetLayoutInfo =
255			{
256				VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,		// VkStructureType                        sType;
257				DE_NULL,													// const void*                            pNext;
258				(VkDescriptorSetLayoutCreateFlags)0,						// VkDescriptorSetLayoutCreateFlags       flags;
259				static_cast<deUint32>(descriptorSetLayoutBindings.size()),	// uint32_t                               bindingCount;
260				&descriptorSetLayoutBindings[0],							// const VkDescriptorSetLayoutBinding*    pBindings;
261			};
262
263			const Unique<VkDescriptorSetLayout>			descriptorSetLayout	(createDescriptorSetLayout(vkd, device, &descriptorSetLayoutInfo));
264			const vector<VkDescriptorSetLayout>			rawSetLayouts		(params.descriptorSetCount, *descriptorSetLayout);
265			vector<VkDescriptorSet>						rawDescriptorSets	(params.descriptorSetCount, DE_NULL);
266
267			const VkDescriptorSetAllocateInfo			descriptorSetAllocateInfo =
268			{
269				VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,				// VkStructureType                 sType;
270				DE_NULL,													// const void*                     pNext;
271				*descriptorPool,											// VkDescriptorPool                descriptorPool;
272				static_cast<deUint32>(rawSetLayouts.size()),				// uint32_t                        descriptorSetCount;
273				&rawSetLayouts[0],											// const VkDescriptorSetLayout*    pSetLayouts;
274			};
275
276			const VkResult result = vkd.allocateDescriptorSets(device, &descriptorSetAllocateInfo, &rawDescriptorSets[0]);
277
278			if (result != VK_SUCCESS)
279			{
280				++numErrorsReturned;
281
282				if (expectOutOfPoolMemoryError && result != VK_ERROR_OUT_OF_POOL_MEMORY)
283					return tcu::TestStatus::fail("Expected VK_ERROR_OUT_OF_POOL_MEMORY but got " + string(getResultName(result)) + " instead");
284			}
285			else
286				context.getTestContext().getLog() << tcu::TestLog::Message << "  Allocation was successful anyway" << tcu::TestLog::EndMessage;
287		}
288	}
289
290	if (numErrorsReturned == 0u)
291		return tcu::TestStatus::pass("Not validated");
292	else
293		return tcu::TestStatus::pass("Pass");
294}
295
296tcu::TestStatus zeroPoolSizeCount(Context& context)
297{
298	const DeviceInterface&	vkd = context.getDeviceInterface();
299	const VkDevice			device = context.getDevice();
300
301	const VkDescriptorPoolCreateInfo			descriptorPoolCreateInfo =
302	{
303		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,				// VkStructureType                sType;
304		DE_NULL,													// const void*                    pNext;
305		VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,			// VkDescriptorPoolCreateFlags    flags;
306		1u,															// uint32_t                       maxSets;
307		0u,															// uint32_t                       poolSizeCount;
308		DE_NULL,													// const VkDescriptorPoolSize*    pPoolSizes;
309	};
310
311	// Test a pool can be created for empty descriptor sets.
312	const Unique<VkDescriptorPool>				descriptorPool(createDescriptorPool(vkd, device, &descriptorPoolCreateInfo));
313
314	const VkDescriptorSetLayoutCreateInfo		descriptorSetLayoutInfo =
315	{
316		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,		// VkStructureType                        sType;
317		DE_NULL,													// const void*                            pNext;
318		(VkDescriptorSetLayoutCreateFlags)0,						// VkDescriptorSetLayoutCreateFlags       flags;
319		0u,															// uint32_t                               bindingCount;
320		DE_NULL,													// const VkDescriptorSetLayoutBinding*    pBindings;
321	};
322
323	const Unique<VkDescriptorSetLayout>			descriptorSetLayout(createDescriptorSetLayout(vkd, device, &descriptorSetLayoutInfo));
324
325	const VkDescriptorSetAllocateInfo			descriptorSetAllocateInfo =
326	{
327		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,				// VkStructureType                 sType;
328		DE_NULL,													// const void*                     pNext;
329		*descriptorPool,											// VkDescriptorPool                descriptorPool;
330		1u,															// uint32_t                        descriptorSetCount;
331		&descriptorSetLayout.get(),									// const VkDescriptorSetLayout*    pSetLayouts;
332	};
333
334	// Create an empty descriptor set from the pool.
335	VkDescriptorSet descriptorSet;
336	VkResult result = vkd.allocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet);
337	if (result != VK_SUCCESS)
338		return tcu::TestStatus::fail("Expected vkAllocateDescriptorSets to return VK_SUCCESS but got " + string(getResultName(result)) + " instead");
339
340	// Free the empty descriptor set back to the pool.
341	result = vkd.freeDescriptorSets(device, *descriptorPool, 1, &descriptorSet);
342	if (result != VK_SUCCESS)
343		return tcu::TestStatus::fail("Expected vkFreeDescriptorSets to return VK_SUCCESS but got " + string(getResultName(result)) + " instead");
344
345	return tcu::TestStatus::pass("Pass");
346}
347
348} // anonymous
349
350tcu::TestCaseGroup* createDescriptorPoolTests (tcu::TestContext& testCtx)
351{
352	const deUint32 numIterationsHigh = 4096;
353
354	de::MovePtr<tcu::TestCaseGroup> descriptorPoolTests(
355		new tcu::TestCaseGroup(testCtx, "descriptor_pool"));
356
357	// Test 2 cycles of vkAllocateDescriptorSets and vkResetDescriptorPool (should pass)
358	addFunctionCase(descriptorPoolTests.get(),
359					"repeated_reset_short",
360					checkSupportFreeDescriptorSets,
361					resetDescriptorPoolTest, ResetDescriptorPoolTestParams(2U));
362	// Test many cycles of vkAllocateDescriptorSets and vkResetDescriptorPool
363	addFunctionCase(descriptorPoolTests.get(),
364					"repeated_reset_long",
365					checkSupportFreeDescriptorSets,
366					resetDescriptorPoolTest, ResetDescriptorPoolTestParams(numIterationsHigh));
367	// Test 2 cycles of vkAllocateDescriptorSets, vkFreeDescriptorSets and vkResetDescriptorPool (should pass)
368	addFunctionCase(descriptorPoolTests.get(),
369					"repeated_free_reset_short",
370					checkSupportFreeDescriptorSets,
371					resetDescriptorPoolTest, ResetDescriptorPoolTestParams(2U, true));
372	// Test many cycles of vkAllocateDescriptorSets, vkFreeDescriptorSets and vkResetDescriptorPool
373	addFunctionCase(descriptorPoolTests.get(),
374					"repeated_free_reset_long",
375					checkSupportFreeDescriptorSets,
376					resetDescriptorPoolTest, ResetDescriptorPoolTestParams(numIterationsHigh, true));
377	// Test that when we run out of descriptors a correct error code is returned
378	addFunctionCase(descriptorPoolTests.get(),
379					"out_of_pool_memory",
380					outOfPoolMemoryTest);
381	// Test a descriptor pool object can be created with zero pools without error or crash
382	addFunctionCase(descriptorPoolTests.get(),
383					"zero_pool_size_count",
384					zeroPoolSizeCount);
385
386	return descriptorPoolTests.release();
387}
388
389} // api
390} // vkt
391