• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group 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  vktGlobalPriorityQueueUtils.cpp
21  * \brief Global Priority Queue Utils
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktGlobalPriorityQueueUtils.hpp"
25 #include "vkImageUtil.hpp"
26 #include "vkQueryUtil.hpp"
27 #include "vkTypeUtil.hpp"
28 #include "vkDeviceUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 #include "vktTestCase.hpp"
31 #include "deStringUtil.hpp"
32 #include "tcuCommandLine.hpp"
33 #include <vector>
34 
35 using namespace vk;
36 
37 namespace vkt
38 {
39 namespace synchronization
40 {
41 
findQueueFamilyIndex(const InstanceInterface & vki,VkPhysicalDevice dev,VkQueueGlobalPriorityKHR priority,VkQueueFlags includeFlags,VkQueueFlags excludeFlags,deUint32 excludeIndex)42 deUint32 findQueueFamilyIndex (const InstanceInterface&	vki,
43 							   VkPhysicalDevice			dev,
44 							   VkQueueGlobalPriorityKHR	priority,
45 							   VkQueueFlags				includeFlags,
46 							   VkQueueFlags				excludeFlags,
47 							   deUint32					excludeIndex)
48 {
49 	deUint32 queueFamilyPropertyCount = 0;
50 	vki.getPhysicalDeviceQueueFamilyProperties2(dev, &queueFamilyPropertyCount, nullptr);
51 	DE_ASSERT(queueFamilyPropertyCount);
52 
53 	std::vector<VkQueueFamilyProperties2>					familyProperties2(queueFamilyPropertyCount);
54 	std::vector<VkQueueFamilyGlobalPriorityPropertiesKHR>	familyPriorityProperties(queueFamilyPropertyCount);
55 
56 	for (deUint32 familyIdx = 0; familyIdx < queueFamilyPropertyCount; ++familyIdx)
57 	{
58 		VkQueueFamilyGlobalPriorityPropertiesKHR* pPriorityProps = &familyPriorityProperties[familyIdx];
59 		pPriorityProps->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR;
60 
61 		VkQueueFamilyProperties2* pFamilyProps = &familyProperties2[familyIdx];
62 		pFamilyProps->sType	= VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
63 		pFamilyProps->pNext	= pPriorityProps;
64 	}
65 
66 	vki.getPhysicalDeviceQueueFamilyProperties2(dev, &queueFamilyPropertyCount, familyProperties2.data());
67 
68 	deUint32 familyFound = INVALID_UINT32;
69 
70 	for (deUint32 familyIdx = 0; familyIdx < queueFamilyPropertyCount; ++familyIdx)
71 	{
72 		if (familyIdx == excludeIndex) continue;
73 
74 		bool priorityMatches = false;
75 		for (uint32_t priorityIdx = 0; !priorityMatches && priorityIdx < familyPriorityProperties[familyIdx].priorityCount; ++priorityIdx)
76 		{
77 			priorityMatches = (priority == familyPriorityProperties[familyIdx].priorities[priorityIdx]);
78 		}
79 		if (!priorityMatches) continue;
80 
81 		const VkQueueFlags queueFlags = familyProperties2[familyIdx].queueFamilyProperties.queueFlags;
82 		if ( ((queueFlags & includeFlags) == includeFlags) && ((queueFlags & excludeFlags) == 0) )
83 		{
84 			familyFound = familyIdx;
85 			break;
86 		}
87 	}
88 
89 	return familyFound;
90 }
91 
92 #define SAVEEXPR(expr, text, file, line) (text=#expr,file=__FILE__,line=__LINE__,expr)
93 
SpecialDevice(Context & ctx,VkQueueFlagBits transitionFrom,VkQueueFlagBits transitionTo,VkQueueGlobalPriorityKHR priorityFrom,VkQueueGlobalPriorityKHR priorityTo,bool enableProtected,bool enableSparseBinding)94 SpecialDevice::SpecialDevice	(Context&						ctx,
95 								 VkQueueFlagBits				transitionFrom,
96 								 VkQueueFlagBits				transitionTo,
97 								 VkQueueGlobalPriorityKHR		priorityFrom,
98 								 VkQueueGlobalPriorityKHR		priorityTo,
99 								 bool							enableProtected,
100 								 bool							enableSparseBinding)
101 		: queueFamilyIndexFrom	(m_queueFamilyIndexFrom)
102 		, queueFamilyIndexTo	(m_queueFamilyIndexTo)
103 		, handle				(m_deviceHandle)
104 		, queueFrom				(m_queueFrom)
105 		, queueTo				(m_queueTo)
106 		, createResult			(m_createResult)
107 		, createExpression		(m_createExpression)
108 		, createFileName		(m_createFileName)
109 		, createFileLine		(m_createFileLine)
110 		, m_context					(ctx)
111 		, m_transitionFrom			(transitionFrom)
112 		, m_transitionTo			(transitionTo)
113 		, m_queueFamilyIndexFrom	(INVALID_UINT32)
114 		, m_queueFamilyIndexTo		(INVALID_UINT32)
115 		, m_deviceHandle			(VK_NULL_HANDLE)
116 		, m_queueFrom				(VK_NULL_HANDLE)
117 		, m_queueTo					(VK_NULL_HANDLE)
118 		, m_allocator				()
119 		, m_createResult			(VK_ERROR_UNKNOWN)
120 		, m_createExpression		(nullptr)
121 		, m_createFileName			(nullptr)
122 		, m_createFileLine			(INVALID_UINT32)
123 {
124 	const DeviceInterface&					vkd					= ctx.getDeviceInterface();
125 	const InstanceInterface&				vki					= ctx.getInstanceInterface();
126 	const VkInstance						instance			= ctx.getInstance();
127 	const tcu::CommandLine&					cmdLine				= ctx.getTestContext().getCommandLine();
128 	const VkPhysicalDevice					phys				= chooseDevice(vki, instance, cmdLine);
129 	const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vki, phys);
130 
131 
132 	VkQueueFlags	flagFrom	= transitionFrom;
133 	VkQueueFlags	flagTo		= transitionTo;
134 	if (enableProtected)
135 	{
136 		flagFrom |= VK_QUEUE_PROTECTED_BIT;
137 		flagTo	|= VK_QUEUE_PROTECTED_BIT;
138 	}
139 	if (enableSparseBinding)
140 	{
141 		flagFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
142 		flagTo	|= VK_QUEUE_SPARSE_BINDING_BIT;
143 	}
144 
145 	m_queueFamilyIndexFrom	= findQueueFamilyIndex(vki, phys, priorityFrom, flagFrom, getColissionFlags(transitionFrom), INVALID_UINT32);
146 	m_queueFamilyIndexTo	= findQueueFamilyIndex(vki, phys, priorityTo, flagTo, getColissionFlags(transitionTo), m_queueFamilyIndexFrom);
147 
148 	DE_ASSERT(m_queueFamilyIndexFrom != INVALID_UINT32);
149 	DE_ASSERT(m_queueFamilyIndexTo != INVALID_UINT32);
150 
151 	const float									queuePriorities[2] { 1.0f, 0.0f };
152 	VkDeviceQueueCreateInfo						queueCreateInfos[2];
153 	VkDeviceQueueGlobalPriorityCreateInfoKHR	priorityCreateInfos[2];
154 	{
155 		priorityCreateInfos[0].sType	= priorityCreateInfos[1].sType		= VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR;
156 		priorityCreateInfos[0].pNext	= priorityCreateInfos[1].pNext		= nullptr;
157 
158 		queueCreateInfos[0].sType		= queueCreateInfos[1].sType			= VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
159 		queueCreateInfos[0].flags		= queueCreateInfos[1].flags			= enableProtected ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0;
160 		queueCreateInfos[0].queueCount	= queueCreateInfos[1].queueCount	= 1;
161 
162 		priorityCreateInfos[0].globalPriority	= priorityFrom;
163 		queueCreateInfos[0].pNext		= &priorityCreateInfos[0];
164 		queueCreateInfos[0].queueFamilyIndex = m_queueFamilyIndexFrom;
165 		queueCreateInfos[0].pQueuePriorities = &queuePriorities[0];
166 
167 		priorityCreateInfos[1].globalPriority	= priorityTo;
168 		queueCreateInfos[1].pNext		= &priorityCreateInfos[1];
169 		queueCreateInfos[1].queueFamilyIndex = m_queueFamilyIndexTo;
170 		queueCreateInfos[1].pQueuePriorities = &queuePriorities[1];
171 	}
172 
173 	VkPhysicalDeviceProtectedMemoryFeatures memFeatures
174 	{
175 		VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
176 		DE_NULL,
177 		VK_TRUE
178 	};
179 	VkPhysicalDeviceFeatures2 devFeatures = ctx.getDeviceFeatures2();
180 	if (enableProtected) devFeatures.pNext = &memFeatures;
181 
182 	const std::vector<const char*>& extensions = ctx.getDeviceCreationExtensions();
183 
184 	VkDeviceCreateInfo deviceCreateInfo			{};
185 	deviceCreateInfo.sType						= VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
186 	deviceCreateInfo.pNext						= &devFeatures;
187 	deviceCreateInfo.flags						= VkDeviceCreateFlags(0);
188 	deviceCreateInfo.queueCreateInfoCount		= 2;
189 	deviceCreateInfo.pQueueCreateInfos			= queueCreateInfos;
190 	deviceCreateInfo.pEnabledFeatures			= nullptr;
191 	deviceCreateInfo.enabledExtensionCount		= static_cast<deUint32>(extensions.size());
192 	deviceCreateInfo.ppEnabledExtensionNames	= de::dataOrNull(extensions);
193 	deviceCreateInfo.ppEnabledLayerNames		= nullptr;
194 	deviceCreateInfo.enabledLayerCount			= 0;
195 
196 	m_createResult = SAVEEXPR(createUncheckedDevice(cmdLine.isValidationEnabled(), vki, phys, &deviceCreateInfo, nullptr, &m_deviceHandle),
197 							  m_createExpression, m_createFileName, m_createFileLine);
198 	if (VK_SUCCESS == m_createResult && VK_NULL_HANDLE != m_deviceHandle)
199 	{
200 		m_allocator		= de::MovePtr<vk::Allocator>(new SimpleAllocator(vkd, m_deviceHandle, memoryProperties));
201 
202 		if (enableProtected)
203 		{
204 			VkDeviceQueueInfo2	queueInfo{};
205 			queueInfo.sType			= VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
206 			queueInfo.flags			= VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
207 			queueInfo.queueIndex	= 0;
208 
209 			queueInfo.queueFamilyIndex = m_queueFamilyIndexFrom;
210 			vkd.getDeviceQueue2(m_deviceHandle, &queueInfo, &m_queueFrom);
211 
212 			queueInfo.queueFamilyIndex = m_queueFamilyIndexTo;
213 			vkd.getDeviceQueue2(m_deviceHandle, &queueInfo, &m_queueTo);
214 		}
215 		else
216 		{
217 			vkd.getDeviceQueue(m_deviceHandle, m_queueFamilyIndexFrom, 0, &m_queueFrom);
218 			vkd.getDeviceQueue(m_deviceHandle, m_queueFamilyIndexTo, 0, &m_queueTo);
219 		}
220 	}
221 }
~SpecialDevice()222 SpecialDevice::~SpecialDevice ()
223 {
224 	if (VK_NULL_HANDLE != m_deviceHandle)
225 	{
226 		m_context.getDeviceInterface().destroyDevice(m_deviceHandle, nullptr);
227 		m_createResult = VK_ERROR_UNKNOWN;
228 		m_deviceHandle = VK_NULL_HANDLE;
229 	}
230 }
getColissionFlags(VkQueueFlags flags)231 VkQueueFlags SpecialDevice::getColissionFlags (VkQueueFlags flags)
232 {
233 	if (flags & VK_QUEUE_TRANSFER_BIT)
234 		return (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
235 
236 	if (flags & VK_QUEUE_COMPUTE_BIT)
237 		return VK_QUEUE_GRAPHICS_BIT;
238 
239 	if (flags & VK_QUEUE_GRAPHICS_BIT)
240 		return 0;
241 
242 	DE_ASSERT(false);
243 	return 0;
244 }
245 
BufferWithMemory(const vk::InstanceInterface & vki,const DeviceInterface & vkd,const vk::VkPhysicalDevice phys,const VkDevice device,Allocator & allocator,const VkBufferCreateInfo & bufferCreateInfo,const MemoryRequirement memoryRequirement,const VkQueue sparseQueue)246 BufferWithMemory::BufferWithMemory	(const vk::InstanceInterface&	vki,
247 									 const DeviceInterface&			vkd,
248 									 const vk::VkPhysicalDevice		phys,
249 									 const VkDevice					device,
250 									 Allocator&						allocator,
251 									 const VkBufferCreateInfo&		bufferCreateInfo,
252 									 const MemoryRequirement		memoryRequirement,
253 									 const VkQueue					sparseQueue)
254 	: m_amISparse		((bufferCreateInfo.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
255 	, m_buffer			(createBuffer(vkd, device, &bufferCreateInfo))
256 	, m_requirements	(getBufferMemoryRequirements(vkd, device, *m_buffer))
257 	, m_allocations		()
258 	, m_size			(bufferCreateInfo.size)
259 {
260 	if (m_amISparse)
261 	{
262 		DE_ASSERT(sparseQueue != VkQueue(0));
263 		const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vki, phys);
264 		const deUint32							memoryTypeIndex		= selectMatchingMemoryType(memoryProperties, m_requirements.memoryTypeBits, memoryRequirement);
265 		const VkDeviceSize						lastChunkSize		= m_requirements.size % m_requirements.alignment;
266 		const uint32_t							chunkCount			= static_cast<uint32_t>(m_requirements.size / m_requirements.alignment + (lastChunkSize ? 1 : 0));
267 		Move<VkFence>							fence				= createFence(vkd, device);
268 
269 		std::vector<VkSparseMemoryBind>			bindings(chunkCount);
270 
271 		for (uint32_t i = 0; i < chunkCount; ++i)
272 		{
273 			VkMemoryAllocateInfo		allocInfo{};
274 			allocInfo.sType				= VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
275 			allocInfo.pNext				= nullptr;
276 			allocInfo.allocationSize	= m_requirements.alignment;
277 			allocInfo.memoryTypeIndex	= memoryTypeIndex;
278 
279 			de::MovePtr<Allocation>		allocation	= allocator.allocate(allocInfo, m_requirements.alignment);
280 
281 			VkSparseMemoryBind&			binding = bindings[i];
282 			binding.resourceOffset		= m_requirements.alignment * i;
283 			binding.size				= m_requirements.alignment;
284 			binding.memory				= allocation->getMemory();
285 			binding.memoryOffset		= allocation->getOffset();
286 			binding.flags				= 0;
287 
288 			m_allocations.emplace_back(allocation.release());
289 		}
290 
291 		VkSparseBufferMemoryBindInfo bindInfo{};
292 		bindInfo.buffer		= *m_buffer;
293 		bindInfo.bindCount	= chunkCount;
294 		bindInfo.pBinds		= de::dataOrNull(bindings);
295 
296 		VkBindSparseInfo sparseInfo{};
297 		sparseInfo.sType				= VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;
298 		sparseInfo.pNext				= nullptr;
299 		sparseInfo.waitSemaphoreCount	= 0;
300 		sparseInfo.pWaitSemaphores		= nullptr;
301 		sparseInfo.bufferBindCount		= 1;
302 		sparseInfo.pBufferBinds			= &bindInfo;
303 		sparseInfo.imageOpaqueBindCount	= 0;
304 		sparseInfo.pImageOpaqueBinds	= nullptr;
305 		sparseInfo.imageBindCount		= 0;
306 		sparseInfo.pImageBinds			= nullptr;
307 		sparseInfo.signalSemaphoreCount	= 0;
308 		sparseInfo.pSignalSemaphores	= nullptr;
309 
310 		VK_CHECK(vkd.queueBindSparse(sparseQueue, 1, &sparseInfo, *fence));
311 		VK_CHECK(vkd.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
312 	}
313 	else
314 	{
315 		de::MovePtr<Allocation> allocation = allocator.allocate(m_requirements, memoryRequirement);
316 		VK_CHECK(vkd.bindBufferMemory(device, *m_buffer, allocation->getMemory(), allocation->getOffset()));
317 		m_allocations.emplace_back(allocation.release());
318 	}
319 }
320 
assertIAmSparse() const321 void BufferWithMemory::assertIAmSparse () const
322 {
323 	if (m_amISparse) TCU_THROW(NotSupportedError, "Host access pointer not implemented for sparse buffers");
324 }
325 
getHostPtr(void) const326 void* BufferWithMemory::getHostPtr (void) const
327 {
328 	assertIAmSparse();
329 	return m_allocations[0]->getHostPtr();
330 }
331 
invalidateAlloc(const DeviceInterface & vk,const VkDevice device) const332 void BufferWithMemory::invalidateAlloc (const DeviceInterface& vk, const VkDevice device) const
333 {
334 	assertIAmSparse();
335 	::vk::invalidateAlloc(vk, device, *m_allocations[0]);
336 }
337 
flushAlloc(const DeviceInterface & vk,const VkDevice device) const338 void BufferWithMemory::flushAlloc (const DeviceInterface& vk, const VkDevice device) const
339 {
340 	assertIAmSparse();
341 	::vk::flushAlloc(vk, device, *m_allocations[0]);
342 }
343 
ImageWithMemory(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice phys,const VkDevice device,Allocator & allocator,const VkImageCreateInfo & imageCreateInfo,const VkQueue sparseQueue,const MemoryRequirement memoryRequirement)344 ImageWithMemory::ImageWithMemory	(const InstanceInterface&		vki,
345 									 const DeviceInterface&			vkd,
346 									 const VkPhysicalDevice			phys,
347 									 const VkDevice					device,
348 									 Allocator&						allocator,
349 									 const VkImageCreateInfo&		imageCreateInfo,
350 									 const VkQueue					sparseQueue,
351 									 const MemoryRequirement		memoryRequirement)
352 	: m_image(((imageCreateInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != 0)
353 			  ? (new image::SparseImage(vkd, device, phys, vki, imageCreateInfo, sparseQueue, allocator, mapVkFormat(imageCreateInfo.format)))
354 			  : (new image::Image(vkd, device, allocator, imageCreateInfo, memoryRequirement)))
355 {
356 }
357 
358 } // synchronization
359 } // vkt
360