• 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 "vkBuilderUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 
40 #include "deUniquePtr.hpp"
41 #include "deStringUtil.hpp"
42 
43 #include <string>
44 #include <vector>
45 
46 using namespace vk;
47 
48 namespace vkt
49 {
50 namespace sparse
51 {
52 namespace
53 {
54 
55 class BufferSparseBindingCase : public TestCase
56 {
57 public:
58 					BufferSparseBindingCase	(tcu::TestContext&	testCtx,
59 											 const std::string&	name,
60 											 const std::string&	description,
61 											 const deUint32		bufferSize);
62 
63 	TestInstance*	createInstance			(Context&			context) const;
64 
65 private:
66 	const deUint32	m_bufferSize;
67 };
68 
BufferSparseBindingCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const deUint32 bufferSize)69 BufferSparseBindingCase::BufferSparseBindingCase (tcu::TestContext&		testCtx,
70 												  const std::string&	name,
71 												  const std::string&	description,
72 												  const deUint32		bufferSize)
73 	: TestCase			(testCtx, name, description)
74 	, m_bufferSize		(bufferSize)
75 {
76 }
77 
78 class BufferSparseBindingInstance : public SparseResourcesBaseInstance
79 {
80 public:
81 					BufferSparseBindingInstance (Context&		context,
82 												 const deUint32	bufferSize);
83 
84 	tcu::TestStatus	iterate						(void);
85 
86 private:
87 	const deUint32	m_bufferSize;
88 };
89 
BufferSparseBindingInstance(Context & context,const deUint32 bufferSize)90 BufferSparseBindingInstance::BufferSparseBindingInstance (Context&			context,
91 														  const deUint32	bufferSize)
92 
93 	: SparseResourcesBaseInstance	(context)
94 	, m_bufferSize					(bufferSize)
95 {
96 }
97 
iterate(void)98 tcu::TestStatus BufferSparseBindingInstance::iterate (void)
99 {
100 	const InstanceInterface&	instance		= m_context.getInstanceInterface();
101 	const VkPhysicalDevice		physicalDevice	= m_context.getPhysicalDevice();
102 
103 	if (!getPhysicalDeviceFeatures(instance, physicalDevice).sparseBinding)
104 		TCU_THROW(NotSupportedError, "Sparse binding not supported");
105 
106 	{
107 		// Create logical device supporting both sparse and compute operations
108 		QueueRequirementsVec queueRequirements;
109 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
110 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
111 
112 		createDeviceSupportingQueues(queueRequirements);
113 	}
114 
115 	const DeviceInterface&	deviceInterface	= getDeviceInterface();
116 	const Queue&			sparseQueue		= getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
117 	const Queue&			computeQueue	= getQueue(VK_QUEUE_COMPUTE_BIT, 0);
118 
119 	VkBufferCreateInfo bufferCreateInfo;
120 
121 	bufferCreateInfo.sType					= VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;	// VkStructureType		sType;
122 	bufferCreateInfo.pNext					= DE_NULL;								// const void*			pNext;
123 	bufferCreateInfo.flags					= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;	// VkBufferCreateFlags	flags;
124 	bufferCreateInfo.size					= m_bufferSize;							// VkDeviceSize			size;
125 	bufferCreateInfo.usage					= VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
126 											  VK_BUFFER_USAGE_TRANSFER_DST_BIT;		// VkBufferUsageFlags	usage;
127 	bufferCreateInfo.sharingMode			= VK_SHARING_MODE_EXCLUSIVE;			// VkSharingMode		sharingMode;
128 	bufferCreateInfo.queueFamilyIndexCount	= 0u;									// deUint32				queueFamilyIndexCount;
129 	bufferCreateInfo.pQueueFamilyIndices	= DE_NULL;								// const deUint32*		pQueueFamilyIndices;
130 
131 	const deUint32 queueFamilyIndices[] = { sparseQueue.queueFamilyIndex, computeQueue.queueFamilyIndex };
132 
133 	if (sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex)
134 	{
135 		bufferCreateInfo.sharingMode			= VK_SHARING_MODE_CONCURRENT;	// VkSharingMode		sharingMode;
136 		bufferCreateInfo.queueFamilyIndexCount	= 2u;							// deUint32				queueFamilyIndexCount;
137 		bufferCreateInfo.pQueueFamilyIndices	= queueFamilyIndices;			// const deUint32*		pQueueFamilyIndices;
138 	}
139 
140 	// Create sparse buffer
141 	const Unique<VkBuffer> sparseBuffer(createBuffer(deviceInterface, getDevice(), &bufferCreateInfo));
142 
143 	// Create sparse buffer memory bind semaphore
144 	const Unique<VkSemaphore> bufferMemoryBindSemaphore(makeSemaphore(deviceInterface, getDevice()));
145 
146 	const VkMemoryRequirements bufferMemRequirement = getBufferMemoryRequirements(deviceInterface, getDevice(), *sparseBuffer);
147 
148 	if (bufferMemRequirement.size > getPhysicalDeviceProperties(instance, physicalDevice).limits.sparseAddressSpaceSize)
149 		TCU_THROW(NotSupportedError, "Required memory size for sparse resources exceeds device limits");
150 
151 	DE_ASSERT((bufferMemRequirement.size % bufferMemRequirement.alignment) == 0);
152 
153 	std::vector<DeviceMemorySp> deviceMemUniquePtrVec;
154 
155 	{
156 		std::vector<VkSparseMemoryBind>	sparseMemoryBinds;
157 		const deUint32					numSparseBinds = static_cast<deUint32>(bufferMemRequirement.size / bufferMemRequirement.alignment);
158 		const deUint32					memoryType = findMatchingMemoryType(instance, physicalDevice, bufferMemRequirement, MemoryRequirement::Any);
159 
160 		if (memoryType == NO_MATCH_FOUND)
161 			return tcu::TestStatus::fail("No matching memory type found");
162 
163 		for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseBinds; ++sparseBindNdx)
164 		{
165 			const VkSparseMemoryBind sparseMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), bufferMemRequirement.alignment, memoryType, bufferMemRequirement.alignment * sparseBindNdx);
166 
167 			deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(sparseMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
168 
169 			sparseMemoryBinds.push_back(sparseMemoryBind);
170 		}
171 
172 		const VkSparseBufferMemoryBindInfo sparseBufferBindInfo = makeSparseBufferMemoryBindInfo(*sparseBuffer, numSparseBinds, &sparseMemoryBinds[0]);
173 
174 		const VkBindSparseInfo bindSparseInfo =
175 		{
176 			VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,			//VkStructureType							sType;
177 			DE_NULL,									//const void*								pNext;
178 			0u,											//deUint32									waitSemaphoreCount;
179 			DE_NULL,									//const VkSemaphore*						pWaitSemaphores;
180 			1u,											//deUint32									bufferBindCount;
181 			&sparseBufferBindInfo,						//const VkSparseBufferMemoryBindInfo*		pBufferBinds;
182 			0u,											//deUint32									imageOpaqueBindCount;
183 			DE_NULL,									//const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
184 			0u,											//deUint32									imageBindCount;
185 			DE_NULL,									//const VkSparseImageMemoryBindInfo*		pImageBinds;
186 			1u,											//deUint32									signalSemaphoreCount;
187 			&bufferMemoryBindSemaphore.get()			//const VkSemaphore*						pSignalSemaphores;
188 		};
189 
190 		// Submit sparse bind commands for execution
191 		VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
192 	}
193 
194 	// Create command buffer for transfer oparations
195 	const Unique<VkCommandPool>		commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
196 	const Unique<VkCommandBuffer>	commandBuffer(makeCommandBuffer(deviceInterface, getDevice(), *commandPool));
197 
198 	// Start recording transfer commands
199 	beginCommandBuffer(deviceInterface, *commandBuffer);
200 
201 	const VkBufferCreateInfo		inputBufferCreateInfo = makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
202 	const Unique<VkBuffer>			inputBuffer				(createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo));
203 	const de::UniquePtr<Allocation>	inputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible));
204 
205 	std::vector<deUint8> referenceData;
206 	referenceData.resize(m_bufferSize);
207 
208 	for (deUint32 valueNdx = 0; valueNdx < m_bufferSize; ++valueNdx)
209 	{
210 		referenceData[valueNdx] = static_cast<deUint8>((valueNdx % bufferMemRequirement.alignment) + 1u);
211 	}
212 
213 	deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], m_bufferSize);
214 
215 	flushMappedMemoryRange(deviceInterface, getDevice(), inputBufferAlloc->getMemory(), inputBufferAlloc->getOffset(), m_bufferSize);
216 
217 	{
218 		const VkBufferMemoryBarrier inputBufferBarrier
219 			= makeBufferMemoryBarrier(	VK_ACCESS_HOST_WRITE_BIT,
220 										VK_ACCESS_TRANSFER_READ_BIT,
221 										*inputBuffer,
222 										0u,
223 										m_bufferSize);
224 
225 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL);
226 	}
227 
228 	{
229 		const VkBufferCopy bufferCopy = makeBufferCopy(0u, 0u, m_bufferSize);
230 
231 		deviceInterface.cmdCopyBuffer(*commandBuffer, *inputBuffer, *sparseBuffer, 1u, &bufferCopy);
232 	}
233 
234 	{
235 		const VkBufferMemoryBarrier sparseBufferBarrier
236 			= makeBufferMemoryBarrier(	VK_ACCESS_TRANSFER_WRITE_BIT,
237 										VK_ACCESS_TRANSFER_READ_BIT,
238 										*sparseBuffer,
239 										0u,
240 										m_bufferSize);
241 
242 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &sparseBufferBarrier, 0u, DE_NULL);
243 	}
244 
245 	const VkBufferCreateInfo		outputBufferCreateInfo	= makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
246 	const Unique<VkBuffer>			outputBuffer			(createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
247 	const de::UniquePtr<Allocation>	outputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
248 
249 	{
250 		const VkBufferCopy bufferCopy = makeBufferCopy(0u, 0u, m_bufferSize);
251 
252 		deviceInterface.cmdCopyBuffer(*commandBuffer, *sparseBuffer, *outputBuffer, 1u, &bufferCopy);
253 	}
254 
255 	{
256 		const VkBufferMemoryBarrier outputBufferBarrier
257 			= makeBufferMemoryBarrier(	VK_ACCESS_TRANSFER_WRITE_BIT,
258 										VK_ACCESS_HOST_READ_BIT,
259 										*outputBuffer,
260 										0u,
261 										m_bufferSize);
262 
263 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL);
264 	}
265 
266 	// End recording transfer commands
267 	endCommandBuffer(deviceInterface, *commandBuffer);
268 
269 	const VkPipelineStageFlags waitStageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
270 
271 	// Submit transfer commands for execution and wait for completion
272 	submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &bufferMemoryBindSemaphore.get(), waitStageBits);
273 
274 	// Retrieve data from output buffer to host memory
275 	invalidateMappedMemoryRange(deviceInterface, getDevice(), outputBufferAlloc->getMemory(), outputBufferAlloc->getOffset(), m_bufferSize);
276 
277 	const deUint8* outputData = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr());
278 
279 	// Wait for sparse queue to become idle
280 	deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
281 
282 	// Compare output data with reference data
283 	if (deMemCmp(&referenceData[0], outputData, m_bufferSize) != 0)
284 		return tcu::TestStatus::fail("Failed");
285 	else
286 		return tcu::TestStatus::pass("Passed");
287 }
288 
createInstance(Context & context) const289 TestInstance* BufferSparseBindingCase::createInstance (Context& context) const
290 {
291 	return new BufferSparseBindingInstance(context, m_bufferSize);
292 }
293 
294 } // anonymous ns
295 
addBufferSparseBindingTests(tcu::TestCaseGroup * group)296 void addBufferSparseBindingTests (tcu::TestCaseGroup* group)
297 {
298 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_10", "", 1 << 10));
299 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_12", "", 1 << 12));
300 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_16", "", 1 << 16));
301 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_17", "", 1 << 17));
302 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_20", "", 1 << 20));
303 	group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_24", "", 1 << 24));
304 }
305 
306 } // sparse
307 } // vkt
308