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