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