1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Sparse buffer tests
22 *//*--------------------------------------------------------------------*/
23
24#include "vktSparseResourcesBufferTests.hpp"
25#include "vktTestCaseUtil.hpp"
26#include "vktTestGroupUtil.hpp"
27#include "vktSparseResourcesTestsUtil.hpp"
28#include "vktSparseResourcesBase.hpp"
29#include "vktSparseResourcesBufferSparseBinding.hpp"
30#include "vktSparseResourcesBufferSparseResidency.hpp"
31#include "vktSparseResourcesBufferMemoryAliasing.hpp"
32
33#include "vkRef.hpp"
34#include "vkRefUtil.hpp"
35#include "vkPlatform.hpp"
36#include "vkPrograms.hpp"
37#include "vkMemUtil.hpp"
38#include "vkBuilderUtil.hpp"
39#include "vkQueryUtil.hpp"
40#include "vkTypeUtil.hpp"
41
42#include "tcuTestLog.hpp"
43
44#include "deUniquePtr.hpp"
45#include "deSharedPtr.hpp"
46#include "deMath.h"
47
48#include <string>
49#include <vector>
50#include <map>
51
52using namespace vk;
53using de::MovePtr;
54using de::UniquePtr;
55using de::SharedPtr;
56using tcu::Vec4;
57using tcu::IVec2;
58using tcu::IVec4;
59
60namespace vkt
61{
62namespace sparse
63{
64namespace
65{
66
67typedef SharedPtr<UniquePtr<Allocation> > AllocationSp;
68
69enum
70{
71	RENDER_SIZE		= 128,				//!< framebuffer size in pixels
72	GRID_SIZE		= RENDER_SIZE / 8,	//!< number of grid tiles in a row
73};
74
75enum TestFlagBits
76{
77												//   sparseBinding is implied
78	TEST_FLAG_ALIASED				= 1u << 0,	//!< sparseResidencyAliased
79	TEST_FLAG_RESIDENCY				= 1u << 1,	//!< sparseResidencyBuffer
80	TEST_FLAG_NON_RESIDENT_STRICT	= 1u << 2,	//!< residencyNonResidentStrict
81	TEST_FLAG_ENABLE_DEVICE_GROUPS	= 1u << 3,	//!< device groups are enabled
82};
83typedef deUint32 TestFlags;
84
85//! SparseAllocationBuilder output. Owns the allocated memory.
86struct SparseAllocation
87{
88	deUint32							numResourceChunks;
89	VkDeviceSize						resourceSize;		//!< buffer size in bytes
90	std::vector<AllocationSp>			allocations;		//!< actual allocated memory
91	std::vector<VkSparseMemoryBind>		memoryBinds;		//!< memory binds backing the resource
92};
93
94//! Utility to lay out memory allocations for a sparse buffer, including holes and aliased regions.
95//! Will allocate memory upon building.
96class SparseAllocationBuilder
97{
98public:
99								SparseAllocationBuilder	(void);
100
101	// \note "chunk" is the smallest (due to alignment) bindable amount of memory
102
103	SparseAllocationBuilder&	addMemoryHole			(const deUint32 numChunks = 1u);
104	SparseAllocationBuilder&	addResourceHole			(const deUint32 numChunks = 1u);
105	SparseAllocationBuilder&	addMemoryBind			(const deUint32 numChunks = 1u);
106	SparseAllocationBuilder&	addAliasedMemoryBind	(const deUint32 allocationNdx, const deUint32 chunkOffset, const deUint32 numChunks = 1u);
107	SparseAllocationBuilder&	addMemoryAllocation		(void);
108
109	MovePtr<SparseAllocation>	build					(const DeviceInterface&		vk,
110														 const VkDevice				device,
111														 Allocator&					allocator,
112														 VkBufferCreateInfo			referenceCreateInfo,		//!< buffer size is ignored in this info
113														 const VkDeviceSize			minChunkSize = 0ull) const;	//!< make sure chunks are at least this big
114
115private:
116	struct MemoryBind
117	{
118		deUint32	allocationNdx;
119		deUint32	resourceChunkNdx;
120		deUint32	memoryChunkNdx;
121		deUint32	numChunks;
122	};
123
124	deUint32					m_allocationNdx;
125	deUint32					m_resourceChunkNdx;
126	deUint32					m_memoryChunkNdx;
127	std::vector<MemoryBind>		m_memoryBinds;
128	std::vector<deUint32>		m_chunksPerAllocation;
129
130};
131
132SparseAllocationBuilder::SparseAllocationBuilder (void)
133	: m_allocationNdx		(0)
134	, m_resourceChunkNdx	(0)
135	, m_memoryChunkNdx		(0)
136{
137	m_chunksPerAllocation.push_back(0);
138}
139
140SparseAllocationBuilder& SparseAllocationBuilder::addMemoryHole (const deUint32 numChunks)
141{
142	m_memoryChunkNdx						+= numChunks;
143	m_chunksPerAllocation[m_allocationNdx]	+= numChunks;
144
145	return *this;
146}
147
148SparseAllocationBuilder& SparseAllocationBuilder::addResourceHole (const deUint32 numChunks)
149{
150	m_resourceChunkNdx += numChunks;
151
152	return *this;
153}
154
155SparseAllocationBuilder& SparseAllocationBuilder::addMemoryAllocation (void)
156{
157	DE_ASSERT(m_memoryChunkNdx != 0);	// doesn't make sense to have an empty allocation
158
159	m_allocationNdx  += 1;
160	m_memoryChunkNdx  = 0;
161	m_chunksPerAllocation.push_back(0);
162
163	return *this;
164}
165
166SparseAllocationBuilder& SparseAllocationBuilder::addMemoryBind (const deUint32 numChunks)
167{
168	const MemoryBind memoryBind =
169	{
170		m_allocationNdx,
171		m_resourceChunkNdx,
172		m_memoryChunkNdx,
173		numChunks
174	};
175	m_memoryBinds.push_back(memoryBind);
176
177	m_resourceChunkNdx						+= numChunks;
178	m_memoryChunkNdx						+= numChunks;
179	m_chunksPerAllocation[m_allocationNdx]	+= numChunks;
180
181	return *this;
182}
183
184SparseAllocationBuilder& SparseAllocationBuilder::addAliasedMemoryBind	(const deUint32 allocationNdx, const deUint32 chunkOffset, const deUint32 numChunks)
185{
186	DE_ASSERT(allocationNdx <= m_allocationNdx);
187
188	const MemoryBind memoryBind =
189	{
190		allocationNdx,
191		m_resourceChunkNdx,
192		chunkOffset,
193		numChunks
194	};
195	m_memoryBinds.push_back(memoryBind);
196
197	m_resourceChunkNdx += numChunks;
198
199	return *this;
200}
201
202inline VkMemoryRequirements requirementsWithSize (VkMemoryRequirements requirements, const VkDeviceSize size)
203{
204	requirements.size = size;
205	return requirements;
206}
207
208MovePtr<SparseAllocation> SparseAllocationBuilder::build (const DeviceInterface&	vk,
209														  const VkDevice			device,
210														  Allocator&				allocator,
211														  VkBufferCreateInfo		referenceCreateInfo,
212														  const VkDeviceSize		minChunkSize) const
213{
214
215	MovePtr<SparseAllocation>	sparseAllocation			(new SparseAllocation());
216
217								referenceCreateInfo.size	= sizeof(deUint32);
218	const Unique<VkBuffer>		refBuffer					(createBuffer(vk, device, &referenceCreateInfo));
219	const VkMemoryRequirements	memoryRequirements			= getBufferMemoryRequirements(vk, device, *refBuffer);
220	const VkDeviceSize			chunkSize					= std::max(memoryRequirements.alignment, static_cast<VkDeviceSize>(deAlign64(minChunkSize, memoryRequirements.alignment)));
221
222	for (std::vector<deUint32>::const_iterator numChunksIter = m_chunksPerAllocation.begin(); numChunksIter != m_chunksPerAllocation.end(); ++numChunksIter)
223	{
224		sparseAllocation->allocations.push_back(makeDeSharedPtr(
225			allocator.allocate(requirementsWithSize(memoryRequirements, *numChunksIter * chunkSize), MemoryRequirement::Any)));
226	}
227
228	for (std::vector<MemoryBind>::const_iterator memBindIter = m_memoryBinds.begin(); memBindIter != m_memoryBinds.end(); ++memBindIter)
229	{
230		const Allocation&			alloc	= **sparseAllocation->allocations[memBindIter->allocationNdx];
231		const VkSparseMemoryBind	bind	=
232		{
233			memBindIter->resourceChunkNdx * chunkSize,							// VkDeviceSize               resourceOffset;
234			memBindIter->numChunks * chunkSize,									// VkDeviceSize               size;
235			alloc.getMemory(),													// VkDeviceMemory             memory;
236			alloc.getOffset() + memBindIter->memoryChunkNdx * chunkSize,		// VkDeviceSize               memoryOffset;
237			(VkSparseMemoryBindFlags)0,											// VkSparseMemoryBindFlags    flags;
238		};
239		sparseAllocation->memoryBinds.push_back(bind);
240		referenceCreateInfo.size = std::max(referenceCreateInfo.size, bind.resourceOffset + bind.size);
241	}
242
243	sparseAllocation->resourceSize		= referenceCreateInfo.size;
244	sparseAllocation->numResourceChunks = m_resourceChunkNdx;
245
246	return sparseAllocation;
247}
248
249VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, const VkImageUsageFlags usage)
250{
251	const VkImageCreateInfo imageParams =
252	{
253		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
254		DE_NULL,										// const void*				pNext;
255		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
256		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
257		format,											// VkFormat					format;
258		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
259		1u,												// deUint32					mipLevels;
260		1u,												// deUint32					arrayLayers;
261		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
262		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
263		usage,											// VkImageUsageFlags		usage;
264		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
265		0u,												// deUint32					queueFamilyIndexCount;
266		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
267		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
268	};
269	return imageParams;
270}
271
272Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
273								   const VkDevice			device,
274								   const VkFormat			colorFormat)
275{
276	const VkAttachmentDescription colorAttachmentDescription =
277	{
278		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
279		colorFormat,										// VkFormat							format;
280		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
281		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
282		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
283		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
284		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
285		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
286		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
287	};
288
289	const VkAttachmentReference colorAttachmentRef =
290	{
291		0u,													// deUint32			attachment;
292		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
293	};
294
295	const VkSubpassDescription subpassDescription =
296	{
297		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
298		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
299		0u,													// deUint32							inputAttachmentCount;
300		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
301		1u,													// deUint32							colorAttachmentCount;
302		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
303		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
304		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
305		0u,													// deUint32							preserveAttachmentCount;
306		DE_NULL												// const deUint32*					pPreserveAttachments;
307	};
308
309	const VkRenderPassCreateInfo renderPassInfo =
310	{
311		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
312		DE_NULL,											// const void*						pNext;
313		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
314		1u,													// deUint32							attachmentCount;
315		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
316		1u,													// deUint32							subpassCount;
317		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
318		0u,													// deUint32							dependencyCount;
319		DE_NULL												// const VkSubpassDependency*		pDependencies;
320	};
321
322	return createRenderPass(vk, device, &renderPassInfo);
323}
324
325Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&					vk,
326									   const VkDevice							device,
327									   const VkPipelineLayout					pipelineLayout,
328									   const VkRenderPass						renderPass,
329									   const IVec2								renderSize,
330									   const VkPrimitiveTopology				topology,
331									   const deUint32							stageCount,
332									   const VkPipelineShaderStageCreateInfo*	pStages)
333{
334	const VkVertexInputBindingDescription vertexInputBindingDescription =
335	{
336		0u,								// uint32_t				binding;
337		sizeof(Vec4),					// uint32_t				stride;
338		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
339	};
340
341	const VkVertexInputAttributeDescription vertexInputAttributeDescription =
342	{
343		0u,									// uint32_t			location;
344		0u,									// uint32_t			binding;
345		VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
346		0u,									// uint32_t			offset;
347	};
348
349	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
350	{
351		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
352		DE_NULL,														// const void*                                 pNext;
353		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
354		1u,																// uint32_t                                    vertexBindingDescriptionCount;
355		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
356		1u,																// uint32_t                                    vertexAttributeDescriptionCount;
357		&vertexInputAttributeDescription,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
358	};
359
360	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
361	{
362		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
363		DE_NULL,														// const void*                                 pNext;
364		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
365		topology,														// VkPrimitiveTopology                         topology;
366		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
367	};
368
369	const VkViewport viewport = makeViewport(
370		0.0f, 0.0f,
371		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
372		0.0f, 1.0f);
373
374	const VkRect2D scissor = {
375		makeOffset2D(0, 0),
376		makeExtent2D(static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y())),
377	};
378
379	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
380	{
381		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
382		DE_NULL,														// const void*                                 pNext;
383		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
384		1u,																// uint32_t                                    viewportCount;
385		&viewport,														// const VkViewport*                           pViewports;
386		1u,																// uint32_t                                    scissorCount;
387		&scissor,														// const VkRect2D*                             pScissors;
388	};
389
390	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
391	{
392		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
393		DE_NULL,														// const void*                              pNext;
394		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
395		VK_FALSE,														// VkBool32                                 depthClampEnable;
396		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
397		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
398		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
399		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
400		VK_FALSE,														// VkBool32									depthBiasEnable;
401		0.0f,															// float									depthBiasConstantFactor;
402		0.0f,															// float									depthBiasClamp;
403		0.0f,															// float									depthBiasSlopeFactor;
404		1.0f,															// float									lineWidth;
405	};
406
407	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
408	{
409		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
410		DE_NULL,														// const void*								pNext;
411		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
412		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
413		VK_FALSE,														// VkBool32									sampleShadingEnable;
414		0.0f,															// float									minSampleShading;
415		DE_NULL,														// const VkSampleMask*						pSampleMask;
416		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
417		VK_FALSE														// VkBool32									alphaToOneEnable;
418	};
419
420	const VkStencilOpState stencilOpState = makeStencilOpState(
421		VK_STENCIL_OP_KEEP,				// stencil fail
422		VK_STENCIL_OP_KEEP,				// depth & stencil pass
423		VK_STENCIL_OP_KEEP,				// depth only fail
424		VK_COMPARE_OP_ALWAYS,			// compare op
425		0u,								// compare mask
426		0u,								// write mask
427		0u);							// reference
428
429	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
430	{
431		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
432		DE_NULL,														// const void*								pNext;
433		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
434		VK_FALSE,														// VkBool32									depthTestEnable;
435		VK_FALSE,														// VkBool32									depthWriteEnable;
436		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
437		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
438		VK_FALSE,														// VkBool32									stencilTestEnable;
439		stencilOpState,													// VkStencilOpState							front;
440		stencilOpState,													// VkStencilOpState							back;
441		0.0f,															// float									minDepthBounds;
442		1.0f,															// float									maxDepthBounds;
443	};
444
445	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
446	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
447	{
448		VK_FALSE,						// VkBool32					blendEnable;
449		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
450		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
451		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
452		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
453		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
454		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
455		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
456	};
457
458	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
459	{
460		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
461		DE_NULL,														// const void*									pNext;
462		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
463		VK_FALSE,														// VkBool32										logicOpEnable;
464		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
465		1u,																// deUint32										attachmentCount;
466		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
467		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
468	};
469
470	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
471	{
472		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
473		DE_NULL,											// const void*										pNext;
474		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags							flags;
475		stageCount,											// deUint32											stageCount;
476		pStages,											// const VkPipelineShaderStageCreateInfo*			pStages;
477		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
478		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
479		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
480		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
481		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
482		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
483		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
484		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
485		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
486		pipelineLayout,										// VkPipelineLayout									layout;
487		renderPass,											// VkRenderPass										renderPass;
488		0u,													// deUint32											subpass;
489		DE_NULL,											// VkPipeline										basePipelineHandle;
490		0,													// deInt32											basePipelineIndex;
491	};
492
493	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
494}
495
496//! Return true if there are any red (or all zero) pixels in the image
497bool imageHasErrorPixels (const tcu::ConstPixelBufferAccess image)
498{
499	const Vec4 errorColor	= Vec4(1.0f, 0.0f, 0.0f, 1.0f);
500	const Vec4 blankColor	= Vec4();
501
502	for (int y = 0; y < image.getHeight(); ++y)
503	for (int x = 0; x < image.getWidth(); ++x)
504	{
505		const Vec4 color = image.getPixel(x, y);
506		if (color == errorColor || color == blankColor)
507			return true;
508	}
509
510	return false;
511}
512
513class Renderer
514{
515public:
516	typedef std::map<VkShaderStageFlagBits, const VkSpecializationInfo*>	SpecializationMap;
517
518	//! Use the delegate to bind descriptor sets, vertex buffers, etc. and make a draw call
519	struct Delegate
520	{
521		virtual			~Delegate		(void) {}
522		virtual void	rendererDraw	(const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const = 0;
523	};
524
525	Renderer (const DeviceInterface&		vk,
526			  const VkDevice				device,
527			  Allocator&					allocator,
528			  const deUint32				queueFamilyIndex,
529			  const VkDescriptorSetLayout	descriptorSetLayout,	//!< may be NULL, if no descriptors are used
530			  BinaryCollection&				binaryCollection,
531			  const std::string&			vertexName,
532			  const std::string&			fragmentName,
533			  const VkBuffer				colorBuffer,
534			  const IVec2&					renderSize,
535			  const VkFormat				colorFormat,
536			  const Vec4&					clearColor,
537			  const VkPrimitiveTopology		topology,
538			  SpecializationMap				specMap = SpecializationMap())
539		: m_colorBuffer				(colorBuffer)
540		, m_renderSize				(renderSize)
541		, m_colorFormat				(colorFormat)
542		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
543		, m_clearColor				(clearColor)
544		, m_topology				(topology)
545		, m_descriptorSetLayout		(descriptorSetLayout)
546	{
547		m_colorImage		= makeImage		(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
548		m_colorImageAlloc	= bindImage		(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
549		m_colorAttachment	= makeImageView	(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
550
551		m_vertexModule		= createShaderModule	(vk, device, binaryCollection.get(vertexName), 0u);
552		m_fragmentModule	= createShaderModule	(vk, device, binaryCollection.get(fragmentName), 0u);
553
554		const VkPipelineShaderStageCreateInfo pShaderStages[] =
555		{
556			{
557				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
558				DE_NULL,													// const void*							pNext;
559				(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
560				VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
561				*m_vertexModule,											// VkShaderModule						module;
562				"main",														// const char*							pName;
563				specMap[VK_SHADER_STAGE_VERTEX_BIT],						// const VkSpecializationInfo*			pSpecializationInfo;
564			},
565			{
566				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
567				DE_NULL,													// const void*							pNext;
568				(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
569				VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
570				*m_fragmentModule,											// VkShaderModule						module;
571				"main",														// const char*							pName;
572				specMap[VK_SHADER_STAGE_FRAGMENT_BIT],						// const VkSpecializationInfo*			pSpecializationInfo;
573			}
574		};
575
576		m_renderPass		= makeRenderPass		(vk, device, m_colorFormat);
577		m_framebuffer		= makeFramebuffer		(vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
578													 static_cast<deUint32>(m_renderSize.x()), static_cast<deUint32>(m_renderSize.y()));
579		m_pipelineLayout	= makePipelineLayout	(vk, device, m_descriptorSetLayout);
580		m_pipeline			= makeGraphicsPipeline	(vk, device, *m_pipelineLayout, *m_renderPass, m_renderSize, m_topology, DE_LENGTH_OF_ARRAY(pShaderStages), pShaderStages);
581		m_cmdPool			= makeCommandPool		(vk, device, queueFamilyIndex);
582		m_cmdBuffer			= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
583	}
584
585	void draw (const DeviceInterface&	vk,
586			   const VkDevice			device,
587			   const VkQueue			queue,
588			   const Delegate&			drawDelegate,
589			   const bool				useDeviceGroups,
590			   const deUint32			deviceID) const
591	{
592		beginCommandBuffer(vk, *m_cmdBuffer);
593
594		const VkClearValue			clearValue	= makeClearValueColor(m_clearColor);
595		const VkRect2D				renderArea	=
596		{
597			makeOffset2D(0, 0),
598			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
599		};
600		const VkRenderPassBeginInfo renderPassBeginInfo =
601		{
602			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
603			DE_NULL,										// const void*             pNext;
604			*m_renderPass,									// VkRenderPass            renderPass;
605			*m_framebuffer,									// VkFramebuffer           framebuffer;
606			renderArea,										// VkRect2D                renderArea;
607			1u,												// uint32_t                clearValueCount;
608			&clearValue,									// const VkClearValue*     pClearValues;
609		};
610		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
611
612		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
613		drawDelegate.rendererDraw(*m_pipelineLayout, *m_cmdBuffer);
614
615		vk.cmdEndRenderPass(*m_cmdBuffer);
616
617		// Prepare color image for copy
618		{
619			const VkImageMemoryBarrier barriers[] =
620			{
621				{
622					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
623					DE_NULL,													// const void*				pNext;
624					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
625					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
626					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
627					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
628					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
629					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
630					*m_colorImage,												// VkImage					image;
631					m_colorSubresourceRange,									// VkImageSubresourceRange	subresourceRange;
632				},
633			};
634
635			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
636				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
637		}
638		// Color image -> host buffer
639		{
640			const VkBufferImageCopy region =
641			{
642				0ull,																		// VkDeviceSize                bufferOffset;
643				0u,																			// uint32_t                    bufferRowLength;
644				0u,																			// uint32_t                    bufferImageHeight;
645				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),			// VkImageSubresourceLayers    imageSubresource;
646				makeOffset3D(0, 0, 0),														// VkOffset3D                  imageOffset;
647				makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u),						// VkExtent3D                  imageExtent;
648			};
649
650			vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_colorBuffer, 1u, &region);
651		}
652		// Buffer write barrier
653		{
654			const VkBufferMemoryBarrier barriers[] =
655			{
656				{
657					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
658					DE_NULL,										// const void*        pNext;
659					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
660					VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
661					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
662					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
663					m_colorBuffer,									// VkBuffer           buffer;
664					0ull,											// VkDeviceSize       offset;
665					VK_WHOLE_SIZE,									// VkDeviceSize       size;
666				},
667			};
668
669			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
670				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
671		}
672
673		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
674		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer, 0U, DE_NULL, DE_NULL, 0U, DE_NULL, useDeviceGroups, deviceID);
675	}
676
677private:
678	const VkBuffer					m_colorBuffer;
679	const IVec2						m_renderSize;
680	const VkFormat					m_colorFormat;
681	const VkImageSubresourceRange	m_colorSubresourceRange;
682	const Vec4						m_clearColor;
683	const VkPrimitiveTopology		m_topology;
684	const VkDescriptorSetLayout		m_descriptorSetLayout;
685
686	Move<VkImage>					m_colorImage;
687	MovePtr<Allocation>				m_colorImageAlloc;
688	Move<VkImageView>				m_colorAttachment;
689	Move<VkShaderModule>			m_vertexModule;
690	Move<VkShaderModule>			m_fragmentModule;
691	Move<VkRenderPass>				m_renderPass;
692	Move<VkFramebuffer>				m_framebuffer;
693	Move<VkPipelineLayout>			m_pipelineLayout;
694	Move<VkPipeline>				m_pipeline;
695	Move<VkCommandPool>				m_cmdPool;
696	Move<VkCommandBuffer>			m_cmdBuffer;
697
698	// "deleted"
699				Renderer	(const Renderer&);
700	Renderer&	operator=	(const Renderer&);
701};
702
703void bindSparseBuffer (const DeviceInterface& vk, const VkDevice device, const VkQueue sparseQueue, const VkBuffer buffer, const SparseAllocation& sparseAllocation,
704						const bool useDeviceGroups, deUint32 resourceDevId, deUint32 memoryDeviceId)
705{
706	const VkSparseBufferMemoryBindInfo sparseBufferMemoryBindInfo =
707	{
708		buffer,														// VkBuffer                     buffer;
709		static_cast<deUint32>(sparseAllocation.memoryBinds.size()),	// uint32_t                     bindCount;
710		&sparseAllocation.memoryBinds[0],							// const VkSparseMemoryBind*    pBinds;
711	};
712
713	const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo =
714	{
715		VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR,		//VkStructureType							sType;
716		DE_NULL,													//const void*								pNext;
717		resourceDevId,												//deUint32									resourceDeviceIndex;
718		memoryDeviceId,												//deUint32									memoryDeviceIndex;
719	};
720
721	const VkBindSparseInfo bindInfo =
722	{
723		VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,							// VkStructureType                             sType;
724		useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL,		// const void*                                 pNext;
725		0u,															// uint32_t                                    waitSemaphoreCount;
726		DE_NULL,													// const VkSemaphore*                          pWaitSemaphores;
727		1u,															// uint32_t                                    bufferBindCount;
728		&sparseBufferMemoryBindInfo,								// const VkSparseBufferMemoryBindInfo*         pBufferBinds;
729		0u,															// uint32_t                                    imageOpaqueBindCount;
730		DE_NULL,													// const VkSparseImageOpaqueMemoryBindInfo*    pImageOpaqueBinds;
731		0u,															// uint32_t                                    imageBindCount;
732		DE_NULL,													// const VkSparseImageMemoryBindInfo*          pImageBinds;
733		0u,															// uint32_t                                    signalSemaphoreCount;
734		DE_NULL,													// const VkSemaphore*                          pSignalSemaphores;
735	};
736
737	const Unique<VkFence> fence(createFence(vk, device));
738
739	VK_CHECK(vk.queueBindSparse(sparseQueue, 1u, &bindInfo, *fence));
740	VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), VK_TRUE, ~0ull));
741}
742
743class SparseBufferTestInstance : public SparseResourcesBaseInstance, Renderer::Delegate
744{
745public:
746	SparseBufferTestInstance (Context& context, const TestFlags flags)
747		: SparseResourcesBaseInstance	(context, (flags & TEST_FLAG_ENABLE_DEVICE_GROUPS) != 0)
748		, m_aliased						((flags & TEST_FLAG_ALIASED)   != 0)
749		, m_residency					((flags & TEST_FLAG_RESIDENCY) != 0)
750		, m_nonResidentStrict			((flags & TEST_FLAG_NON_RESIDENT_STRICT) != 0)
751		, m_renderSize					(RENDER_SIZE, RENDER_SIZE)
752		, m_colorFormat					(VK_FORMAT_R8G8B8A8_UNORM)
753		, m_colorBufferSize				(m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat)))
754	{
755		{
756			QueueRequirementsVec requirements;
757			requirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
758			requirements.push_back(QueueRequirements(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 1u));
759
760			createDeviceSupportingQueues(requirements);
761		}
762		const VkPhysicalDeviceFeatures	features	= getPhysicalDeviceFeatures(m_context.getInstanceInterface(), getPhysicalDevice());
763
764		if (!features.sparseBinding)
765			TCU_THROW(NotSupportedError, "Missing feature: sparseBinding");
766
767		if (m_residency && !features.sparseResidencyBuffer)
768			TCU_THROW(NotSupportedError, "Missing feature: sparseResidencyBuffer");
769
770		if (m_aliased && !features.sparseResidencyAliased)
771			TCU_THROW(NotSupportedError, "Missing feature: sparseResidencyAliased");
772
773		if (m_nonResidentStrict && !m_context.getDeviceProperties().sparseProperties.residencyNonResidentStrict)
774			TCU_THROW(NotSupportedError, "Missing sparse property: residencyNonResidentStrict");
775
776		const DeviceInterface& vk		= getDeviceInterface();
777		m_sparseQueue					= getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0u);
778		m_universalQueue				= getQueue(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0u);
779
780		m_sharedQueueFamilyIndices[0]	= m_sparseQueue.queueFamilyIndex;
781		m_sharedQueueFamilyIndices[1]	= m_universalQueue.queueFamilyIndex;
782
783		m_colorBuffer					= makeBuffer(vk, getDevice(), makeBufferCreateInfo(m_colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
784		m_colorBufferAlloc				= bindBuffer(vk, getDevice(), getAllocator(), *m_colorBuffer, MemoryRequirement::HostVisible);
785
786		deMemset(m_colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(m_colorBufferSize));
787		flushMappedMemoryRange(vk, getDevice(), m_colorBufferAlloc->getMemory(), m_colorBufferAlloc->getOffset(), m_colorBufferSize);
788	}
789
790protected:
791	VkBufferCreateInfo getSparseBufferCreateInfo (const VkBufferUsageFlags usage) const
792	{
793		VkBufferCreateFlags	flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
794		if (m_residency)
795			flags |= VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT;
796		if (m_aliased)
797			flags |= VK_BUFFER_CREATE_SPARSE_ALIASED_BIT;
798
799		VkBufferCreateInfo referenceBufferCreateInfo =
800		{
801			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,				// VkStructureType        sType;
802			DE_NULL,											// const void*            pNext;
803			flags,												// VkBufferCreateFlags    flags;
804			0u,	// override later								// VkDeviceSize           size;
805			VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage,			// VkBufferUsageFlags     usage;
806			VK_SHARING_MODE_EXCLUSIVE,							// VkSharingMode          sharingMode;
807			0u,													// uint32_t               queueFamilyIndexCount;
808			DE_NULL,											// const uint32_t*        pQueueFamilyIndices;
809		};
810
811		if (m_sparseQueue.queueFamilyIndex != m_universalQueue.queueFamilyIndex)
812		{
813			referenceBufferCreateInfo.sharingMode			= VK_SHARING_MODE_CONCURRENT;
814			referenceBufferCreateInfo.queueFamilyIndexCount	= DE_LENGTH_OF_ARRAY(m_sharedQueueFamilyIndices);
815			referenceBufferCreateInfo.pQueueFamilyIndices	= m_sharedQueueFamilyIndices;
816		}
817
818		return referenceBufferCreateInfo;
819	}
820
821	void draw (const VkPrimitiveTopology	topology,
822			   const VkDescriptorSetLayout	descriptorSetLayout	= DE_NULL,
823			   Renderer::SpecializationMap	specMap				= Renderer::SpecializationMap(),
824			   bool							useDeviceGroups		= false,
825			   deUint32						deviceID			= 0)
826	{
827		const UniquePtr<Renderer> renderer(new Renderer(
828			getDeviceInterface(), getDevice(), getAllocator(), m_universalQueue.queueFamilyIndex, descriptorSetLayout,
829			m_context.getBinaryCollection(), "vert", "frag", *m_colorBuffer, m_renderSize, m_colorFormat, Vec4(1.0f, 0.0f, 0.0f, 1.0f), topology, specMap));
830
831		renderer->draw(getDeviceInterface(), getDevice(), m_universalQueue.queueHandle, *this, useDeviceGroups, deviceID);
832	}
833
834	bool isResultImageCorrect (void) const
835	{
836		invalidateMappedMemoryRange(getDeviceInterface(), getDevice(), m_colorBufferAlloc->getMemory(), 0ull, m_colorBufferSize);
837
838		const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(m_colorFormat), m_renderSize.x(), m_renderSize.y(), 1u, m_colorBufferAlloc->getHostPtr());
839
840		m_context.getTestContext().getLog()
841			<< tcu::LogImageSet("Result", "Result") << tcu::LogImage("color0", "", resultImage) << tcu::TestLog::EndImageSet;
842
843		return !imageHasErrorPixels(resultImage);
844	}
845
846	const bool							m_aliased;
847	const bool							m_residency;
848	const bool							m_nonResidentStrict;
849
850	Queue								m_sparseQueue;
851	Queue								m_universalQueue;
852
853private:
854	const IVec2							m_renderSize;
855	const VkFormat						m_colorFormat;
856	const VkDeviceSize					m_colorBufferSize;
857
858	Move<VkBuffer>						m_colorBuffer;
859	MovePtr<Allocation>					m_colorBufferAlloc;
860
861	deUint32							m_sharedQueueFamilyIndices[2];
862};
863
864void initProgramsDrawWithUBO (vk::SourceCollections& programCollection, const TestFlags flags)
865{
866	// Vertex shader
867	{
868		std::ostringstream src;
869		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
870			<< "\n"
871			<< "layout(location = 0) in vec4 in_position;\n"
872			<< "\n"
873			<< "out gl_PerVertex {\n"
874			<< "    vec4 gl_Position;\n"
875			<< "};\n"
876			<< "\n"
877			<< "void main(void)\n"
878			<< "{\n"
879			<< "    gl_Position = in_position;\n"
880			<< "}\n";
881
882		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
883	}
884
885	// Fragment shader
886	{
887		const bool			aliased				= (flags & TEST_FLAG_ALIASED) != 0;
888		const bool			residency			= (flags & TEST_FLAG_RESIDENCY) != 0;
889		const bool			nonResidentStrict	= (flags & TEST_FLAG_NON_RESIDENT_STRICT) != 0;
890		const std::string	valueExpr			= (aliased ? "ivec4(3*(ndx % nonAliasedSize) ^ 127, 0, 0, 0)" : "ivec4(3*ndx ^ 127, 0, 0, 0)");
891
892		std::ostringstream src;
893		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
894			<< "\n"
895			<< "layout(location = 0) out vec4 o_color;\n"
896			<< "\n"
897			<< "layout(constant_id = 1) const int dataSize  = 1;\n"
898			<< "layout(constant_id = 2) const int chunkSize = 1;\n"
899			<< "\n"
900			<< "layout(set = 0, binding = 0, std140) uniform SparseBuffer {\n"
901			<< "    ivec4 data[dataSize];\n"
902			<< "} ubo;\n"
903			<< "\n"
904			<< "void main(void)\n"
905			<< "{\n"
906			<< "    const int fragNdx        = int(gl_FragCoord.x) + " << RENDER_SIZE << " * int(gl_FragCoord.y);\n"
907			<< "    const int pageSize       = " << RENDER_SIZE << " * " << RENDER_SIZE << ";\n"
908			<< "    const int numChunks      = dataSize / chunkSize;\n";
909
910		if (aliased)
911			src << "    const int nonAliasedSize = (numChunks > 1 ? dataSize - chunkSize : dataSize);\n";
912
913		src << "    bool      ok             = true;\n"
914			<< "\n"
915			<< "    for (int ndx = fragNdx; ndx < dataSize; ndx += pageSize)\n"
916			<< "    {\n";
917
918		if (residency && nonResidentStrict)
919		{
920			src << "        if (ndx >= chunkSize && ndx < 2*chunkSize)\n"
921				<< "            ok = ok && (ubo.data[ndx] == ivec4(0));\n"
922				<< "        else\n"
923				<< "            ok = ok && (ubo.data[ndx] == " + valueExpr + ");\n";
924		}
925		else if (residency)
926		{
927			src << "        if (ndx >= chunkSize && ndx < 2*chunkSize)\n"
928				<< "            continue;\n"
929				<< "        ok = ok && (ubo.data[ndx] == " << valueExpr << ");\n";
930		}
931		else
932			src << "        ok = ok && (ubo.data[ndx] == " << valueExpr << ");\n";
933
934		src << "    }\n"
935			<< "\n"
936			<< "    if (ok)\n"
937			<< "        o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
938			<< "    else\n"
939			<< "        o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
940			<< "}\n";
941
942		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
943	}
944}
945
946//! Sparse buffer backing a UBO
947class UBOTestInstance : public SparseBufferTestInstance
948{
949public:
950	UBOTestInstance (Context& context, const TestFlags flags)
951		: SparseBufferTestInstance	(context, flags)
952	{
953	}
954
955	void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const
956	{
957		const DeviceInterface&	vk				= getDeviceInterface();
958		const VkDeviceSize		vertexOffset	= 0ull;
959
960		vk.cmdBindVertexBuffers	(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexOffset);
961		vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
962		vk.cmdDraw				(cmdBuffer, 4u, 1u, 0u, 0u);
963	}
964
965	tcu::TestStatus iterate (void)
966	{
967		const DeviceInterface&		vk					= getDeviceInterface();
968		MovePtr<SparseAllocation>	sparseAllocation;
969		Move<VkBuffer>				sparseBuffer;
970		Move<VkBuffer>				sparseBufferAliased;
971		bool						setupDescriptors	= true;
972
973		// Go through all physical devices
974		for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++)
975		{
976			const deUint32	firstDeviceID	= physDevID;
977			const deUint32	secondDeviceID	= (firstDeviceID + 1) % m_numPhysicalDevices;
978
979			// Set up the sparse buffer
980			{
981				VkBufferCreateInfo	referenceBufferCreateInfo	= getSparseBufferCreateInfo(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
982				const VkDeviceSize	minChunkSize				= 512u;	// make sure the smallest allocation is at least this big
983				deUint32			numMaxChunks				= 0u;
984
985				// Check how many chunks we can allocate given the alignment and size requirements of UBOs
986				{
987					const UniquePtr<SparseAllocation> minAllocation(SparseAllocationBuilder()
988						.addMemoryBind()
989						.build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize));
990
991					numMaxChunks = deMaxu32(static_cast<deUint32>(m_context.getDeviceProperties().limits.maxUniformBufferRange / minAllocation->resourceSize), 1u);
992				}
993
994				if (numMaxChunks < 4)
995				{
996					sparseAllocation = SparseAllocationBuilder()
997						.addMemoryBind()
998						.build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize);
999				}
1000				else
1001				{
1002					// Try to use a non-trivial memory allocation scheme to make it different from a non-sparse binding
1003					SparseAllocationBuilder builder;
1004					builder.addMemoryBind();
1005
1006					if (m_residency)
1007						builder.addResourceHole();
1008
1009					builder
1010						.addMemoryAllocation()
1011						.addMemoryHole()
1012						.addMemoryBind();
1013
1014					if (m_aliased)
1015						builder.addAliasedMemoryBind(0u, 0u);
1016
1017					sparseAllocation = builder.build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize);
1018					DE_ASSERT(sparseAllocation->resourceSize <= m_context.getDeviceProperties().limits.maxUniformBufferRange);
1019				}
1020
1021				// Create the buffer
1022				referenceBufferCreateInfo.size	= sparseAllocation->resourceSize;
1023				sparseBuffer					= makeBuffer(vk, getDevice(), referenceBufferCreateInfo);
1024				bindSparseBuffer(vk, getDevice(), m_sparseQueue.queueHandle, *sparseBuffer, *sparseAllocation, usingDeviceGroups(), firstDeviceID, secondDeviceID);
1025
1026				if (m_aliased)
1027				{
1028					sparseBufferAliased = makeBuffer(vk, getDevice(), referenceBufferCreateInfo);
1029					bindSparseBuffer(vk, getDevice(), m_sparseQueue.queueHandle, *sparseBufferAliased, *sparseAllocation, usingDeviceGroups(), firstDeviceID, secondDeviceID);
1030				}
1031			}
1032
1033			// Set uniform data
1034			{
1035				const bool					hasAliasedChunk		= (m_aliased && sparseAllocation->memoryBinds.size() > 1u);
1036				const VkDeviceSize			chunkSize			= sparseAllocation->resourceSize / sparseAllocation->numResourceChunks;
1037				const VkDeviceSize			stagingBufferSize	= sparseAllocation->resourceSize - (hasAliasedChunk ? chunkSize : 0);
1038				const deUint32				numBufferEntries	= static_cast<deUint32>(stagingBufferSize / sizeof(IVec4));
1039
1040				const Unique<VkBuffer>		stagingBuffer		(makeBuffer(vk, getDevice(), makeBufferCreateInfo(stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT)));
1041				const UniquePtr<Allocation>	stagingBufferAlloc	(bindBuffer(vk, getDevice(), getAllocator(), *stagingBuffer, MemoryRequirement::HostVisible));
1042
1043				{
1044					// If aliased chunk is used, the staging buffer is smaller than the sparse buffer and we don't overwrite the last chunk
1045					IVec4* const pData = static_cast<IVec4*>(stagingBufferAlloc->getHostPtr());
1046					for (deUint32 i = 0; i < numBufferEntries; ++i)
1047						pData[i] = IVec4(3*i ^ 127, 0, 0, 0);
1048
1049					flushMappedMemoryRange(vk, getDevice(), stagingBufferAlloc->getMemory(), stagingBufferAlloc->getOffset(), stagingBufferSize);
1050
1051					const VkBufferCopy copyRegion =
1052					{
1053						0ull,						// VkDeviceSize    srcOffset;
1054						0ull,						// VkDeviceSize    dstOffset;
1055						stagingBufferSize,			// VkDeviceSize    size;
1056					};
1057
1058					const Unique<VkCommandPool>		cmdPool		(makeCommandPool(vk, getDevice(), m_universalQueue.queueFamilyIndex));
1059					const Unique<VkCommandBuffer>	cmdBuffer	(allocateCommandBuffer(vk, getDevice(), *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1060
1061					beginCommandBuffer	(vk, *cmdBuffer);
1062					vk.cmdCopyBuffer	(*cmdBuffer, *stagingBuffer, *sparseBuffer, 1u, &copyRegion);
1063					endCommandBuffer	(vk, *cmdBuffer);
1064
1065					submitCommandsAndWait(vk, getDevice(), m_universalQueue.queueHandle, *cmdBuffer, 0u, DE_NULL, DE_NULL, 0, DE_NULL, usingDeviceGroups(), firstDeviceID);
1066					// Once the fence is signaled, the write is also available to the aliasing buffer.
1067				}
1068			}
1069
1070			// Make sure that we don't try to access a larger range than is allowed. This only applies to a single chunk case.
1071			const deUint32 maxBufferRange = deMinu32(static_cast<deUint32>(sparseAllocation->resourceSize), m_context.getDeviceProperties().limits.maxUniformBufferRange);
1072
1073			// Descriptor sets
1074			{
1075				// Setup only once
1076				if (setupDescriptors)
1077				{
1078					m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1079						.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
1080						.build(vk, getDevice());
1081
1082					m_descriptorPool = DescriptorPoolBuilder()
1083						.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
1084						.build(vk, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1085
1086					m_descriptorSet = makeDescriptorSet(vk, getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
1087					setupDescriptors = false;
1088				}
1089
1090				const VkBuffer					buffer				= (m_aliased ? *sparseBufferAliased : *sparseBuffer);
1091				const VkDescriptorBufferInfo	sparseBufferInfo	= makeDescriptorBufferInfo(buffer, 0ull, maxBufferRange);
1092
1093				DescriptorSetUpdateBuilder()
1094					.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &sparseBufferInfo)
1095					.update(vk, getDevice());
1096			}
1097
1098			// Vertex data
1099			{
1100				const Vec4 vertexData[] =
1101				{
1102					Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1103					Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
1104					Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1105					Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
1106				};
1107
1108				const VkDeviceSize	vertexBufferSize	= sizeof(vertexData);
1109
1110				m_vertexBuffer		= makeBuffer(vk, getDevice(), makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1111				m_vertexBufferAlloc	= bindBuffer(vk, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible);
1112
1113				deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertexData[0], vertexBufferSize);
1114				flushMappedMemoryRange(vk, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferSize);
1115			}
1116
1117			// Draw
1118			{
1119				std::vector<deInt32> specializationData;
1120				{
1121					const deUint32	numBufferEntries	= maxBufferRange / static_cast<deUint32>(sizeof(IVec4));
1122					const deUint32	numEntriesPerChunk	= numBufferEntries / sparseAllocation->numResourceChunks;
1123
1124					specializationData.push_back(numBufferEntries);
1125					specializationData.push_back(numEntriesPerChunk);
1126				}
1127
1128				const VkSpecializationMapEntry	specMapEntries[] =
1129				{
1130					{
1131						1u,					// uint32_t    constantID;
1132						0u,					// uint32_t    offset;
1133						sizeof(deInt32),	// size_t      size;
1134					},
1135					{
1136						2u,					// uint32_t    constantID;
1137						sizeof(deInt32),	// uint32_t    offset;
1138						sizeof(deInt32),	// size_t      size;
1139					},
1140				};
1141
1142				const VkSpecializationInfo specInfo =
1143				{
1144					DE_LENGTH_OF_ARRAY(specMapEntries),		// uint32_t                           mapEntryCount;
1145					specMapEntries,							// const VkSpecializationMapEntry*    pMapEntries;
1146					sizeInBytes(specializationData),		// size_t                             dataSize;
1147					getDataOrNullptr(specializationData),	// const void*                        pData;
1148				};
1149
1150				Renderer::SpecializationMap	specMap;
1151				specMap[VK_SHADER_STAGE_FRAGMENT_BIT] = &specInfo;
1152
1153				draw(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, *m_descriptorSetLayout, specMap, usingDeviceGroups(), firstDeviceID);
1154			}
1155
1156			if(!isResultImageCorrect())
1157				return tcu::TestStatus::fail("Some buffer values were incorrect");
1158		}
1159		return tcu::TestStatus::pass("Pass");
1160	}
1161
1162private:
1163	Move<VkBuffer>					m_vertexBuffer;
1164	MovePtr<Allocation>				m_vertexBufferAlloc;
1165
1166	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
1167	Move<VkDescriptorPool>			m_descriptorPool;
1168	Move<VkDescriptorSet>			m_descriptorSet;
1169};
1170
1171void initProgramsDrawGrid (vk::SourceCollections& programCollection, const TestFlags flags)
1172{
1173	DE_UNREF(flags);
1174
1175	// Vertex shader
1176	{
1177		std::ostringstream src;
1178		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1179			<< "\n"
1180			<< "layout(location = 0) in  vec4 in_position;\n"
1181			<< "layout(location = 0) out int  out_ndx;\n"
1182			<< "\n"
1183			<< "out gl_PerVertex {\n"
1184			<< "    vec4 gl_Position;\n"
1185			<< "};\n"
1186			<< "\n"
1187			<< "void main(void)\n"
1188			<< "{\n"
1189			<< "    gl_Position = in_position;\n"
1190			<< "    out_ndx     = gl_VertexIndex;\n"
1191			<< "}\n";
1192
1193		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1194	}
1195
1196	// Fragment shader
1197	{
1198		std::ostringstream src;
1199		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1200			<< "\n"
1201			<< "layout(location = 0) flat in  int  in_ndx;\n"
1202			<< "layout(location = 0)      out vec4 o_color;\n"
1203			<< "\n"
1204			<< "void main(void)\n"
1205			<< "{\n"
1206			<< "    if (in_ndx % 2 == 0)\n"
1207			<< "        o_color = vec4(vec3(1.0), 1.0);\n"
1208			<< "    else\n"
1209			<< "        o_color = vec4(vec3(0.75), 1.0);\n"
1210			<< "}\n";
1211
1212		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1213	}
1214}
1215
1216//! Generate vertex positions for a grid of tiles composed of two triangles each (6 vertices)
1217void generateGrid (void* pRawData, const float step, const float ox, const float oy, const deUint32 numX, const deUint32 numY, const float z = 0.0f)
1218{
1219	typedef Vec4 (*TilePtr)[6];
1220
1221	TilePtr const pData = static_cast<TilePtr>(pRawData);
1222	{
1223		for (deUint32 iy = 0; iy < numY; ++iy)
1224		for (deUint32 ix = 0; ix < numX; ++ix)
1225		{
1226			const deUint32	ndx	= ix + numX * iy;
1227			const float		x	= ox + step * static_cast<float>(ix);
1228			const float		y	= oy + step * static_cast<float>(iy);
1229
1230			pData[ndx][0] = Vec4(x + step,	y,			z, 1.0f);
1231			pData[ndx][1] = Vec4(x,			y,			z, 1.0f);
1232			pData[ndx][2] = Vec4(x,			y + step,	z, 1.0f);
1233
1234			pData[ndx][3] = Vec4(x,			y + step,	z, 1.0f);
1235			pData[ndx][4] = Vec4(x + step,	y + step,	z, 1.0f);
1236			pData[ndx][5] = Vec4(x + step,	y,			z, 1.0f);
1237		}
1238	}
1239}
1240
1241//! Base test for a sparse buffer backing a vertex/index buffer
1242class DrawGridTestInstance : public SparseBufferTestInstance
1243{
1244public:
1245	DrawGridTestInstance (Context& context, const TestFlags flags, const VkBufferUsageFlags usage, const VkDeviceSize minChunkSize)
1246		: SparseBufferTestInstance	(context, flags)
1247	{
1248		const DeviceInterface&	vk							= getDeviceInterface();
1249		VkBufferCreateInfo		referenceBufferCreateInfo	= getSparseBufferCreateInfo(usage);
1250
1251		{
1252			// Allocate two chunks, each covering half of the viewport
1253			SparseAllocationBuilder builder;
1254			builder.addMemoryBind();
1255
1256			if (m_residency)
1257				builder.addResourceHole();
1258
1259			builder
1260				.addMemoryAllocation()
1261				.addMemoryHole()
1262				.addMemoryBind();
1263
1264			if (m_aliased)
1265				builder.addAliasedMemoryBind(0u, 0u);
1266
1267			m_sparseAllocation	= builder.build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize);
1268		}
1269
1270		// Create the buffer
1271		referenceBufferCreateInfo.size	= m_sparseAllocation->resourceSize;
1272		m_sparseBuffer					= makeBuffer(vk, getDevice(), referenceBufferCreateInfo);
1273
1274
1275		m_perDrawBufferOffset	= m_sparseAllocation->resourceSize / m_sparseAllocation->numResourceChunks;
1276		m_stagingBufferSize		= 2 * m_perDrawBufferOffset;
1277		m_stagingBuffer			= makeBuffer(vk, getDevice(), makeBufferCreateInfo(m_stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT));
1278		m_stagingBufferAlloc	= bindBuffer(vk, getDevice(), getAllocator(), *m_stagingBuffer, MemoryRequirement::HostVisible);
1279
1280
1281	}
1282
1283	tcu::TestStatus iterate (void)
1284	{
1285		const DeviceInterface&	vk	= getDeviceInterface();
1286
1287		for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++)
1288		{
1289			const deUint32	firstDeviceID	= physDevID;
1290			const deUint32	secondDeviceID	= (firstDeviceID + 1) % m_numPhysicalDevices;
1291
1292			// Bind the memory
1293			bindSparseBuffer(vk, getDevice(), m_sparseQueue.queueHandle, *m_sparseBuffer, *m_sparseAllocation, usingDeviceGroups(), firstDeviceID, secondDeviceID);
1294
1295			initializeBuffers();
1296
1297			// Upload to the sparse buffer
1298			{
1299				flushMappedMemoryRange(vk, getDevice(), m_stagingBufferAlloc->getMemory(), m_stagingBufferAlloc->getOffset(), m_stagingBufferSize);
1300
1301				VkDeviceSize	firstChunkOffset	= 0ull;
1302				VkDeviceSize	secondChunkOffset	= m_perDrawBufferOffset;
1303
1304				if (m_residency)
1305					secondChunkOffset += m_perDrawBufferOffset;
1306
1307				if (m_aliased)
1308					firstChunkOffset = secondChunkOffset + m_perDrawBufferOffset;
1309
1310				const VkBufferCopy copyRegions[] =
1311				{
1312					{
1313						0ull,						// VkDeviceSize    srcOffset;
1314						firstChunkOffset,			// VkDeviceSize    dstOffset;
1315						m_perDrawBufferOffset,		// VkDeviceSize    size;
1316					},
1317					{
1318						m_perDrawBufferOffset,		// VkDeviceSize    srcOffset;
1319						secondChunkOffset,			// VkDeviceSize    dstOffset;
1320						m_perDrawBufferOffset,		// VkDeviceSize    size;
1321					},
1322				};
1323
1324				const Unique<VkCommandPool>		cmdPool		(makeCommandPool(vk, getDevice(), m_universalQueue.queueFamilyIndex));
1325				const Unique<VkCommandBuffer>	cmdBuffer	(allocateCommandBuffer(vk, getDevice(), *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1326
1327				beginCommandBuffer	(vk, *cmdBuffer);
1328				vk.cmdCopyBuffer	(*cmdBuffer, *m_stagingBuffer, *m_sparseBuffer, DE_LENGTH_OF_ARRAY(copyRegions), copyRegions);
1329				endCommandBuffer	(vk, *cmdBuffer);
1330
1331				submitCommandsAndWait(vk, getDevice(), m_universalQueue.queueHandle, *cmdBuffer, 0u, DE_NULL, DE_NULL, 0, DE_NULL, usingDeviceGroups(), firstDeviceID);
1332			}
1333
1334
1335			Renderer::SpecializationMap	specMap;
1336			draw(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, DE_NULL, specMap, usingDeviceGroups(), firstDeviceID);
1337
1338			if(!isResultImageCorrect())
1339				return tcu::TestStatus::fail("Some buffer values were incorrect");
1340		}
1341		return tcu::TestStatus::pass("Pass");
1342	}
1343
1344protected:
1345	virtual void				initializeBuffers		(void) = 0;
1346
1347	VkDeviceSize				m_perDrawBufferOffset;
1348
1349	VkDeviceSize				m_stagingBufferSize;
1350	Move<VkBuffer>				m_stagingBuffer;
1351	MovePtr<Allocation>			m_stagingBufferAlloc;
1352
1353	MovePtr<SparseAllocation>	m_sparseAllocation;
1354	Move<VkBuffer>				m_sparseBuffer;
1355};
1356
1357//! Sparse buffer backing a vertex input buffer
1358class VertexBufferTestInstance : public DrawGridTestInstance
1359{
1360public:
1361	VertexBufferTestInstance (Context& context, const TestFlags flags)
1362		: DrawGridTestInstance	(context,
1363								 flags,
1364								 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1365								 GRID_SIZE * GRID_SIZE * 6 * sizeof(Vec4))
1366	{
1367	}
1368
1369	void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const
1370	{
1371		DE_UNREF(pipelineLayout);
1372
1373		m_context.getTestContext().getLog()
1374			<< tcu::TestLog::Message << "Drawing a grid of triangles backed by a sparse vertex buffer. There should be no red pixels visible." << tcu::TestLog::EndMessage;
1375
1376		const DeviceInterface&	vk				= getDeviceInterface();
1377		const deUint32			vertexCount		= 6 * (GRID_SIZE * GRID_SIZE) / 2;
1378		VkDeviceSize			vertexOffset	= 0ull;
1379
1380		vk.cmdBindVertexBuffers	(cmdBuffer, 0u, 1u, &m_sparseBuffer.get(), &vertexOffset);
1381		vk.cmdDraw				(cmdBuffer, vertexCount, 1u, 0u, 0u);
1382
1383		vertexOffset += m_perDrawBufferOffset * (m_residency ? 2 : 1);
1384
1385		vk.cmdBindVertexBuffers	(cmdBuffer, 0u, 1u, &m_sparseBuffer.get(), &vertexOffset);
1386		vk.cmdDraw				(cmdBuffer, vertexCount, 1u, 0u, 0u);
1387	}
1388
1389	void initializeBuffers (void)
1390	{
1391		deUint8*	pData	= static_cast<deUint8*>(m_stagingBufferAlloc->getHostPtr());
1392		const float	step	= 2.0f / static_cast<float>(GRID_SIZE);
1393
1394		// Prepare data for two draw calls
1395		generateGrid(pData,							step, -1.0f, -1.0f, GRID_SIZE, GRID_SIZE/2);
1396		generateGrid(pData + m_perDrawBufferOffset,	step, -1.0f,  0.0f, GRID_SIZE, GRID_SIZE/2);
1397	}
1398};
1399
1400//! Sparse buffer backing an index buffer
1401class IndexBufferTestInstance : public DrawGridTestInstance
1402{
1403public:
1404	IndexBufferTestInstance (Context& context, const TestFlags flags)
1405		: DrawGridTestInstance	(context,
1406								 flags,
1407								 VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
1408								 GRID_SIZE * GRID_SIZE * 6 * sizeof(deUint32))
1409		, m_halfVertexCount		(6 * (GRID_SIZE * GRID_SIZE) / 2)
1410	{
1411	}
1412
1413	void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const
1414	{
1415		DE_UNREF(pipelineLayout);
1416
1417		m_context.getTestContext().getLog()
1418			<< tcu::TestLog::Message << "Drawing a grid of triangles from a sparse index buffer. There should be no red pixels visible." << tcu::TestLog::EndMessage;
1419
1420		const DeviceInterface&	vk				= getDeviceInterface();
1421		const VkDeviceSize		vertexOffset	= 0ull;
1422		VkDeviceSize			indexOffset		= 0ull;
1423
1424		vk.cmdBindVertexBuffers	(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexOffset);
1425
1426		vk.cmdBindIndexBuffer	(cmdBuffer, *m_sparseBuffer, indexOffset, VK_INDEX_TYPE_UINT32);
1427		vk.cmdDrawIndexed		(cmdBuffer, m_halfVertexCount, 1u, 0u, 0, 0u);
1428
1429		indexOffset += m_perDrawBufferOffset * (m_residency ? 2 : 1);
1430
1431		vk.cmdBindIndexBuffer	(cmdBuffer, *m_sparseBuffer, indexOffset, VK_INDEX_TYPE_UINT32);
1432		vk.cmdDrawIndexed		(cmdBuffer, m_halfVertexCount, 1u, 0u, 0, 0u);
1433	}
1434
1435	void initializeBuffers (void)
1436	{
1437		// Vertex buffer
1438		const DeviceInterface&	vk					= getDeviceInterface();
1439		const VkDeviceSize		vertexBufferSize	= 2 * m_halfVertexCount * sizeof(Vec4);
1440								m_vertexBuffer		= makeBuffer(vk, getDevice(), makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1441								m_vertexBufferAlloc	= bindBuffer(vk, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible);
1442
1443		{
1444			const float	step = 2.0f / static_cast<float>(GRID_SIZE);
1445
1446			generateGrid(m_vertexBufferAlloc->getHostPtr(), step, -1.0f, -1.0f, GRID_SIZE, GRID_SIZE);
1447
1448			flushMappedMemoryRange(vk, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferSize);
1449		}
1450
1451		// Sparse index buffer
1452		for (deUint32 chunkNdx = 0u; chunkNdx < 2; ++chunkNdx)
1453		{
1454			deUint8* const	pData		= static_cast<deUint8*>(m_stagingBufferAlloc->getHostPtr()) + chunkNdx * m_perDrawBufferOffset;
1455			deUint32* const	pIndexData	= reinterpret_cast<deUint32*>(pData);
1456			const deUint32	ndxBase		= chunkNdx * m_halfVertexCount;
1457
1458			for (deUint32 i = 0u; i < m_halfVertexCount; ++i)
1459				pIndexData[i] = ndxBase + i;
1460		}
1461	}
1462
1463private:
1464	const deUint32			m_halfVertexCount;
1465	Move<VkBuffer>			m_vertexBuffer;
1466	MovePtr<Allocation>		m_vertexBufferAlloc;
1467};
1468
1469//! Draw from a sparse indirect buffer
1470class IndirectBufferTestInstance : public DrawGridTestInstance
1471{
1472public:
1473	IndirectBufferTestInstance (Context& context, const TestFlags flags)
1474		: DrawGridTestInstance	(context,
1475								 flags,
1476								 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
1477								 sizeof(VkDrawIndirectCommand))
1478	{
1479	}
1480
1481	void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const
1482	{
1483		DE_UNREF(pipelineLayout);
1484
1485		m_context.getTestContext().getLog()
1486			<< tcu::TestLog::Message << "Drawing two triangles covering the whole viewport. There should be no red pixels visible." << tcu::TestLog::EndMessage;
1487
1488		const DeviceInterface&	vk				= getDeviceInterface();
1489		const VkDeviceSize		vertexOffset	= 0ull;
1490		VkDeviceSize			indirectOffset	= 0ull;
1491
1492		vk.cmdBindVertexBuffers	(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexOffset);
1493		vk.cmdDrawIndirect		(cmdBuffer, *m_sparseBuffer, indirectOffset, 1u, 0u);
1494
1495		indirectOffset += m_perDrawBufferOffset * (m_residency ? 2 : 1);
1496
1497		vk.cmdDrawIndirect		(cmdBuffer, *m_sparseBuffer, indirectOffset, 1u, 0u);
1498	}
1499
1500	void initializeBuffers (void)
1501	{
1502		// Vertex buffer
1503		const DeviceInterface&	vk					= getDeviceInterface();
1504		const VkDeviceSize		vertexBufferSize	= 2 * 3 * sizeof(Vec4);
1505								m_vertexBuffer		= makeBuffer(vk, getDevice(), makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1506								m_vertexBufferAlloc	= bindBuffer(vk, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible);
1507
1508		{
1509			generateGrid(m_vertexBufferAlloc->getHostPtr(), 2.0f, -1.0f, -1.0f, 1, 1);
1510			flushMappedMemoryRange(vk, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferSize);
1511		}
1512
1513		// Indirect buffer
1514		for (deUint32 chunkNdx = 0u; chunkNdx < 2; ++chunkNdx)
1515		{
1516			deUint8* const					pData		= static_cast<deUint8*>(m_stagingBufferAlloc->getHostPtr()) + chunkNdx * m_perDrawBufferOffset;
1517			VkDrawIndirectCommand* const	pCmdData	= reinterpret_cast<VkDrawIndirectCommand*>(pData);
1518
1519			pCmdData->firstVertex	= 3u * chunkNdx;
1520			pCmdData->firstInstance	= 0u;
1521			pCmdData->vertexCount	= 3u;
1522			pCmdData->instanceCount	= 1u;
1523		}
1524	}
1525
1526private:
1527	Move<VkBuffer>			m_vertexBuffer;
1528	MovePtr<Allocation>		m_vertexBufferAlloc;
1529};
1530
1531//! Similar to the class in vktTestCaseUtil.hpp, but uses Arg0 directly rather than through a InstanceFunction1
1532template<typename Arg0>
1533class FunctionProgramsSimple1
1534{
1535public:
1536	typedef void	(*Function)				(vk::SourceCollections& dst, Arg0 arg0);
1537					FunctionProgramsSimple1	(Function func) : m_func(func)							{}
1538	void			init					(vk::SourceCollections& dst, const Arg0& arg0) const	{ m_func(dst, arg0); }
1539
1540private:
1541	const Function	m_func;
1542};
1543
1544//! Convenience function to create a TestCase based on a freestanding initPrograms and a TestInstance implementation
1545template<typename TestInstanceT, typename Arg0>
1546TestCase* createTestInstanceWithPrograms (tcu::TestContext&									testCtx,
1547										  const std::string&								name,
1548										  const std::string&								desc,
1549										  typename FunctionProgramsSimple1<Arg0>::Function	initPrograms,
1550										  Arg0												arg0)
1551{
1552	return new InstanceFactory1<TestInstanceT, Arg0, FunctionProgramsSimple1<Arg0> >(
1553		testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc, FunctionProgramsSimple1<Arg0>(initPrograms), arg0);
1554}
1555
1556void populateTestGroup (tcu::TestCaseGroup* parentGroup)
1557{
1558	const struct
1559	{
1560		std::string		name;
1561		TestFlags		flags;
1562	} groups[] =
1563	{
1564		{ "sparse_binding",										0u,													},
1565		{ "sparse_binding_aliased",								TEST_FLAG_ALIASED,									},
1566		{ "sparse_residency",									TEST_FLAG_RESIDENCY,								},
1567		{ "sparse_residency_aliased",							TEST_FLAG_RESIDENCY | TEST_FLAG_ALIASED,			},
1568		{ "sparse_residency_non_resident_strict",				TEST_FLAG_RESIDENCY | TEST_FLAG_NON_RESIDENT_STRICT,},
1569	};
1570
1571	const int numGroupsIncludingNonResidentStrict	= DE_LENGTH_OF_ARRAY(groups);
1572	const int numGroupsDefaultList					= numGroupsIncludingNonResidentStrict - 1;
1573	std::string devGroupPrefix						= "device_group_";
1574
1575	// Transfer
1576	{
1577		MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "transfer", ""));
1578		{
1579			MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(parentGroup->getTestContext(), "sparse_binding", ""));
1580			addBufferSparseBindingTests(subGroup.get(), false);
1581			group->addChild(subGroup.release());
1582
1583			MovePtr<tcu::TestCaseGroup> subGroupDeviceGroups(new tcu::TestCaseGroup(parentGroup->getTestContext(), "device_group_sparse_binding", ""));
1584			addBufferSparseBindingTests(subGroupDeviceGroups.get(), true);
1585			group->addChild(subGroupDeviceGroups.release());
1586		}
1587		parentGroup->addChild(group.release());
1588	}
1589
1590	// SSBO
1591	{
1592		MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "ssbo", ""));
1593		{
1594			MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(parentGroup->getTestContext(), "sparse_binding_aliased", ""));
1595			addBufferSparseMemoryAliasingTests(subGroup.get(), false);
1596			group->addChild(subGroup.release());
1597
1598			MovePtr<tcu::TestCaseGroup> subGroupDeviceGroups(new tcu::TestCaseGroup(parentGroup->getTestContext(), "device_group_sparse_binding_aliased", ""));
1599			addBufferSparseMemoryAliasingTests(subGroupDeviceGroups.get(), true);
1600			group->addChild(subGroupDeviceGroups.release());
1601		}
1602		{
1603			MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(parentGroup->getTestContext(), "sparse_residency", ""));
1604			addBufferSparseResidencyTests(subGroup.get(), false);
1605			group->addChild(subGroup.release());
1606
1607			MovePtr<tcu::TestCaseGroup> subGroupDeviceGroups(new tcu::TestCaseGroup(parentGroup->getTestContext(), "device_group_sparse_residency", ""));
1608			addBufferSparseResidencyTests(subGroupDeviceGroups.get(), true);
1609			group->addChild(subGroupDeviceGroups.release());
1610		}
1611		parentGroup->addChild(group.release());
1612	}
1613
1614	// UBO
1615	{
1616		MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "ubo", ""));
1617
1618		for (int groupNdx = 0u; groupNdx < numGroupsIncludingNonResidentStrict; ++groupNdx)
1619		{
1620			group->addChild(createTestInstanceWithPrograms<UBOTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawWithUBO, groups[groupNdx].flags));
1621		}
1622		for (int groupNdx = 0u; groupNdx < numGroupsIncludingNonResidentStrict; ++groupNdx)
1623		{
1624			group->addChild(createTestInstanceWithPrograms<UBOTestInstance>(group->getTestContext(), (devGroupPrefix + groups[groupNdx].name).c_str(), "", initProgramsDrawWithUBO, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS));
1625		}
1626		parentGroup->addChild(group.release());
1627	}
1628
1629	// Vertex buffer
1630	{
1631		MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "vertex_buffer", ""));
1632
1633		for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx)
1634		{
1635			group->addChild(createTestInstanceWithPrograms<VertexBufferTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags));
1636		}
1637		for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx)
1638		{
1639			group->addChild(createTestInstanceWithPrograms<VertexBufferTestInstance>(group->getTestContext(), (devGroupPrefix + groups[groupNdx].name).c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS));
1640		}
1641
1642		parentGroup->addChild(group.release());
1643	}
1644
1645	// Index buffer
1646	{
1647		MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "index_buffer", ""));
1648
1649		for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx)
1650		{
1651			group->addChild(createTestInstanceWithPrograms<IndexBufferTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags));
1652		}
1653		for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx)
1654		{
1655			group->addChild(createTestInstanceWithPrograms<IndexBufferTestInstance>(group->getTestContext(), (devGroupPrefix + groups[groupNdx].name).c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS));
1656		}
1657
1658		parentGroup->addChild(group.release());
1659	}
1660
1661	// Indirect buffer
1662	{
1663		MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "indirect_buffer", ""));
1664
1665		for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx)
1666		{
1667			group->addChild(createTestInstanceWithPrograms<IndirectBufferTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags));
1668		}
1669		for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx)
1670		{
1671			group->addChild(createTestInstanceWithPrograms<IndirectBufferTestInstance>(group->getTestContext(), (devGroupPrefix +  groups[groupNdx].name).c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS));
1672		}
1673
1674		parentGroup->addChild(group.release());
1675	}
1676}
1677
1678} // anonymous ns
1679
1680tcu::TestCaseGroup* createSparseBufferTests (tcu::TestContext& testCtx)
1681{
1682	return createTestGroup(testCtx, "buffer", "Sparse buffer usage tests", populateTestGroup);
1683}
1684
1685} // sparse
1686} // vkt
1687