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