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#include "vktCustomInstancesDevices.hpp"
28
29#include "deStringUtil.hpp"
30#include "deUniquePtr.hpp"
31#include "vkImageUtil.hpp"
32#include "vkMemUtil.hpp"
33#include "vkCmdUtil.hpp"
34#include "vktTestCase.hpp"
35#include "vktTestCaseUtil.hpp"
36#include "vkQueryUtil.hpp"
37#include "vkRefUtil.hpp"
38#include "vkCmdUtil.hpp"
39#include "vkSafetyCriticalUtil.hpp"
40#include "tcuImageCompare.hpp"
41#include "tcuCommandLine.hpp"
42#include "tcuTexture.hpp"
43#include "tcuTextureUtil.hpp"
44#include "tcuVectorType.hpp"
45#include "deSharedPtr.hpp"
46#include <limits>
47
48namespace vkt
49{
50
51namespace api
52{
53
54using namespace vk;
55
56namespace
57{
58
59struct TestParams
60{
61	enum
62	{
63		TEST_DATA_SIZE													= 256
64	};
65
66	VkDeviceSize					dstSize;
67	VkDeviceSize					dstOffset;
68	VkDeviceSize					size;
69	deUint32						testData[TEST_DATA_SIZE];
70	de::SharedPtr<IBufferAllocator>	bufferAllocator;
71	bool							useTransferOnlyQueue;
72};
73
74// Creates a device that has transfer only operations
75Move<VkDevice> createCustomDevice(Context& context, uint32_t& queueFamilyIndex)
76{
77	const InstanceInterface&	instanceDriver = context.getInstanceInterface();
78	const VkPhysicalDevice		physicalDevice = context.getPhysicalDevice();
79
80	queueFamilyIndex = findQueueFamilyIndexWithCaps(instanceDriver, physicalDevice, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
81
82	const std::vector<VkQueueFamilyProperties>	queueFamilies = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice);
83
84	// This must be found, findQueueFamilyIndexWithCaps would have
85	// thrown a NotSupported exception if the requested queue type did
86	// not exist. Similarly, this was written with the assumption the
87	// "alternative" queue would be different to the universal queue.
88	DE_ASSERT(queueFamilyIndex < queueFamilies.size() && queueFamilyIndex != context.getUniversalQueueFamilyIndex());
89	const float queuePriority = 1.0f;
90	const VkDeviceQueueCreateInfo deviceQueueCreateInfos
91	{
92		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,		// VkStructureType				sType;
93		nullptr,										// const void*					pNext;
94		(VkDeviceQueueCreateFlags)0u,					// VkDeviceQueueCreateFlags		flags;
95		queueFamilyIndex,								// uint32_t						queueFamilyIndex;
96		1u,												// uint32_t						queueCount;
97		&queuePriority,									// const float*					pQueuePriorities;
98	};
99
100	// Replicate default device extension list.
101	const auto	extensionNames				= context.getDeviceCreationExtensions();
102	auto		synchronization2Features	= context.getSynchronization2Features();
103	auto		deviceFeatures2				= context.getDeviceFeatures2();
104	const void*	pNext						= &deviceFeatures2;
105
106	if (context.isDeviceFunctionalitySupported("VK_KHR_synchronization2"))
107	{
108		synchronization2Features.pNext = &deviceFeatures2;
109		pNext = &synchronization2Features;
110	}
111
112#ifdef CTS_USES_VULKANSC
113	VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ? context.getResourceInterface()->getStatMax() : resetDeviceObjectReservationCreateInfo();
114	memReservationInfo.pNext = pNext;
115	pNext = &memReservationInfo;
116
117	VkPipelineCacheCreateInfo			pcCI;
118	std::vector<VkPipelinePoolSize>		poolSizes;
119	if (context.getTestContext().getCommandLine().isSubProcess())
120	{
121		if (context.getResourceInterface()->getCacheDataSize() > 0)
122		{
123			pcCI =
124			{
125				VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,			// VkStructureType				sType;
126				DE_NULL,												// const void*					pNext;
127				VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
128					VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT,	// VkPipelineCacheCreateFlags	flags;
129				context.getResourceInterface()->getCacheDataSize(),	// deUintptr					initialDataSize;
130				context.getResourceInterface()->getCacheData()		// const void*					pInitialData;
131			};
132			memReservationInfo.pipelineCacheCreateInfoCount = 1;
133			memReservationInfo.pPipelineCacheCreateInfos = &pcCI;
134		}
135		poolSizes = context.getResourceInterface()->getPipelinePoolSizes();
136		if (!poolSizes.empty())
137		{
138			memReservationInfo.pipelinePoolSizeCount = deUint32(poolSizes.size());
139			memReservationInfo.pPipelinePoolSizes = poolSizes.data();
140		}
141	}
142#endif // CTS_USES_VULKANSC
143
144	const VkDeviceCreateInfo deviceCreateInfo
145	{
146		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,			// VkStructureType					sType;
147		pNext,											// const void*						pNext;
148		(VkDeviceCreateFlags)0u,						// VkDeviceCreateFlags				flags;
149		1u,												// uint32_t							queueCreateInfoCount;
150		&deviceQueueCreateInfos,						// const VkDeviceQueueCreateInfo*	pQueueCreateInfos;
151		0u,												// uint32_t							enabledLayerCount;
152		DE_NULL,										// const char* const*				ppEnabledLayerNames;
153		static_cast<uint32_t>(extensionNames.size()),	// uint32_t							enabledExtensionCount;
154		extensionNames.data(),							// const char* const*				ppEnabledExtensionNames;
155		DE_NULL,										// const VkPhysicalDeviceFeatures*	pEnabledFeatures;
156	};
157
158	return vkt::createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), context.getInstance(), instanceDriver, physicalDevice, &deviceCreateInfo);
159}
160
161class FillWholeBufferTestInstance : public vkt::TestInstance
162{
163public:
164							FillWholeBufferTestInstance	(Context& context, const TestParams& testParams);
165	virtual tcu::TestStatus iterate						(void) override;
166protected:
167	// dstSize will be used as the buffer size.
168	// dstOffset will be used as the offset for vkCmdFillBuffer.
169	// size in vkCmdFillBuffer will always be VK_WHOLE_SIZE.
170	const TestParams		m_params;
171
172	Move<VkDevice>			m_customDevice;
173	de::MovePtr<Allocator>	m_customAllocator;
174
175	VkDevice				m_device;
176	Allocator*				m_allocator;
177	uint32_t				m_queueFamilyIndex;
178
179	Move<VkCommandPool>		m_cmdPool;
180	Move<VkCommandBuffer>	m_cmdBuffer;
181
182	Move<VkBuffer>			m_destination;
183	de::MovePtr<Allocation>	m_destinationBufferAlloc;
184};
185
186FillWholeBufferTestInstance::FillWholeBufferTestInstance(Context& context, const TestParams& testParams)
187	: vkt::TestInstance(context), m_params(testParams)
188{
189	const InstanceInterface&	vki			= m_context.getInstanceInterface();
190	const DeviceInterface&		vk			= m_context.getDeviceInterface();
191	const VkPhysicalDevice		physDevice	= m_context.getPhysicalDevice();
192
193	if (testParams.useTransferOnlyQueue)
194	{
195		m_customDevice		= createCustomDevice(context, m_queueFamilyIndex);
196		m_customAllocator	= de::MovePtr<Allocator>(new SimpleAllocator(vk, *m_customDevice, getPhysicalDeviceMemoryProperties(vki, physDevice)));
197
198		m_device			= *m_customDevice;
199		m_allocator			= &(*m_customAllocator);
200	}
201	else
202	{
203		m_device			= context.getDevice();
204		m_allocator			= &context.getDefaultAllocator();
205		m_queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
206	}
207
208	m_cmdPool = createCommandPool(vk, m_device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, m_queueFamilyIndex);
209	m_cmdBuffer = allocateCommandBuffer(vk, m_device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
210	testParams.bufferAllocator->createTestBuffer(vk, m_device, m_queueFamilyIndex, m_params.dstSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, context, *m_allocator, m_destination, MemoryRequirement::HostVisible, m_destinationBufferAlloc);
211}
212
213tcu::TestStatus FillWholeBufferTestInstance::iterate(void)
214{
215	const DeviceInterface&	vk		= m_context.getDeviceInterface();
216	const VkQueue			queue	= getDeviceQueue(vk, m_device, m_queueFamilyIndex, 0);
217
218	// if posible use synchronization2 when testing transfer only queue
219	const bool useSynchronization2 = m_context.isDeviceFunctionalitySupported("VK_KHR_synchronization2") && m_params.useTransferOnlyQueue;
220
221	// Make sure some stuff below will work.
222	DE_ASSERT(m_params.dstSize >= sizeof(deUint32));
223	DE_ASSERT(m_params.dstSize <  static_cast<VkDeviceSize>(std::numeric_limits<size_t>::max()));
224	DE_ASSERT(m_params.dstOffset < m_params.dstSize);
225
226	// Fill buffer from the host and flush buffer memory.
227	deUint8* bytes = reinterpret_cast<deUint8*>(m_destinationBufferAlloc->getHostPtr());
228	deMemset(bytes, 0xff, static_cast<size_t>(m_params.dstSize));
229	flushAlloc(vk, m_device, *m_destinationBufferAlloc);
230
231	const VkBufferMemoryBarrier	gpuToHostBarrier
232	{
233		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType			sType;
234		DE_NULL,									// const void*				pNext;
235		VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags			srcAccessMask;
236		VK_ACCESS_HOST_READ_BIT,					// VkAccessFlags			dstAccessMask;
237		VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex;
238		VK_QUEUE_FAMILY_IGNORED,					// deUint32					dstQueueFamilyIndex;
239		*m_destination,								// VkBuffer					buffer;
240		0u,											// VkDeviceSize				offset;
241		VK_WHOLE_SIZE								// VkDeviceSize				size;
242	};
243
244#ifndef CTS_USES_VULKANSC
245	using BufferMemoryBarrier2		= VkBufferMemoryBarrier2;
246	using DependencyInfo			= VkDependencyInfo;
247	using CommandBufferSubmitInfo	= VkCommandBufferSubmitInfo;
248	using SubmitInfo2				= VkSubmitInfo2;
249	auto cmdPipelineBarrier2Fun		= &DeviceInterface::cmdPipelineBarrier2;
250	auto queueSubmit2Fun			= &DeviceInterface::queueSubmit2;
251#else
252	using BufferMemoryBarrier2		= VkBufferMemoryBarrier2KHR;
253	using DependencyInfo			= VkDependencyInfoKHR;
254	using CommandBufferSubmitInfo	= VkCommandBufferSubmitInfoKHR;
255	using SubmitInfo2				= VkSubmitInfo2KHR;
256	auto cmdPipelineBarrier2Fun		= &DeviceInterface::cmdPipelineBarrier2KHR;
257	auto queueSubmit2Fun			= &DeviceInterface::queueSubmit2KHR;
258#endif // CTS_USES_VULKANSC
259
260	BufferMemoryBarrier2 gpuToHostBarrier2	= initVulkanStructure();
261	gpuToHostBarrier2.srcStageMask			= VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR;
262	gpuToHostBarrier2.srcAccessMask			= VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR;
263	gpuToHostBarrier2.dstStageMask			= VK_PIPELINE_STAGE_2_HOST_BIT_KHR;
264	gpuToHostBarrier2.dstAccessMask			= VK_ACCESS_2_HOST_READ_BIT_KHR;
265	gpuToHostBarrier2.srcQueueFamilyIndex	= VK_QUEUE_FAMILY_IGNORED;
266	gpuToHostBarrier2.dstQueueFamilyIndex	= VK_QUEUE_FAMILY_IGNORED;
267	gpuToHostBarrier2.buffer				= *m_destination;
268	gpuToHostBarrier2.size					= VK_WHOLE_SIZE;
269
270	DependencyInfo depInfo = initVulkanStructure();
271	depInfo.bufferMemoryBarrierCount	= 1;
272	depInfo.pBufferMemoryBarriers		= &gpuToHostBarrier2;
273
274	// Fill buffer using VK_WHOLE_SIZE.
275	beginCommandBuffer(vk, *m_cmdBuffer);
276	vk.cmdFillBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, VK_WHOLE_SIZE, deUint32{0x01010101});
277
278	if (useSynchronization2)
279		(vk.*(cmdPipelineBarrier2Fun))(*m_cmdBuffer, &depInfo);
280	else
281		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, DE_NULL, 1, &gpuToHostBarrier, 0, DE_NULL);
282
283	endCommandBuffer(vk, *m_cmdBuffer);
284
285	Move<VkFence> fence(createFence(vk, m_device));
286	if (useSynchronization2)
287	{
288		CommandBufferSubmitInfo commandBufferInfos	= initVulkanStructure();
289		commandBufferInfos.commandBuffer			= *m_cmdBuffer;
290
291		SubmitInfo2 submitInfo2						= initVulkanStructure();
292		submitInfo2.commandBufferInfoCount			= 1u;
293		submitInfo2.pCommandBufferInfos				= &commandBufferInfos;
294
295		(vk.*(queueSubmit2Fun))(queue, 1u, &submitInfo2, *fence);
296	}
297	else
298	{
299		VkSubmitInfo submitInfo			= initVulkanStructure();
300		submitInfo.commandBufferCount	= 1u;
301		submitInfo.pCommandBuffers		= &m_cmdBuffer.get();
302
303		VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
304	}
305	waitForFence(vk, m_device, *fence);
306
307	// Invalidate buffer memory and check the buffer contains the expected results.
308	invalidateAlloc(vk, m_device, *m_destinationBufferAlloc);
309
310	const VkDeviceSize startOfExtra = (m_params.dstSize / sizeof(deUint32)) * sizeof(deUint32);
311	for (VkDeviceSize i = 0; i < m_params.dstSize; ++i)
312	{
313		const deUint8 expectedByte = ((i >= m_params.dstOffset && i < startOfExtra)? 0x01 : 0xff);
314		if (bytes[i] != expectedByte)
315		{
316			std::ostringstream msg;
317			msg << "Invalid byte at position " << i << " in the buffer (found 0x"
318				<< std::hex << static_cast<int>(bytes[i]) << " but expected 0x" << static_cast<int>(expectedByte) << ")";
319			return tcu::TestStatus::fail(msg.str());
320		}
321	}
322
323	return tcu::TestStatus::pass("Pass");
324}
325
326class FillWholeBufferTestCase : public vkt::TestCase
327{
328public:
329							FillWholeBufferTestCase	(tcu::TestContext&	testCtx,
330													 const std::string&	name,
331													 const TestParams	params)
332		: vkt::TestCase(testCtx, name), m_params(params)
333	{}
334
335	virtual TestInstance*	createInstance			(Context&			context) const override
336	{
337		return static_cast<TestInstance*>(new FillWholeBufferTestInstance(context, m_params));
338	}
339private:
340	const TestParams		m_params;
341};
342
343
344class FillBufferTestInstance : public vkt::TestInstance
345{
346public:
347									FillBufferTestInstance				(Context&					context,
348																		 TestParams					testParams);
349	virtual tcu::TestStatus			iterate								(void);
350protected:
351	const TestParams				m_params;
352
353	Move<VkDevice>					m_customDevice;
354	de::MovePtr<Allocator>			m_customAllocator;
355
356	VkDevice						m_device;
357	Allocator*						m_allocator;
358	uint32_t						m_queueFamilyIndex;
359
360	Move<VkCommandPool>				m_cmdPool;
361	Move<VkCommandBuffer>			m_cmdBuffer;
362	de::MovePtr<tcu::TextureLevel>	m_destinationTextureLevel;
363	de::MovePtr<tcu::TextureLevel>	m_expectedTextureLevel;
364
365	VkCommandBufferBeginInfo		m_cmdBufferBeginInfo;
366
367	Move<VkBuffer>					m_destination;
368	de::MovePtr<Allocation>			m_destinationBufferAlloc;
369
370	void							generateBuffer						(tcu::PixelBufferAccess		buffer,
371																		 int						width,
372																		 int						height,
373																		 int						depth = 1);
374	virtual void					generateExpectedResult				(void);
375	void							uploadBuffer						(tcu::ConstPixelBufferAccess
376																									bufferAccess,
377																		 const Allocation&			bufferAlloc);
378	virtual tcu::TestStatus			checkTestResult						(tcu::ConstPixelBufferAccess
379																									result);
380	deUint32						calculateSize						(tcu::ConstPixelBufferAccess
381																									src) const
382	{
383		return src.getWidth() * src.getHeight() * src.getDepth() * tcu::getPixelSize(src.getFormat());
384	}
385};
386
387									FillBufferTestInstance::FillBufferTestInstance
388																		(Context&					context,
389																		 TestParams					testParams)
390									: vkt::TestInstance					(context)
391									, m_params							(testParams)
392{
393	const InstanceInterface&	vki			= m_context.getInstanceInterface();
394	const DeviceInterface&		vk			= m_context.getDeviceInterface();
395	const VkPhysicalDevice		physDevice	= m_context.getPhysicalDevice();
396
397	if (testParams.useTransferOnlyQueue)
398	{
399		m_customDevice		= createCustomDevice(context, m_queueFamilyIndex);
400		m_customAllocator	= de::MovePtr<Allocator>(new SimpleAllocator(vk, *m_customDevice, getPhysicalDeviceMemoryProperties(vki, physDevice)));
401
402		m_device			= *m_customDevice;
403		m_allocator			= &(*m_customAllocator);
404	}
405	else
406	{
407		m_device			= context.getDevice();
408		m_allocator			= &context.getDefaultAllocator();
409		m_queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
410	}
411
412	// Create command pool
413	m_cmdPool = createCommandPool(vk, m_device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, m_queueFamilyIndex);
414
415	// Create command buffer
416	m_cmdBuffer = allocateCommandBuffer(vk, m_device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
417
418	testParams.bufferAllocator->createTestBuffer(vk, m_device, m_queueFamilyIndex, m_params.dstSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, context, *m_allocator, m_destination, MemoryRequirement::HostVisible, m_destinationBufferAlloc);
419}
420
421tcu::TestStatus						FillBufferTestInstance::iterate		(void)
422{
423	const int						dstLevelWidth						= (int)(m_params.dstSize / 4);
424	m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
425
426	generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
427
428	generateExpectedResult();
429
430	uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
431
432	const DeviceInterface&	vk		= m_context.getDeviceInterface();
433	const VkQueue			queue	= getDeviceQueue(vk, m_device, m_queueFamilyIndex, 0);
434
435	const VkBufferMemoryBarrier		dstBufferBarrier					=
436	{
437		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,						// VkStructureType			sType;
438		DE_NULL,														// const void*				pNext;
439		VK_ACCESS_TRANSFER_WRITE_BIT,									// VkAccessFlags			srcAccessMask;
440		VK_ACCESS_HOST_READ_BIT,										// VkAccessFlags			dstAccessMask;
441		VK_QUEUE_FAMILY_IGNORED,										// deUint32					srcQueueFamilyIndex;
442		VK_QUEUE_FAMILY_IGNORED,										// deUint32					dstQueueFamilyIndex;
443		*m_destination,													// VkBuffer					buffer;
444		m_params.dstOffset,												// VkDeviceSize				offset;
445		VK_WHOLE_SIZE													// VkDeviceSize				size;
446	};
447
448	beginCommandBuffer(vk, *m_cmdBuffer);
449	vk.cmdFillBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData[0]);
450	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);
451	endCommandBuffer(vk, *m_cmdBuffer);
452
453	submitCommandsAndWait(vk, m_device, queue, m_cmdBuffer.get());
454
455	// Read buffer data
456	de::MovePtr<tcu::TextureLevel>	resultLevel	(new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
457	invalidateAlloc(vk, m_device, *m_destinationBufferAlloc);
458	tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
459
460	return checkTestResult(resultLevel->getAccess());
461}
462
463void								FillBufferTestInstance::generateBuffer
464																		(tcu::PixelBufferAccess		buffer,
465																		 int						width,
466																		 int						height,
467																		 int						depth)
468{
469	for (int z = 0; z < depth; z++)
470	{
471		for (int y = 0; y < height; y++)
472		{
473			for (int x = 0; x < width; x++)
474				buffer.setPixel(tcu::UVec4(x, y, z, 255), x, y, z);
475		}
476	}
477}
478
479void								FillBufferTestInstance::uploadBuffer
480																		(tcu::ConstPixelBufferAccess
481																									bufferAccess,
482																		 const Allocation&			bufferAlloc)
483{
484	const DeviceInterface&			vk									= m_context.getDeviceInterface();
485	const deUint32					bufferSize							= calculateSize(bufferAccess);
486
487	// Write buffer data
488	deMemcpy(bufferAlloc.getHostPtr(), bufferAccess.getDataPtr(), bufferSize);
489	flushAlloc(vk, m_device, bufferAlloc);
490}
491
492tcu::TestStatus						FillBufferTestInstance::checkTestResult
493																		(tcu::ConstPixelBufferAccess
494																									result)
495{
496	const tcu::ConstPixelBufferAccess
497									expected							= m_expectedTextureLevel->getAccess();
498	const tcu::UVec4				threshold							(0, 0, 0, 0);
499
500	if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparsion", expected, result, threshold, tcu::COMPARE_LOG_RESULT))
501	{
502		return tcu::TestStatus::fail("Fill and Update Buffer test");
503	}
504
505	return tcu::TestStatus::pass("Fill and Update Buffer test");
506}
507
508void								FillBufferTestInstance::generateExpectedResult
509																		(void)
510{
511	const tcu::ConstPixelBufferAccess
512									dst									= m_destinationTextureLevel->getAccess();
513
514	m_expectedTextureLevel	= de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
515	tcu::copy(m_expectedTextureLevel->getAccess(), dst);
516
517	deUint32*						currentPtr							= (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
518	deUint32*						endPtr								= currentPtr + m_params.size / 4;
519
520	while (currentPtr < endPtr)
521	{
522		*currentPtr = m_params.testData[0];
523		currentPtr++;
524	}
525}
526
527class FillBufferTestCase : public vkt::TestCase
528{
529public:
530									FillBufferTestCase					(tcu::TestContext&			testCtx,
531																		 const std::string&			name,
532																		 const TestParams			params)
533									: vkt::TestCase						(testCtx, name)
534									, m_params							(params)
535	{}
536
537	virtual TestInstance*			createInstance						(Context&					context) const
538	{
539		return static_cast<TestInstance*>(new FillBufferTestInstance(context, m_params));
540	}
541private:
542	const TestParams				m_params;
543};
544
545// Update Buffer
546
547class UpdateBufferTestInstance : public FillBufferTestInstance
548{
549public:
550									UpdateBufferTestInstance			(Context&					context,
551																		 TestParams					testParams)
552									: FillBufferTestInstance			(context, testParams)
553	{}
554	virtual tcu::TestStatus			iterate								(void);
555
556protected:
557	virtual void					generateExpectedResult				(void);
558};
559
560tcu::TestStatus						UpdateBufferTestInstance::iterate	(void)
561{
562	const int						dstLevelWidth						= (int)(m_params.dstSize / 4);
563	m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
564
565	generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
566
567	generateExpectedResult();
568
569	uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
570
571	const DeviceInterface&	vk		= m_context.getDeviceInterface();
572	const VkQueue			queue	= getDeviceQueue(vk, m_device, m_queueFamilyIndex, 0);
573
574	const VkBufferMemoryBarrier		dstBufferBarrier					=
575	{
576		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,						// VkStructureType			sType;
577		DE_NULL,														// const void*				pNext;
578		VK_ACCESS_TRANSFER_WRITE_BIT,									// VkAccessFlags			srcAccessMask;
579		VK_ACCESS_HOST_READ_BIT,										// VkAccessFlags			dstAccessMask;
580		VK_QUEUE_FAMILY_IGNORED,										// deUint32					srcQueueFamilyIndex;
581		VK_QUEUE_FAMILY_IGNORED,										// deUint32					dstQueueFamilyIndex;
582		*m_destination,													// VkBuffer					buffer;
583		m_params.dstOffset,												// VkDeviceSize				offset;
584		VK_WHOLE_SIZE													// VkDeviceSize				size;
585	};
586
587	beginCommandBuffer(vk, *m_cmdBuffer);
588	vk.cmdUpdateBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData);
589	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);
590	endCommandBuffer(vk, *m_cmdBuffer);
591
592	submitCommandsAndWait(vk, m_device, queue, m_cmdBuffer.get());
593
594	// Read buffer data
595	de::MovePtr<tcu::TextureLevel>	resultLevel	(new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
596	invalidateAlloc(vk, m_device, *m_destinationBufferAlloc);
597	tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
598
599	return checkTestResult(resultLevel->getAccess());
600}
601
602void								UpdateBufferTestInstance::generateExpectedResult
603																		(void)
604{
605	const tcu::ConstPixelBufferAccess
606									dst									= m_destinationTextureLevel->getAccess();
607
608	m_expectedTextureLevel	= de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
609	tcu::copy(m_expectedTextureLevel->getAccess(), dst);
610
611	deUint32*						currentPtr							= (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
612
613	deMemcpy(currentPtr, m_params.testData, (size_t)m_params.size);
614}
615
616class UpdateBufferTestCase : public vkt::TestCase
617{
618public:
619									UpdateBufferTestCase				(tcu::TestContext&			testCtx,
620																		 const std::string&			name,
621																		 const TestParams			params)
622									: vkt::TestCase						(testCtx, name)
623									, m_params							(params)
624	{}
625
626	virtual TestInstance*			createInstance						(Context&					context) const
627	{
628		return (TestInstance*) new UpdateBufferTestInstance(context, m_params);
629	}
630private:
631	TestParams						m_params;
632};
633
634} // anonymous
635
636tcu::TestCaseGroup*					createFillAndUpdateBufferTests	(tcu::TestContext&			testCtx)
637{
638	const de::SharedPtr<IBufferAllocator> bufferAllocators[]
639	{
640		de::SharedPtr<BufferSuballocation>(new BufferSuballocation()),
641		de::SharedPtr<BufferDedicatedAllocation>(new BufferDedicatedAllocation())
642	};
643
644	de::MovePtr<tcu::TestCaseGroup> fillAndUpdateBufferTests(new tcu::TestCaseGroup(testCtx, "fill_and_update_buffer"));
645
646	struct TestGroupData
647	{
648		const char*		name;
649		bool			useDedicatedAllocation;
650		bool			useTransferOnlyQueue;
651	};
652	const TestGroupData testGroupData[]
653	{
654		// BufferView Fill and Update Tests for Suballocated Objects
655		{ "suballocation",false,	false },
656		// BufferView Fill and Update Tests for Suballocated Objects on transfer only queue
657		{ "suballocation_transfer_queue",false,	true },
658		// BufferView Fill and Update Tests for Dedicatedly Allocated Objects
659		{ "dedicated_alloc",true,	false },
660	};
661
662	TestParams params;
663	for (const auto& groupData : testGroupData)
664	{
665		de::MovePtr<tcu::TestCaseGroup> currentTestsGroup(new tcu::TestCaseGroup(testCtx, groupData.name));
666
667		params.dstSize				= TestParams::TEST_DATA_SIZE;
668		params.bufferAllocator		= bufferAllocators[groupData.useDedicatedAllocation];
669		params.useTransferOnlyQueue	= groupData.useTransferOnlyQueue;
670
671		deUint8* data = (deUint8*) params.testData;
672		for (deUint32 b = 0u; b < (params.dstSize * sizeof(params.testData[0])); b++)
673			data[b] = (deUint8) (b % 255);
674
675		{
676			const std::string		testName							("buffer_whole");
677
678			params.dstOffset = 0;
679			params.size = params.dstSize;
680
681			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, params));
682			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, params));
683		}
684
685		{
686			const std::string		testName							("buffer_first_one");
687
688			params.dstOffset = 0;
689			params.size = 4;
690
691			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, params));
692			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, params));
693		}
694
695		{
696			const std::string		testName							("buffer_second_one");
697
698			params.dstOffset = 4;
699			params.size = 4;
700
701			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, params));
702			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, params));
703		}
704
705		{
706			const std::string		testName							("buffer_second_part");
707
708			params.dstOffset = params.dstSize / 2;
709			params.size = params.dstSize / 2;
710
711			currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, params));
712			currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, params));
713		}
714
715		// VK_WHOLE_SIZE tests.
716		{
717			for (VkDeviceSize i = 0; i < sizeof(deUint32); ++i)
718			{
719				for (VkDeviceSize j = 0; j < sizeof(deUint32); ++j)
720				{
721					params.dstSize		= TestParams::TEST_DATA_SIZE + i;
722					params.dstOffset	= j * sizeof(deUint32);
723					params.size			= VK_WHOLE_SIZE;
724
725					const VkDeviceSize	extraBytes	= params.dstSize % sizeof(deUint32);
726					const std::string	name		= "fill_buffer_vk_whole_size_" + de::toString(extraBytes) + "_extra_bytes_offset_" + de::toString(params.dstOffset);
727
728					currentTestsGroup->addChild(new FillWholeBufferTestCase{testCtx, name, params});
729				}
730			}
731		}
732
733		fillAndUpdateBufferTests->addChild(currentTestsGroup.release());
734	}
735
736	return fillAndUpdateBufferTests.release();
737}
738
739} // api
740} // vkt
741