1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 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 Fill Buffer Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktApiFillBufferTests.hpp"
26#include "vktApiBufferAndImageAllocationUtil.hpp"
27
28#include "deStringUtil.hpp"
29#include "deUniquePtr.hpp"
30#include "vkImageUtil.hpp"
31#include "vkMemUtil.hpp"
32#include "vktTestCase.hpp"
33#include "vktTestCaseUtil.hpp"
34#include "vkQueryUtil.hpp"
35#include "vkRefUtil.hpp"
36#include "tcuImageCompare.hpp"
37#include "tcuTexture.hpp"
38#include "tcuTextureUtil.hpp"
39#include "tcuVectorType.hpp"
40#include "deSharedPtr.hpp"
41
42namespace vkt
43{
44
45namespace api
46{
47
48using namespace vk;
49
50namespace
51{
52
53struct TestParams
54{
55	enum
56	{
57		TEST_DATA_SIZE													= 256
58	};
59
60	VkDeviceSize					dstSize;
61	VkDeviceSize					dstOffset;
62	VkDeviceSize					size;
63	deUint32						testData[TEST_DATA_SIZE];
64	de::SharedPtr<IBufferAllocator>	bufferAllocator;
65};
66
67class FillBufferTestInstance : public vkt::TestInstance
68{
69public:
70									FillBufferTestInstance				(Context&					context,
71																		 TestParams					testParams);
72	virtual tcu::TestStatus			iterate								(void);
73protected:
74	const TestParams				m_params;
75
76	Move<VkCommandPool>				m_cmdPool;
77	Move<VkCommandBuffer>			m_cmdBuffer;
78	Move<VkFence>					m_fence;
79	de::MovePtr<tcu::TextureLevel>	m_destinationTextureLevel;
80	de::MovePtr<tcu::TextureLevel>	m_expectedTextureLevel;
81
82	VkCommandBufferBeginInfo		m_cmdBufferBeginInfo;
83
84	Move<VkBuffer>					m_destination;
85	de::MovePtr<Allocation>			m_destinationBufferAlloc;
86
87	void							generateBuffer						(tcu::PixelBufferAccess		buffer,
88																		 int						width,
89																		 int						height,
90																		 int						depth = 1);
91	virtual void					generateExpectedResult				(void);
92	void							uploadBuffer						(tcu::ConstPixelBufferAccess
93																									bufferAccess,
94																		 const Allocation&			bufferAlloc);
95	virtual tcu::TestStatus			checkTestResult						(tcu::ConstPixelBufferAccess
96																									result);
97	deUint32						calculateSize						(tcu::ConstPixelBufferAccess
98																									src) const
99	{
100		return src.getWidth() * src.getHeight() * src.getDepth() * tcu::getPixelSize(src.getFormat());
101	}
102};
103
104									FillBufferTestInstance::FillBufferTestInstance
105																		(Context&					context,
106																		 TestParams					testParams)
107									: vkt::TestInstance					(context)
108									, m_params							(testParams)
109{
110	const DeviceInterface&			vk									= context.getDeviceInterface();
111	const VkDevice					vkDevice							= context.getDevice();
112	const deUint32					queueFamilyIndex					= context.getUniversalQueueFamilyIndex();
113	Allocator&						memAlloc							= context.getDefaultAllocator();
114
115	// Create command pool
116	m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
117
118	// Create command buffer
119	m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
120
121	// Create fence
122	m_fence = createFence(vk, vkDevice);
123
124	testParams.bufferAllocator->createTestBuffer(m_params.dstSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, context, memAlloc, m_destination, MemoryRequirement::HostVisible, m_destinationBufferAlloc);
125}
126
127tcu::TestStatus						FillBufferTestInstance::iterate		(void)
128{
129	const int						dstLevelWidth						= (int)(m_params.dstSize / 4);
130	m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
131
132	generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
133
134	generateExpectedResult();
135
136	uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
137
138	const DeviceInterface&			vk									= m_context.getDeviceInterface();
139	const VkDevice					vkDevice							= m_context.getDevice();
140	const VkQueue					queue								= m_context.getUniversalQueue();
141
142	const VkBufferMemoryBarrier		dstBufferBarrier					=
143	{
144		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,						// VkStructureType			sType;
145		DE_NULL,														// const void*				pNext;
146		VK_ACCESS_TRANSFER_WRITE_BIT,									// VkAccessFlags			srcAccessMask;
147		VK_ACCESS_HOST_READ_BIT,										// VkAccessFlags			dstAccessMask;
148		VK_QUEUE_FAMILY_IGNORED,										// deUint32					srcQueueFamilyIndex;
149		VK_QUEUE_FAMILY_IGNORED,										// deUint32					dstQueueFamilyIndex;
150		*m_destination,													// VkBuffer					buffer;
151		0u,																// VkDeviceSize				offset;
152		m_params.dstOffset												// VkDeviceSize				size;
153	};
154
155	const VkCommandBufferBeginInfo	cmdBufferBeginInfo					=
156	{
157		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,					// VkStructureType			sType;
158		DE_NULL,														// const void*				pNext;
159		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,					// VkCommandBufferUsageFlags flags;
160		(const VkCommandBufferInheritanceInfo*)DE_NULL,
161	};
162
163	VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
164	vk.cmdFillBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData[0]);
165	vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
166	VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
167
168	const VkSubmitInfo				submitInfo							=
169	{
170		VK_STRUCTURE_TYPE_SUBMIT_INFO,									// VkStructureType			sType;
171		DE_NULL,														// const void*				pNext;
172		0u,																// deUint32					waitSemaphoreCount;
173		DE_NULL,														// const VkSemaphore*		pWaitSemaphores;
174		(const VkPipelineStageFlags*)DE_NULL,
175		1u,																// deUint32					commandBufferCount;
176		&m_cmdBuffer.get(),												// const VkCommandBuffer*	pCommandBuffers;
177		0u,																// deUint32					signalSemaphoreCount;
178		DE_NULL															// const VkSemaphore*		pSignalSemaphores;
179	};
180
181	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
182	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
183	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
184
185	// Read buffer data
186	de::MovePtr<tcu::TextureLevel>	resultLevel	(new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
187	invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset(), m_params.dstOffset);
188	tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
189
190	return checkTestResult(resultLevel->getAccess());
191}
192
193void								FillBufferTestInstance::generateBuffer
194																		(tcu::PixelBufferAccess		buffer,
195																		 int						width,
196																		 int						height,
197																		 int						depth)
198{
199	for (int z = 0; z < depth; z++)
200	{
201		for (int y = 0; y < height; y++)
202		{
203			for (int x = 0; x < width; x++)
204				buffer.setPixel(tcu::UVec4(x, y, z, 255), x, y, z);
205		}
206	}
207}
208
209void								FillBufferTestInstance::uploadBuffer
210																		(tcu::ConstPixelBufferAccess
211																									bufferAccess,
212																		 const Allocation&			bufferAlloc)
213{
214	const DeviceInterface&			vk									= m_context.getDeviceInterface();
215	const VkDevice					vkDevice							= m_context.getDevice();
216	const deUint32					bufferSize							= calculateSize(bufferAccess);
217
218	// Write buffer data
219	deMemcpy(bufferAlloc.getHostPtr(), bufferAccess.getDataPtr(), bufferSize);
220	flushMappedMemoryRange(vk, vkDevice, bufferAlloc.getMemory(), bufferAlloc.getOffset(), bufferSize);
221}
222
223tcu::TestStatus						FillBufferTestInstance::checkTestResult
224																		(tcu::ConstPixelBufferAccess
225																									result)
226{
227	const tcu::ConstPixelBufferAccess
228									expected							= m_expectedTextureLevel->getAccess();
229	const tcu::UVec4				threshold							(0, 0, 0, 0);
230
231	if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparsion", expected, result, threshold, tcu::COMPARE_LOG_RESULT))
232	{
233		return tcu::TestStatus::fail("Fill and Update Buffer test");
234	}
235
236	return tcu::TestStatus::pass("Fill and Update Buffer test");
237}
238
239void								FillBufferTestInstance::generateExpectedResult
240																		(void)
241{
242	const tcu::ConstPixelBufferAccess
243									dst									= m_destinationTextureLevel->getAccess();
244
245	m_expectedTextureLevel	= de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
246	tcu::copy(m_expectedTextureLevel->getAccess(), dst);
247
248	deUint32*						currentPtr							= (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
249	deUint32*						endPtr								= currentPtr + m_params.size / 4;
250
251	while (currentPtr < endPtr)
252	{
253		*currentPtr = m_params.testData[0];
254		currentPtr++;
255	}
256}
257
258class FillBufferTestCase : public vkt::TestCase
259{
260public:
261									FillBufferTestCase					(tcu::TestContext&			testCtx,
262																		 const std::string&			name,
263																		 const std::string&			description,
264																		 const TestParams			params)
265									: vkt::TestCase						(testCtx, name, description)
266									, m_params							(params)
267	{}
268
269	virtual TestInstance*			createInstance						(Context&					context) const
270	{
271		return static_cast<TestInstance*>(new FillBufferTestInstance(context, m_params));
272	}
273private:
274	const TestParams				m_params;
275};
276
277// Update Buffer
278
279class UpdateBufferTestInstance : public FillBufferTestInstance
280{
281public:
282									UpdateBufferTestInstance			(Context&					context,
283																		 TestParams					testParams)
284									: FillBufferTestInstance			(context, testParams)
285	{}
286	virtual tcu::TestStatus			iterate								(void);
287
288protected:
289	virtual void					generateExpectedResult				(void);
290};
291
292tcu::TestStatus						UpdateBufferTestInstance::iterate	(void)
293{
294	const int						dstLevelWidth						= (int)(m_params.dstSize / 4);
295	m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
296
297	generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
298
299	generateExpectedResult();
300
301	uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
302
303	const DeviceInterface&			vk									= m_context.getDeviceInterface();
304	const VkDevice					vkDevice							= m_context.getDevice();
305	const VkQueue					queue								= m_context.getUniversalQueue();
306
307	const VkBufferMemoryBarrier		dstBufferBarrier					=
308	{
309		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,						// VkStructureType			sType;
310		DE_NULL,														// const void*				pNext;
311		VK_ACCESS_TRANSFER_WRITE_BIT,									// VkAccessFlags			srcAccessMask;
312		VK_ACCESS_HOST_READ_BIT,										// VkAccessFlags			dstAccessMask;
313		VK_QUEUE_FAMILY_IGNORED,										// deUint32					srcQueueFamilyIndex;
314		VK_QUEUE_FAMILY_IGNORED,										// deUint32					dstQueueFamilyIndex;
315		*m_destination,													// VkBuffer					buffer;
316		0u,																// VkDeviceSize				offset;
317		m_params.dstOffset												// VkDeviceSize				size;
318	};
319
320	const VkCommandBufferBeginInfo	cmdBufferBeginInfo					=
321	{
322		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,					// VkStructureType			sType;
323		DE_NULL,														// const void*				pNext;
324		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,					// VkCommandBufferUsageFlags flags;
325		(const VkCommandBufferInheritanceInfo*)DE_NULL,
326	};
327
328	VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
329	vk.cmdUpdateBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData);
330	vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
331	VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
332
333	const VkSubmitInfo				submitInfo							=
334	{
335		VK_STRUCTURE_TYPE_SUBMIT_INFO,									// VkStructureType			sType;
336		DE_NULL,														// const void*				pNext;
337		0u,																// deUint32					waitSemaphoreCount;
338		DE_NULL,														// const VkSemaphore*		pWaitSemaphores;
339		(const VkPipelineStageFlags*)DE_NULL,
340		1u,																// deUint32					commandBufferCount;
341		&m_cmdBuffer.get(),												// const VkCommandBuffer*	pCommandBuffers;
342		0u,																// deUint32					signalSemaphoreCount;
343		DE_NULL															// const VkSemaphore*		pSignalSemaphores;
344	};
345
346	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
347	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
348	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
349
350	// Read buffer data
351	de::MovePtr<tcu::TextureLevel>	resultLevel	(new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
352	invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset(), m_params.dstOffset);
353	tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
354
355	return checkTestResult(resultLevel->getAccess());
356}
357
358void								UpdateBufferTestInstance::generateExpectedResult
359																		(void)
360{
361	const tcu::ConstPixelBufferAccess
362									dst									= m_destinationTextureLevel->getAccess();
363
364	m_expectedTextureLevel	= de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
365	tcu::copy(m_expectedTextureLevel->getAccess(), dst);
366
367	deUint32*						currentPtr							= (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
368
369	deMemcpy(currentPtr, m_params.testData, (size_t)m_params.size);
370}
371
372class UpdateBufferTestCase : public vkt::TestCase
373{
374public:
375									UpdateBufferTestCase				(tcu::TestContext&			testCtx,
376																		 const std::string&			name,
377																		 const std::string&			description,
378																		 const TestParams			params)
379									: vkt::TestCase						(testCtx, name, description)
380									, m_params							(params)
381	{}
382
383	virtual TestInstance*			createInstance						(Context&					context) const
384	{
385		return (TestInstance*) new UpdateBufferTestInstance(context, m_params);
386	}
387private:
388	TestParams						m_params;
389};
390
391} // anonymous
392
393tcu::TestCaseGroup*					createFillAndUpdateBufferTests	(tcu::TestContext&			testCtx)
394{
395	const de::SharedPtr<IBufferAllocator>
396									bufferAllocators[]					=
397	{
398		de::SharedPtr<BufferSuballocation>(new BufferSuballocation()),
399		de::SharedPtr<BufferDedicatedAllocation>(new BufferDedicatedAllocation())
400	};
401
402	de::MovePtr<tcu::TestCaseGroup>	fillAndUpdateBufferTests			(new tcu::TestCaseGroup(testCtx, "fill_and_update_buffer", "Fill and Update Buffer Tests"));
403	tcu::TestCaseGroup*				bufferViewAllocationGroupTests[]
404																		=
405	{
406		new tcu::TestCaseGroup(testCtx, "suballocation", "BufferView Fill and Update Tests for Suballocated Objects"),
407		new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "BufferView Fill and Update Tests for Dedicatedly Allocated Objects")
408	};
409	for (deUint32 subgroupNdx = 0u; subgroupNdx < DE_LENGTH_OF_ARRAY(bufferViewAllocationGroupTests); ++subgroupNdx)
410	{
411		if (bufferViewAllocationGroupTests[subgroupNdx] == DE_NULL)
412		{
413			TCU_THROW(InternalError, "Could not create test subgroup.");
414		}
415		fillAndUpdateBufferTests->addChild(bufferViewAllocationGroupTests[subgroupNdx]);
416	}
417	TestParams						params;
418	params.dstSize = TestParams::TEST_DATA_SIZE;
419
420
421	for (deUint32 buffersAllocationNdx = 0u; buffersAllocationNdx < DE_LENGTH_OF_ARRAY(bufferAllocators); ++buffersAllocationNdx)
422	{
423		DE_ASSERT(params.dstSize <= TestParams::TEST_DATA_SIZE);
424		deMemset(params.testData, 0xFFu, (size_t)params.dstSize);
425		params.bufferAllocator = bufferAllocators[buffersAllocationNdx];
426		const deUint32				testCaseGroupNdx					= buffersAllocationNdx;
427		tcu::TestCaseGroup*			currentTestsGroup					= bufferViewAllocationGroupTests[testCaseGroupNdx];
428
429		{
430			const std::string		description							("whole buffer");
431			const std::string		testName							("buffer_whole");
432
433			params.dstOffset = 0;
434			params.size = params.dstSize;
435
436			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
437			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
438		}
439
440		{
441			const std::string		description							("first word in buffer");
442			const std::string		testName							("buffer_first_one");
443
444			params.dstOffset = 0;
445			params.size = 4;
446
447			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
448			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
449		}
450
451		{
452			const std::string		description							("second word in buffer");
453			const std::string		testName							("buffer_second_one");
454
455			params.dstOffset = 4;
456			params.size = 4;
457
458			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
459			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
460		}
461
462		{
463			const std::string		description							("buffer second part");
464			const std::string		testName							("buffer_second_part");
465
466			params.dstOffset = params.dstSize / 2;
467			params.size = params.dstSize / 2;
468
469			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
470			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
471		}
472	}
473
474	return fillAndUpdateBufferTests.release();
475}
476
477} // api
478} // vkt
479