• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 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  vktSparseResourcesBufferSparseBinding.cpp
21  * \brief Buffer Sparse Binding tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSparseResourcesBufferSparseBinding.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktSparseResourcesBase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkRef.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 
42 #include "deUniquePtr.hpp"
43 #include "deStringUtil.hpp"
44 
45 #include <string>
46 #include <vector>
47 
48 using namespace vk;
49 
50 namespace vkt
51 {
52 namespace sparse
53 {
54 namespace
55 {
56 
57 class BufferSparseBindingCase : public TestCase
58 {
59 public:
60 					BufferSparseBindingCase	(tcu::TestContext&	testCtx,
61 											 const std::string&	name,
62 											 const std::string&	description,
63 											 const deUint32		bufferSize,
64 											 const bool			useDeviceGroups);
65 
66 	TestInstance*	createInstance			(Context&			context) const;
67 	virtual void	checkSupport			(Context&			context) const;
68 
69 private:
70 	const deUint32	m_bufferSize;
71 	const bool		m_useDeviceGroups;
72 };
73 
BufferSparseBindingCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const deUint32 bufferSize,const bool useDeviceGroups)74 BufferSparseBindingCase::BufferSparseBindingCase (tcu::TestContext&		testCtx,
75 												  const std::string&	name,
76 												  const std::string&	description,
77 												  const deUint32		bufferSize,
78 												  const bool			useDeviceGroups)
79 	: TestCase			(testCtx, name, description)
80 	, m_bufferSize		(bufferSize)
81 	, m_useDeviceGroups	(useDeviceGroups)
82 {
83 }
84 
checkSupport(Context & context) const85 void BufferSparseBindingCase::checkSupport (Context& context) const
86 {
87 	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING);
88 }
89 
90 class BufferSparseBindingInstance : public SparseResourcesBaseInstance
91 {
92 public:
93 					BufferSparseBindingInstance (Context&		context,
94 												 const deUint32	bufferSize,
95 												 const bool		useDeviceGroups);
96 
97 	tcu::TestStatus	iterate						(void);
98 
99 private:
100 	const deUint32	m_bufferSize;
101 	const deUint32	m_useDeviceGroups;
102 };
103 
BufferSparseBindingInstance(Context & context,const deUint32 bufferSize,const bool useDeviceGroups)104 BufferSparseBindingInstance::BufferSparseBindingInstance (Context&			context,
105 														  const deUint32	bufferSize,
106 														  const bool		useDeviceGroups)
107 
108 	: SparseResourcesBaseInstance	(context, useDeviceGroups)
109 	, m_bufferSize					(bufferSize)
110 	, m_useDeviceGroups				(useDeviceGroups)
111 {
112 }
113 
iterate(void)114 tcu::TestStatus BufferSparseBindingInstance::iterate (void)
115 {
116 	const InstanceInterface&	instance		= m_context.getInstanceInterface();
117 	{
118 		// Create logical device supporting both sparse and compute operations
119 		QueueRequirementsVec queueRequirements;
120 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
121 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
122 
123 		createDeviceSupportingQueues(queueRequirements);
124 	}
125 	const vk::VkPhysicalDevice&	physicalDevice	= getPhysicalDevice();
126 
127 	const DeviceInterface&	deviceInterface	= getDeviceInterface();
128 	const Queue&			sparseQueue		= getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
129 	const Queue&			computeQueue	= getQueue(VK_QUEUE_COMPUTE_BIT, 0);
130 
131 	// Go through all physical devices
132 	for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++)
133 	{
134 		const deUint32	firstDeviceID	= physDevID;
135 		const deUint32	secondDeviceID	= (firstDeviceID + 1) % m_numPhysicalDevices;
136 
137 		VkBufferCreateInfo bufferCreateInfo;
138 
139 		bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;	// VkStructureType		sType;
140 		bufferCreateInfo.pNext = DE_NULL;								// const void*			pNext;
141 		bufferCreateInfo.flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT;	// VkBufferCreateFlags	flags;
142 		bufferCreateInfo.size = m_bufferSize;							// VkDeviceSize			size;
143 		bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
144 			VK_BUFFER_USAGE_TRANSFER_DST_BIT;							// VkBufferUsageFlags	usage;
145 		bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;		// VkSharingMode		sharingMode;
146 		bufferCreateInfo.queueFamilyIndexCount = 0u;					// deUint32				queueFamilyIndexCount;
147 		bufferCreateInfo.pQueueFamilyIndices = DE_NULL;					// const deUint32*		pQueueFamilyIndices;
148 
149 		const deUint32 queueFamilyIndices[] = { sparseQueue.queueFamilyIndex, computeQueue.queueFamilyIndex };
150 
151 		if (sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex)
152 		{
153 			bufferCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;	// VkSharingMode		sharingMode;
154 			bufferCreateInfo.queueFamilyIndexCount = 2u;				// deUint32				queueFamilyIndexCount;
155 			bufferCreateInfo.pQueueFamilyIndices = queueFamilyIndices;	// const deUint32*		pQueueFamilyIndices;
156 		}
157 
158 		// Create sparse buffer
159 		const Unique<VkBuffer> sparseBuffer(createBuffer(deviceInterface, getDevice(), &bufferCreateInfo));
160 
161 		// Create sparse buffer memory bind semaphore
162 		const Unique<VkSemaphore> bufferMemoryBindSemaphore(createSemaphore(deviceInterface, getDevice()));
163 
164 		const VkMemoryRequirements bufferMemRequirement = getBufferMemoryRequirements(deviceInterface, getDevice(), *sparseBuffer);
165 
166 		if (bufferMemRequirement.size > getPhysicalDeviceProperties(instance, physicalDevice).limits.sparseAddressSpaceSize)
167 			TCU_THROW(NotSupportedError, "Required memory size for sparse resources exceeds device limits");
168 
169 		DE_ASSERT((bufferMemRequirement.size % bufferMemRequirement.alignment) == 0);
170 
171 		Move<VkDeviceMemory> sparseMemoryAllocation;
172 
173 		{
174 			std::vector<VkSparseMemoryBind>	sparseMemoryBinds;
175 			const deUint32					numSparseBinds = static_cast<deUint32>(bufferMemRequirement.size / bufferMemRequirement.alignment);
176 			const deUint32					memoryType	   = findMatchingMemoryType(instance, getPhysicalDevice(secondDeviceID), bufferMemRequirement, MemoryRequirement::Any);
177 
178 			if (memoryType == NO_MATCH_FOUND)
179 				return tcu::TestStatus::fail("No matching memory type found");
180 
181 			if (firstDeviceID != secondDeviceID)
182 			{
183 				VkPeerMemoryFeatureFlags	peerMemoryFeatureFlags = (VkPeerMemoryFeatureFlags)0;
184 				const deUint32				heapIndex = getHeapIndexForMemoryType(instance, getPhysicalDevice(secondDeviceID), memoryType);
185 				deviceInterface.getDeviceGroupPeerMemoryFeatures(getDevice(), heapIndex, firstDeviceID, secondDeviceID, &peerMemoryFeatureFlags);
186 
187 				if (((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT) == 0) ||
188 					((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_DST_BIT) == 0))
189 				{
190 					TCU_THROW(NotSupportedError, "Peer memory does not support COPY_SRC and COPY_DST");
191 				}
192 			}
193 
194 			{
195 				const VkMemoryAllocateInfo allocateInfo =
196 				{
197 					VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,			// VkStructureType    sType;
198 					DE_NULL,										// const void*        pNext;
199 					bufferMemRequirement.size,						// VkDeviceSize       allocationSize;
200 					memoryType,										// uint32_t           memoryTypeIndex;
201 				};
202 
203 				sparseMemoryAllocation = allocateMemory(deviceInterface, getDevice(), &allocateInfo);
204 			}
205 
206 			for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseBinds; ++sparseBindNdx)
207 			{
208 				const VkSparseMemoryBind sparseMemoryBind =
209 				{
210 					bufferMemRequirement.alignment * sparseBindNdx,			// VkDeviceSize               resourceOffset;
211 					bufferMemRequirement.alignment,							// VkDeviceSize               size;
212 					*sparseMemoryAllocation,								// VkDeviceMemory             memory;
213 					bufferMemRequirement.alignment * sparseBindNdx,			// VkDeviceSize               memoryOffset;
214 					(VkSparseMemoryBindFlags)0,								// VkSparseMemoryBindFlags    flags;
215 				};
216 				sparseMemoryBinds.push_back(sparseMemoryBind);
217 			}
218 
219 			const VkSparseBufferMemoryBindInfo sparseBufferBindInfo = makeSparseBufferMemoryBindInfo(*sparseBuffer, numSparseBinds, &sparseMemoryBinds[0]);
220 
221 			const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo =
222 			{
223 				VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR,	//VkStructureType							sType;
224 				DE_NULL,												//const void*								pNext;
225 				firstDeviceID,											//deUint32									resourceDeviceIndex;
226 				secondDeviceID,											//deUint32									memoryDeviceIndex;
227 			};
228 
229 			const VkBindSparseInfo bindSparseInfo =
230 			{
231 				VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,						//VkStructureType							sType;
232 				m_useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL,	//const void*								pNext;
233 				0u,														//deUint32									waitSemaphoreCount;
234 				DE_NULL,												//const VkSemaphore*						pWaitSemaphores;
235 				1u,														//deUint32									bufferBindCount;
236 				&sparseBufferBindInfo,									//const VkSparseBufferMemoryBindInfo*		pBufferBinds;
237 				0u,														//deUint32									imageOpaqueBindCount;
238 				DE_NULL,												//const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
239 				0u,														//deUint32									imageBindCount;
240 				DE_NULL,												//const VkSparseImageMemoryBindInfo*		pImageBinds;
241 				1u,														//deUint32									signalSemaphoreCount;
242 				&bufferMemoryBindSemaphore.get()						//const VkSemaphore*						pSignalSemaphores;
243 			};
244 
245 			// Submit sparse bind commands for execution
246 			VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
247 		}
248 
249 		// Create command buffer for transfer operations
250 		const Unique<VkCommandPool>		commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
251 		const Unique<VkCommandBuffer>	commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
252 
253 		// Start recording transfer commands
254 		beginCommandBuffer(deviceInterface, *commandBuffer);
255 
256 		const VkBufferCreateInfo		inputBufferCreateInfo = makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
257 		const Unique<VkBuffer>			inputBuffer(createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo));
258 		const de::UniquePtr<Allocation>	inputBufferAlloc(bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible));
259 
260 		std::vector<deUint8> referenceData;
261 		referenceData.resize(m_bufferSize);
262 
263 		for (deUint32 valueNdx = 0; valueNdx < m_bufferSize; ++valueNdx)
264 		{
265 			referenceData[valueNdx] = static_cast<deUint8>((valueNdx % bufferMemRequirement.alignment) + 1u);
266 		}
267 
268 		deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], m_bufferSize);
269 
270 		flushAlloc(deviceInterface, getDevice(), *inputBufferAlloc);
271 
272 		{
273 			const VkBufferMemoryBarrier inputBufferBarrier
274 				= makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT,
275 					VK_ACCESS_TRANSFER_READ_BIT,
276 					*inputBuffer,
277 					0u,
278 					m_bufferSize);
279 
280 			deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL);
281 		}
282 
283 		{
284 			const VkBufferCopy bufferCopy = makeBufferCopy(0u, 0u, m_bufferSize);
285 
286 			deviceInterface.cmdCopyBuffer(*commandBuffer, *inputBuffer, *sparseBuffer, 1u, &bufferCopy);
287 		}
288 
289 		{
290 			const VkBufferMemoryBarrier sparseBufferBarrier
291 				= makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT,
292 					VK_ACCESS_TRANSFER_READ_BIT,
293 					*sparseBuffer,
294 					0u,
295 					m_bufferSize);
296 
297 			deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &sparseBufferBarrier, 0u, DE_NULL);
298 		}
299 
300 		const VkBufferCreateInfo		outputBufferCreateInfo = makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
301 		const Unique<VkBuffer>			outputBuffer(createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
302 		const de::UniquePtr<Allocation>	outputBufferAlloc(bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
303 
304 		{
305 			const VkBufferCopy bufferCopy = makeBufferCopy(0u, 0u, m_bufferSize);
306 
307 			deviceInterface.cmdCopyBuffer(*commandBuffer, *sparseBuffer, *outputBuffer, 1u, &bufferCopy);
308 		}
309 
310 		{
311 			const VkBufferMemoryBarrier outputBufferBarrier
312 				= makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT,
313 					VK_ACCESS_HOST_READ_BIT,
314 					*outputBuffer,
315 					0u,
316 					m_bufferSize);
317 
318 			deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL);
319 		}
320 
321 		// End recording transfer commands
322 		endCommandBuffer(deviceInterface, *commandBuffer);
323 
324 		const VkPipelineStageFlags waitStageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
325 
326 		// Submit transfer commands for execution and wait for completion
327 		// In case of device groups, submit on the physical device with the resource
328 		submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &bufferMemoryBindSemaphore.get(),
329 			waitStageBits, 0, DE_NULL, m_useDeviceGroups, firstDeviceID);
330 
331 		// Retrieve data from output buffer to host memory
332 		invalidateAlloc(deviceInterface, getDevice(), *outputBufferAlloc);
333 
334 		const deUint8* outputData = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr());
335 
336 		// Wait for sparse queue to become idle
337 		deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
338 
339 		// Compare output data with reference data
340 		if (deMemCmp(&referenceData[0], outputData, m_bufferSize) != 0)
341 			return tcu::TestStatus::fail("Failed");
342 	}
343 	return tcu::TestStatus::pass("Passed");
344 }
345 
createInstance(Context & context) const346 TestInstance* BufferSparseBindingCase::createInstance (Context& context) const
347 {
348 	return new BufferSparseBindingInstance(context, m_bufferSize, m_useDeviceGroups);
349 }
350 
351 } // anonymous ns
352 
addBufferSparseBindingTests(tcu::TestCaseGroup * group,const bool useDeviceGroups)353 void addBufferSparseBindingTests (tcu::TestCaseGroup* group, const bool useDeviceGroups)
354 {
355 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_10", "", 1 << 10, useDeviceGroups));
356 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_12", "", 1 << 12, useDeviceGroups));
357 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_16", "", 1 << 16, useDeviceGroups));
358 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_17", "", 1 << 17, useDeviceGroups));
359 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_20", "", 1 << 20, useDeviceGroups));
360 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_24", "", 1 << 24, useDeviceGroups));
361 }
362 
363 } // sparse
364 } // vkt
365