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,const std::string & description,BufferViewCaseParameters createInfo)113 										BufferViewTestCase				(tcu::TestContext&			testCtx,
114 																		 const std::string&			name,
115 																		 const std::string&			description,
116 																		 BufferViewCaseParameters	createInfo)
117 										: TestCase						(testCtx, name, description)
118 										, m_testCase					(createInfo)
119 	{}
~BufferViewTestCase(void)120 	virtual								~BufferViewTestCase				(void)
121 	{}
createInstance(Context & ctx) const122 	virtual TestInstance*				createInstance					(Context&					ctx) const
123 	{
124 		return new BufferViewTestInstance(ctx, m_testCase);
125 	}
checkSupport(Context & ctx) const126 	virtual void						checkSupport					(Context&					ctx) const
127 	{
128 		VkFormatProperties					properties;
129 
130 		ctx.getInstanceInterface().getPhysicalDeviceFormatProperties(ctx.getPhysicalDevice(), m_testCase.format, &properties);
131 		if (!(properties.bufferFeatures & m_testCase.features))
132 			TCU_THROW(NotSupportedError, "Format not supported");
133 		if (m_testCase.bufferAllocationKind == ALLOCATION_KIND_DEDICATED)
134 		{
135 			const std::vector<std::string>&		extensions = ctx.getDeviceExtensions();
136 			const deBool						isSupported = isDeviceExtensionSupported(ctx.getUsedApiVersion(), extensions, "VK_KHR_dedicated_allocation");
137 			if (!isSupported)
138 				TCU_THROW(NotSupportedError, "Dedicated allocation not supported");
139 		}
140 	}
141 private:
142 	BufferViewCaseParameters			m_testCase;
143 };
144 
createTestBuffer(VkDeviceSize size,VkBufferUsageFlags usage,Context & context,Move<VkBuffer> & testBuffer,Move<VkDeviceMemory> & memory) const145 tcu::TestStatus BufferSuballocation::createTestBuffer					(VkDeviceSize				size,
146 																		 VkBufferUsageFlags			usage,
147 																		 Context&					context,
148 																		 Move<VkBuffer>&			testBuffer,
149 																		 Move<VkDeviceMemory>&		memory) const
150 {
151 	const VkDevice						vkDevice						= context.getDevice();
152 	const DeviceInterface&				vk								= context.getDeviceInterface();
153 	const deUint32						queueFamilyIndex				= context.getUniversalQueueFamilyIndex();
154 	VkMemoryRequirements				memReqs;
155 	const VkBufferCreateInfo			bufferParams					=
156 	{
157 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,							//	VkStructureType			sType;
158 		DE_NULL,														//	const void*				pNext;
159 		0u,																//	VkBufferCreateFlags		flags;
160 		size,															//	VkDeviceSize			size;
161 		usage,															//	VkBufferUsageFlags		usage;
162 		VK_SHARING_MODE_EXCLUSIVE,										//	VkSharingMode			sharingMode;
163 		1u,																//	deUint32				queueFamilyCount;
164 		&queueFamilyIndex,												//	const deUint32*			pQueueFamilyIndices;
165 	};
166 
167 	try
168 	{
169 		testBuffer = vk::createBuffer(vk, vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
170 	}
171 	catch (const vk::Error& error)
172 	{
173 		return tcu::TestStatus::fail("Buffer creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
174 	}
175 
176 	vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
177 
178 	if (size > memReqs.size)
179 	{
180 		std::ostringstream errorMsg;
181 		errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
182 		return tcu::TestStatus::fail(errorMsg.str());
183 	}
184 
185 	const VkMemoryAllocateInfo			memAlloc						=
186 	{
187 		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,							//	VkStructureType			sType
188 		NULL,															//	const void*				pNext
189 		memReqs.size,													//	VkDeviceSize			allocationSize
190 		(deUint32)deCtz32(memReqs.memoryTypeBits)						//	deUint32				memoryTypeIndex
191 	};
192 
193 	try
194 	{
195 		memory = allocateMemory(vk, vkDevice, &memAlloc, (const VkAllocationCallbacks*)DE_NULL);
196 	}
197 	catch (const vk::Error& error)
198 	{
199 		return tcu::TestStatus::fail("Alloc memory failed! (Error code: " + de::toString(error.getMessage()) + ")");
200 	}
201 
202 	if (vk.bindBufferMemory(vkDevice, *testBuffer, *memory, 0) != VK_SUCCESS)
203 		return tcu::TestStatus::fail("Bind buffer memory failed!");
204 
205 	return tcu::TestStatus::incomplete();
206 }
207 
createTestBuffer(VkDeviceSize size,VkBufferUsageFlags usage,Context & context,Move<VkBuffer> & testBuffer,Move<VkDeviceMemory> & memory) const208 tcu::TestStatus BufferDedicatedAllocation::createTestBuffer				(VkDeviceSize				size,
209 																		 VkBufferUsageFlags			usage,
210 																		 Context&					context,
211 																		 Move<VkBuffer>&			testBuffer,
212 																		 Move<VkDeviceMemory>&		memory) const
213 {
214 	const InstanceInterface&			vkInstance						= context.getInstanceInterface();
215 	const VkDevice						vkDevice						= context.getDevice();
216 	const VkPhysicalDevice				vkPhysicalDevice				= context.getPhysicalDevice();
217 	const DeviceInterface&				vk								= context.getDeviceInterface();
218 	const deUint32						queueFamilyIndex				= context.getUniversalQueueFamilyIndex();
219 	VkPhysicalDeviceMemoryProperties	memoryProperties;
220 	VkMemoryDedicatedRequirements		dedicatedRequirements			=
221 	{
222 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,				// VkStructureType		sType;
223 		DE_NULL,														// const void*			pNext;
224 		false,															// VkBool32				prefersDedicatedAllocation
225 		false															// VkBool32				requiresDedicatedAllocation
226 	};
227 	VkMemoryRequirements2				memReqs							=
228 	{
229 		VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,						// VkStructureType		sType
230 		&dedicatedRequirements,											// void*				pNext
231 		{0, 0, 0}														// VkMemoryRequirements	memoryRequirements
232 	};
233 
234 	const VkBufferCreateInfo			bufferParams					=
235 	{
236 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,							//	VkStructureType			sType;
237 		DE_NULL,														//	const void*				pNext;
238 		0u,																//	VkBufferCreateFlags		flags;
239 		size,															//	VkDeviceSize			size;
240 		usage,															//	VkBufferUsageFlags		usage;
241 		VK_SHARING_MODE_EXCLUSIVE,										//	VkSharingMode			sharingMode;
242 		1u,																//	deUint32				queueFamilyCount;
243 		&queueFamilyIndex,												//	const deUint32*			pQueueFamilyIndices;
244 	};
245 
246 	try
247 	{
248 		testBuffer = vk::createBuffer(vk, vkDevice, &bufferParams, (const VkAllocationCallbacks*)DE_NULL);
249 	}
250 	catch (const vk::Error& error)
251 	{
252 		return tcu::TestStatus::fail("Buffer creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
253 	}
254 
255 	VkBufferMemoryRequirementsInfo2	info								=
256 	{
257 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,			// VkStructureType		sType
258 		DE_NULL,														// const void*			pNext
259 		*testBuffer														// VkBuffer				buffer
260 	};
261 
262 	vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);
263 
264 	if (dedicatedRequirements.requiresDedicatedAllocation == VK_TRUE)
265 	{
266 		std::ostringstream				errorMsg;
267 		errorMsg << "Nonexternal objects cannot require dedicated allocation.";
268 		return tcu::TestStatus::fail(errorMsg.str());
269 	}
270 
271 	if (size > memReqs.memoryRequirements.size)
272 	{
273 		std::ostringstream				errorMsg;
274 		errorMsg << "Requied memory size (" << memReqs.memoryRequirements.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
275 		return tcu::TestStatus::fail(errorMsg.str());
276 	}
277 
278 	deMemset(&memoryProperties, 0, sizeof(memoryProperties));
279 	vkInstance.getPhysicalDeviceMemoryProperties(vkPhysicalDevice, &memoryProperties);
280 
281 	const deUint32						heapTypeIndex					= static_cast<deUint32>(deCtz32(memReqs.memoryRequirements.memoryTypeBits));
282 
283 	vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs);			// get the proper size requirement
284 
285 	if (size > memReqs.memoryRequirements.size)
286 	{
287 		std::ostringstream				errorMsg;
288 		errorMsg << "Requied memory size (" << memReqs.memoryRequirements.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
289 		return tcu::TestStatus::fail(errorMsg.str());
290 	}
291 
292 	{
293 		VkResult						result							= VK_ERROR_OUT_OF_HOST_MEMORY;
294 		VkDeviceMemory					rawMemory						= DE_NULL;
295 
296 		vk::VkMemoryDedicatedAllocateInfo
297 										dedicatedInfo					=
298 		{
299 			VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,			// VkStructureType			sType
300 			DE_NULL,													// const void*				pNext
301 			DE_NULL,													// VkImage					image
302 			*testBuffer													// VkBuffer					buffer
303 		};
304 
305 		VkMemoryAllocateInfo			memoryAllocateInfo				=
306 		{
307 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,						// VkStructureType			sType
308 			&dedicatedInfo,												// const void*				pNext
309 			memReqs.memoryRequirements.size,							// VkDeviceSize				allocationSize
310 			heapTypeIndex,												// deUint32					memoryTypeIndex
311 		};
312 
313 		result = vk.allocateMemory(vkDevice, &memoryAllocateInfo, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
314 
315 		if (result != VK_SUCCESS)
316 			return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.memoryRequirements.size) + " bytes of memory");
317 
318 		memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
319 	}
320 
321 
322 	if (vk.bindBufferMemory(vkDevice, *testBuffer, *memory, 0) != VK_SUCCESS)
323 		return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
324 
325 	return tcu::TestStatus::incomplete();
326 }
327 
iterate(void)328 tcu::TestStatus BufferViewTestInstance::iterate							(void)
329 {
330 	const VkDevice						vkDevice						= m_context.getDevice();
331 	const DeviceInterface&				vk								= m_context.getDeviceInterface();
332 	const VkDeviceSize					size							= 3 * 5 * 7 * 64;
333 	Move<VkBuffer>						testBuffer;
334 	Move<VkDeviceMemory>				testBufferMemory;
335 
336 	// Create buffer
337 	if (m_testCase.bufferAllocationKind == ALLOCATION_KIND_DEDICATED)
338 	{
339 		BufferDedicatedAllocation().createTestBuffer(size, m_testCase.usage, m_context, testBuffer, testBufferMemory);
340 	}
341 	else
342 	{
343 		BufferSuballocation().createTestBuffer(size, m_testCase.usage, m_context, testBuffer, testBufferMemory);
344 	}
345 
346 	{
347 		// Create buffer view.
348 		Move<VkBufferView>				bufferView;
349 		const VkBufferViewCreateInfo	bufferViewCreateInfo			=
350 		{
351 			VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,					//	VkStructureType			sType;
352 			NULL,														//	const void*				pNext;
353 			(VkBufferViewCreateFlags)0,
354 			*testBuffer,												//	VkBuffer				buffer;
355 			m_testCase.format,											//	VkFormat				format;
356 			m_testCase.offset,											//	VkDeviceSize			offset;
357 			m_testCase.range,											//	VkDeviceSize			range;
358 		};
359 
360 		try
361 		{
362 			bufferView = createBufferView(vk, vkDevice, &bufferViewCreateInfo, (const VkAllocationCallbacks*)DE_NULL);
363 		}
364 		catch (const vk::Error& error)
365 		{
366 			return tcu::TestStatus::fail("Buffer View creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
367 		}
368 	}
369 
370 	// Testing complete view size.
371 	{
372 		Move<VkBufferView>				completeBufferView;
373 		VkBufferViewCreateInfo			completeBufferViewCreateInfo	=
374 		{
375 			VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,					//	VkStructureType			sType;
376 			NULL,														//	const void*				pNext;
377 			(VkBufferViewCreateFlags)0,
378 			*testBuffer,												//	VkBuffer				buffer;
379 			m_testCase.format,											//	VkFormat				format;
380 			m_testCase.offset,											//	VkDeviceSize			offset;
381 			size,														//	VkDeviceSize			range;
382 		};
383 
384 		try
385 		{
386 			completeBufferView = createBufferView(vk, vkDevice, &completeBufferViewCreateInfo, (const VkAllocationCallbacks*)DE_NULL);
387 		}
388 		catch (const vk::Error& error)
389 		{
390 			return tcu::TestStatus::fail("Buffer View creation failed! (Error code: " + de::toString(error.getMessage()) + ")");
391 		}
392 	}
393 
394 	return tcu::TestStatus::pass("BufferView test");
395 }
396 
397 } // anonymous
398 
createBufferViewCreateTests(tcu::TestContext & testCtx)399  tcu::TestCaseGroup* createBufferViewCreateTests						(tcu::TestContext& testCtx)
400 {
401 	const VkDeviceSize					range							= VK_WHOLE_SIZE;
402 	const vk::VkBufferUsageFlags		usage[]							= { vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, vk::VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT };
403 	const vk::VkFormatFeatureFlags		feature[]						= { vk::VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT, vk::VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT };
404 	const char* const					usageName[]						= { "uniform", "storage"};
405 
406 	de::MovePtr<tcu::TestCaseGroup>		bufferViewTests					(new tcu::TestCaseGroup(testCtx, "create", "BufferView Construction Tests"));
407 
408 	if (!bufferViewTests)
409 		TCU_THROW(InternalError, "Could not create test group \"create\".");
410 
411 	de::MovePtr<tcu::TestCaseGroup>		bufferViewAllocationGroupTests[ALLOCATION_KIND_LAST]
412 																		=
413 	{
414 		de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "suballocation", "BufferView Construction Tests for Suballocated Buffer")),
415 		de::MovePtr<tcu::TestCaseGroup>(new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "BufferView Construction Tests for Dedicatedly Allocated Buffer"))
416 	};
417 
418 	for (deUint32 allocationKind = 0; allocationKind < ALLOCATION_KIND_LAST; ++allocationKind)
419 	for (deUint32 usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usage); ++usageNdx)
420 	{
421 		de::MovePtr<tcu::TestCaseGroup>	usageGroup		(new tcu::TestCaseGroup(testCtx, usageName[usageNdx], ""));
422 
423 		for (deUint32 format = vk::VK_FORMAT_UNDEFINED + 1; format < VK_CORE_FORMAT_LAST; format++)
424 		{
425 			const std::string			formatName						= de::toLower(getFormatName((VkFormat)format)).substr(10);
426 			de::MovePtr<tcu::TestCaseGroup>	formatGroup		(new tcu::TestCaseGroup(testCtx, "suballocation", "BufferView Construction Tests for Suballocated Buffer"));
427 
428 			const std::string			testName						= de::toLower(getFormatName((VkFormat)format)).substr(10);
429 			const std::string			testDescription					= "vkBufferView test " + testName;
430 
431 			{
432 				const BufferViewCaseParameters
433 										testParams						=
434 				{
435 					static_cast<vk::VkFormat>(format),					// VkFormat					format;
436 					0,													// VkDeviceSize				offset;
437 					range,												// VkDeviceSize				range;
438 					usage[usageNdx],									// VkBufferUsageFlags		usage;
439 					feature[usageNdx],									// VkFormatFeatureFlags		flags;
440 					static_cast<AllocationKind>(allocationKind)			// AllocationKind			bufferAllocationKind;
441 				};
442 
443 				usageGroup->addChild(new BufferViewTestCase(testCtx, testName.c_str(), testDescription.c_str(), testParams));
444 			}
445 		}
446 		bufferViewAllocationGroupTests[allocationKind]->addChild(usageGroup.release());
447 	}
448 
449 	for (deUint32 subgroupNdx = 0u; subgroupNdx < DE_LENGTH_OF_ARRAY(bufferViewAllocationGroupTests); ++subgroupNdx)
450 	{
451 		bufferViewTests->addChild(bufferViewAllocationGroupTests[subgroupNdx].release());
452 	}
453 
454 	return bufferViewTests.release();
455 }
456 
457 } // api
458 } // vk
459