1 /*-------------------------------------------------------------------------
2  *  Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Vulkan Buffer View Creation Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktApiBufferViewCreateTests.hpp"
26 #include "deStringUtil.hpp"
27 #include "deSharedPtr.hpp"
28 #include "gluVarType.hpp"
29 #include "tcuTestLog.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vktTestCase.hpp"
33 #include "vkQueryUtil.hpp"
34 
35 namespace vkt
36 {
37 
38 using namespace vk;
39 
40 namespace api
41 {
42 
43 namespace
44 {
45 
46 enum AllocationKind
47 {
48 	ALLOCATION_KIND_SUBALLOCATED = 0,
49 	ALLOCATION_KIND_DEDICATED,
50 
51 	ALLOCATION_KIND_LAST,
52 };
53 
54 class IBufferAllocator;
55 
56 struct BufferViewCaseParameters
57 {
58 	VkFormat							format;
59 	VkDeviceSize						offset;
60 	VkDeviceSize						range;
61 	VkBufferUsageFlags					usage;
62 	VkFormatFeatureFlags				features;
63 	AllocationKind						bufferAllocationKind;
64 };
65 
66 class BufferViewTestInstance : public TestInstance
67 {
68 public:
BufferViewTestInstance(Context& ctx, BufferViewCaseParameters createInfo)69 										BufferViewTestInstance			(Context&					ctx,
70 																		 BufferViewCaseParameters	createInfo)
71 										: TestInstance					(ctx)
72 										, m_testCase					(createInfo)
73 	{}
74 	virtual tcu::TestStatus				iterate							(void);
75 
76 protected:
77 	BufferViewCaseParameters			m_testCase;
78 };
79 
80 class IBufferAllocator
81 {
82 public:
83 	virtual tcu::TestStatus				createTestBuffer				(VkDeviceSize				size,
84 																		 VkBufferUsageFlags			usage,
85 																		 Context&					context,
86 																		 Move<VkBuffer>&			testBuffer,
87 																		 Move<VkDeviceMemory>&		memory) const = 0;
88 };
89 
90 class BufferSuballocation : public IBufferAllocator
91 {
92 public:
93 	virtual tcu::TestStatus				createTestBuffer				(VkDeviceSize				size,
94 																		 VkBufferUsageFlags			usage,
95 																		 Context&					context,
96 																		 Move<VkBuffer>&			testBuffer,
97 																		 Move<VkDeviceMemory>&		memory) const;
98 };
99 
100 class BufferDedicatedAllocation	: public IBufferAllocator
101 {
102 public:
103 	virtual tcu::TestStatus				createTestBuffer				(VkDeviceSize				size,
104 																		 VkBufferUsageFlags			usage,
105 																		 Context&					context,
106 																		 Move<VkBuffer>&			testBuffer,
107 																		 Move<VkDeviceMemory>&		memory) const;
108 };
109 
110 class BufferViewTestCase : public TestCase
111 {
112 public:
BufferViewTestCase(tcu::TestContext& testCtx, const std::string& name, BufferViewCaseParameters createInfo)113 										BufferViewTestCase				(tcu::TestContext&			testCtx,
114 																		 const std::string&			name,
115 																		 BufferViewCaseParameters	createInfo)
116 										: TestCase						(testCtx, name)
117 										, m_testCase					(createInfo)
118 	{}
~BufferViewTestCase(void)119 	virtual								~BufferViewTestCase				(void)
120 	{}
createInstance(Context& ctx) const121 	virtual TestInstance*				createInstance					(Context&					ctx) const
122 	{
123 		return new BufferViewTestInstance(ctx, m_testCase);
124 	}
checkSupport(Context& ctx) const125 	virtual void						checkSupport					(Context&					ctx) const
126 	{
127 		VkFormatProperties					properties;
128 
129 		ctx.getInstanceInterface().getPhysicalDeviceFormatProperties(ctx.getPhysicalDevice(), m_testCase.format, &properties);
130 		if (!(properties.bufferFeatures & m_testCase.features))
131 			TCU_THROW(NotSupportedError, "Format not supported");
132 		if (m_testCase.bufferAllocationKind == ALLOCATION_KIND_DEDICATED)
133 		{
134 			if (!ctx.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
135 				TCU_THROW(NotSupportedError, "Dedicated allocation not supported");
136 		}
137 	}
138 private:
139 	BufferViewCaseParameters			m_testCase;
140 };
141 
createTestBuffer(VkDeviceSize size, VkBufferUsageFlags usage, Context& context, Move<VkBuffer>& testBuffer, Move<VkDeviceMemory>& memory) const142 tcu::TestStatus BufferSuballocation::createTestBuffer					(VkDeviceSize				size,
143 																		 VkBufferUsageFlags			usage,
144 																		 Context&					context,
145 																		 Move<VkBuffer>&			testBuffer,
146 																		 Move<VkDeviceMemory>&		memory) const
147 {
148 	const VkDevice						vkDevice						= context.getDevice();
149 	const DeviceInterface&				vk								= context.getDeviceInterface();
150 	const deUint32						queueFamilyIndex				= context.getUniversalQueueFamilyIndex();
151 	VkMemoryRequirements				memReqs;
152 	const VkBufferCreateInfo			bufferParams					=
153 	{
154 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,							//	VkStructureType			sType;
155 		DE_NULL,														//	const void*				pNext;
156 		0u,																//	VkBufferCreateFlags		flags;
157 		size,															//	VkDeviceSize			size;
158 		usage,															//	VkBufferUsageFlags		usage;
159 		VK_SHARING_MODE_EXCLUSIVE,										//	VkSharingMode			sharingMode;
160 		1u,																//	deUint32				queueFamilyCount;
161 		&queueFamilyIndex,												//	const deUint32*			pQueueFamilyIndices;
162 	};
163 
164 	try
165 	{
166 		testBuffer = vk::createBuffer(vk, vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
167 	}
168 	catch (const vk::Error& error)
169 	{
170 		return tcu::TestStatus::fail("Buffer creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
171 	}
172 
173 	vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
174 
175 #ifdef CTS_USES_VULKANSC
176 	if (context.getTestContext().getCommandLine().isSubProcess())
177 #endif // CTS_USES_VULKANSC
178 	{
179 		if (size > memReqs.size)
180 		{
181 			std::ostringstream errorMsg;
182 			errorMsg << "Required memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
183 			return tcu::TestStatus::fail(errorMsg.str());
184 		}
185 	}
186 
187 	const VkMemoryAllocateInfo			memAlloc						=
188 	{
189 		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,							//	VkStructureType			sType
190 		NULL,															//	const void*				pNext
191 		memReqs.size,													//	VkDeviceSize			allocationSize
192 		(deUint32)deCtz32(memReqs.memoryTypeBits)						//	deUint32				memoryTypeIndex
193 	};
194 
195 	try
196 	{
197 		memory = allocateMemory(vk, vkDevice, &memAlloc, (const VkAllocationCallbacks*)DE_NULL);
198 	}
199 	catch (const vk::Error& error)
200 	{
201 		return tcu::TestStatus::fail("Alloc memory failed! (Error code: " + de::toString(error.getMessage()) + ")");
202 	}
203 
204 	if (vk.bindBufferMemory(vkDevice, *testBuffer, *memory, 0) != VK_SUCCESS)
205 		return tcu::TestStatus::fail("Bind buffer memory failed!");
206 
207 	return tcu::TestStatus::incomplete();
208 }
209 
createTestBuffer(VkDeviceSize size, VkBufferUsageFlags usage, Context& context, Move<VkBuffer>& testBuffer, Move<VkDeviceMemory>& memory) const210 tcu::TestStatus BufferDedicatedAllocation::createTestBuffer				(VkDeviceSize				size,
211 																		 VkBufferUsageFlags			usage,
212 																		 Context&					context,
213 																		 Move<VkBuffer>&			testBuffer,
214 																		 Move<VkDeviceMemory>&		memory) const
215 {
216 	const InstanceInterface&			vkInstance						= context.getInstanceInterface();
217 	const VkDevice						vkDevice						= context.getDevice();
218 	const VkPhysicalDevice				vkPhysicalDevice				= context.getPhysicalDevice();
219 	const DeviceInterface&				vk								= context.getDeviceInterface();
220 	const deUint32						queueFamilyIndex				= context.getUniversalQueueFamilyIndex();
221 	VkPhysicalDeviceMemoryProperties	memoryProperties;
222 	VkMemoryDedicatedRequirements		dedicatedRequirements			=
223 	{
224 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,				// VkStructureType		sType;
225 		DE_NULL,														// const void*			pNext;
226 		false,															// VkBool32				prefersDedicatedAllocation
227 		false															// VkBool32				requiresDedicatedAllocation
228 	};
229 	VkMemoryRequirements2				memReqs							=
230 	{
231 		VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,						// VkStructureType		sType
232 		&dedicatedRequirements,											// void*				pNext
233 		{0, 0, 0}														// VkMemoryRequirements	memoryRequirements
234 	};
235 
236 	const VkBufferCreateInfo			bufferParams					=
237 	{
238 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,							//	VkStructureType			sType;
239 		DE_NULL,														//	const void*				pNext;
240 		0u,																//	VkBufferCreateFlags		flags;
241 		size,															//	VkDeviceSize			size;
242 		usage,															//	VkBufferUsageFlags		usage;
243 		VK_SHARING_MODE_EXCLUSIVE,										//	VkSharingMode			sharingMode;
244 		1u,																//	deUint32				queueFamilyCount;
245 		&queueFamilyIndex,												//	const deUint32*			pQueueFamilyIndices;
246 	};
247 
248 	try
249 	{
250 		testBuffer = vk::createBuffer(vk, vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
251 	}
252 	catch (const vk::Error& error)
253 	{
254 		return tcu::TestStatus::fail("Buffer creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
255 	}
256 
257 	VkBufferMemoryRequirementsInfo2	info								=
258 	{
259 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,			// VkStructureType		sType
260 		DE_NULL,														// const void*			pNext
261 		*testBuffer														// VkBuffer				buffer
262 	};
263 
264 	vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);
265 
266 	if (dedicatedRequirements.requiresDedicatedAllocation == VK_TRUE)
267 	{
268 		std::ostringstream				errorMsg;
269 		errorMsg << "Nonexternal objects cannot require dedicated allocation.";
270 		return tcu::TestStatus::fail(errorMsg.str());
271 	}
272 
273 	if (size > memReqs.memoryRequirements.size)
274 	{
275 		std::ostringstream				errorMsg;
276 		errorMsg << "Requied memory size (" << memReqs.memoryRequirements.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
277 		return tcu::TestStatus::fail(errorMsg.str());
278 	}
279 
280 	deMemset(&memoryProperties, 0, sizeof(memoryProperties));
281 	vkInstance.getPhysicalDeviceMemoryProperties(vkPhysicalDevice, &memoryProperties);
282 
283 	if (memReqs.memoryRequirements.memoryTypeBits == 0)
284 		return tcu::TestStatus::fail("memoryTypeBits is 0");
285 
286 	const deUint32						heapTypeIndex					= static_cast<deUint32>(deCtz32(memReqs.memoryRequirements.memoryTypeBits));
287 
288 	vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);			// get the proper size requirement
289 
290 	if (size > memReqs.memoryRequirements.size)
291 	{
292 		std::ostringstream				errorMsg;
293 		errorMsg << "Requied memory size (" << memReqs.memoryRequirements.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
294 		return tcu::TestStatus::fail(errorMsg.str());
295 	}
296 
297 	{
298 		VkResult						result							= VK_ERROR_OUT_OF_HOST_MEMORY;
299 		VkDeviceMemory					rawMemory						= DE_NULL;
300 
301 		vk::VkMemoryDedicatedAllocateInfo
302 										dedicatedInfo					=
303 		{
304 			VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,			// VkStructureType			sType
305 			DE_NULL,													// const void*				pNext
306 			DE_NULL,													// VkImage					image
307 			*testBuffer													// VkBuffer					buffer
308 		};
309 
310 		VkMemoryAllocateInfo			memoryAllocateInfo				=
311 		{
312 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,						// VkStructureType			sType
313 			&dedicatedInfo,												// const void*				pNext
314 			memReqs.memoryRequirements.size,							// VkDeviceSize				allocationSize
315 			heapTypeIndex,												// deUint32					memoryTypeIndex
316 		};
317 
318 		result = vk.allocateMemory(vkDevice, &memoryAllocateInfo, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
319 
320 		if (result != VK_SUCCESS)
321 			return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.memoryRequirements.size) + " bytes of memory");
322 
323 		memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
324 	}
325 
326 
327 	if (vk.bindBufferMemory(vkDevice, *testBuffer, *memory, 0) != VK_SUCCESS)
328 		return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
329 
330 	return tcu::TestStatus::incomplete();
331 }
332 
iterate(void)333 tcu::TestStatus BufferViewTestInstance::iterate							(void)
334 {
335 	const VkDevice						vkDevice						= m_context.getDevice();
336 	const DeviceInterface&				vk								= m_context.getDeviceInterface();
337 	const VkDeviceSize					size							= 3 * 5 * 7 * 64;
338 	Move<VkBuffer>						testBuffer;
339 	Move<VkDeviceMemory>				testBufferMemory;
340 
341 	// Create buffer
342 	if (m_testCase.bufferAllocationKind == ALLOCATION_KIND_DEDICATED)
343 	{
344 		BufferDedicatedAllocation().createTestBuffer(size, m_testCase.usage, m_context, testBuffer, testBufferMemory);
345 	}
346 	else
347 	{
348 		BufferSuballocation().createTestBuffer(size, m_testCase.usage, m_context, testBuffer, testBufferMemory);
349 	}
350 
351 	{
352 		// Create buffer view.
353 		Move<VkBufferView>				bufferView;
354 		const VkBufferViewCreateInfo	bufferViewCreateInfo			=
355 		{
356 			VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,					//	VkStructureType			sType;
357 			NULL,														//	const void*				pNext;
358 			(VkBufferViewCreateFlags)0,
359 			*testBuffer,												//	VkBuffer				buffer;
360 			m_testCase.format,											//	VkFormat				format;
361 			m_testCase.offset,											//	VkDeviceSize			offset;
362 			m_testCase.range,											//	VkDeviceSize			range;
363 		};
364 
365 		try
366 		{
367 			bufferView = createBufferView(vk, vkDevice, &bufferViewCreateInfo, (const VkAllocationCallbacks*)DE_NULL);
368 		}
369 		catch (const vk::Error& error)
370 		{
371 			return tcu::TestStatus::fail("Buffer View creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
372 		}
373 	}
374 
375 	// Testing complete view size.
376 	{
377 		Move<VkBufferView>				completeBufferView;
378 		VkBufferViewCreateInfo			completeBufferViewCreateInfo	=
379 		{
380 			VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,					//	VkStructureType			sType;
381 			NULL,														//	const void*				pNext;
382 			(VkBufferViewCreateFlags)0,
383 			*testBuffer,												//	VkBuffer				buffer;
384 			m_testCase.format,											//	VkFormat				format;
385 			m_testCase.offset,											//	VkDeviceSize			offset;
386 			size,														//	VkDeviceSize			range;
387 		};
388 
389 		try
390 		{
391 			completeBufferView = createBufferView(vk, vkDevice, &completeBufferViewCreateInfo, (const VkAllocationCallbacks*)DE_NULL);
392 		}
393 		catch (const vk::Error& error)
394 		{
395 			return tcu::TestStatus::fail("Buffer View creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
396 		}
397 	}
398 
399 	return tcu::TestStatus::pass("BufferView test");
400 }
401 
402 } // anonymous
403 
createBufferViewCreateTests(tcu::TestContext& testCtx)404  tcu::TestCaseGroup* createBufferViewCreateTests						(tcu::TestContext& testCtx)
405 {
406 	const VkDeviceSize					range							= VK_WHOLE_SIZE;
407 	const vk::VkBufferUsageFlags		usage[]							= { vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, vk::VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT };
408 	const vk::VkFormatFeatureFlags		feature[]						= { vk::VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT, vk::VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT };
409 	const char* const					usageName[]						= { "uniform", "storage"};
410 
411 	de::MovePtr<tcu::TestCaseGroup>		bufferViewTests					(new tcu::TestCaseGroup(testCtx, "create"));
412 
413 	if (!bufferViewTests)
414 		TCU_THROW(InternalError, "Could not create test group \"create\".");
415 
416 	de::MovePtr<tcu::TestCaseGroup>		bufferViewAllocationGroupTests[ALLOCATION_KIND_LAST]
417 																		=
418 	{
419 		// BufferView Construction Tests for Suballocated Buffer
420 		de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "suballocation")),
421 		de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "BufferView Construction Tests for Dedicatedly Allocated Buffer"))
422 	};
423 
424 	for (deUint32 allocationKind = 0; allocationKind < ALLOCATION_KIND_LAST; ++allocationKind)
425 	for (deUint32 usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usage); ++usageNdx)
426 	{
427 		de::MovePtr<tcu::TestCaseGroup>	usageGroup		(new tcu::TestCaseGroup(testCtx, usageName[usageNdx]));
428 
429 		for (deUint32 format = vk::VK_FORMAT_UNDEFINED + 1; format < VK_CORE_FORMAT_LAST; format++)
430 		{
431 			const std::string			formatName						= de::toLower(getFormatName((VkFormat)format)).substr(10);
432 			de::MovePtr<tcu::TestCaseGroup>	formatGroup		(new tcu::TestCaseGroup(testCtx, "suballocation"));
433 
434 			const std::string			testName						= de::toLower(getFormatName((VkFormat)format)).substr(10);
435 
436 			{
437 				const BufferViewCaseParameters
438 										testParams						=
439 				{
440 					static_cast<vk::VkFormat>(format),					// VkFormat					format;
441 					0,													// VkDeviceSize				offset;
442 					range,												// VkDeviceSize				range;
443 					usage[usageNdx],									// VkBufferUsageFlags		usage;
444 					feature[usageNdx],									// VkFormatFeatureFlags		flags;
445 					static_cast<AllocationKind>(allocationKind)			// AllocationKind			bufferAllocationKind;
446 				};
447 
448 				usageGroup->addChild(new BufferViewTestCase(testCtx, testName.c_str(), testParams));
449 			}
450 		}
451 		bufferViewAllocationGroupTests[allocationKind]->addChild(usageGroup.release());
452 	}
453 
454 	for (deUint32 subgroupNdx = 0u; subgroupNdx < DE_LENGTH_OF_ARRAY(bufferViewAllocationGroupTests); ++subgroupNdx)
455 	{
456 		bufferViewTests->addChild(bufferViewAllocationGroupTests[subgroupNdx].release());
457 	}
458 
459 	return bufferViewTests.release();
460 }
461 
462 } // api
463 } // vk
464