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  vktSparseResourcesShaderIntrinsicsStorage.cpp
     21  * \brief Sparse Resources Shader Intrinsics for storage images
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vktSparseResourcesShaderIntrinsicsStorage.hpp"
     25 
     26 using namespace vk;
     27 
     28 namespace vkt
     29 {
     30 namespace sparse
     31 {
     32 
     33 tcu::UVec3 computeWorkGroupSize (const tcu::UVec3& gridSize)
     34 {
     35 	const deUint32		maxComputeWorkGroupInvocations	= 128u;
     36 	const tcu::UVec3	maxComputeWorkGroupSize			= tcu::UVec3(128u, 128u, 64u);
     37 
     38 	const deUint32 xWorkGroupSize = std::min(std::min(gridSize.x(), maxComputeWorkGroupSize.x()), maxComputeWorkGroupInvocations);
     39 	const deUint32 yWorkGroupSize = std::min(std::min(gridSize.y(), maxComputeWorkGroupSize.y()), maxComputeWorkGroupInvocations / xWorkGroupSize);
     40 	const deUint32 zWorkGroupSize = std::min(std::min(gridSize.z(), maxComputeWorkGroupSize.z()), maxComputeWorkGroupInvocations / (xWorkGroupSize*yWorkGroupSize));
     41 
     42 	return tcu::UVec3(xWorkGroupSize, yWorkGroupSize, zWorkGroupSize);
     43 }
     44 
     45 void SparseShaderIntrinsicsCaseStorage::initPrograms (vk::SourceCollections& programCollection) const
     46 {
     47 	const std::string	imageTypeStr	= getShaderImageType(m_format, m_imageType);
     48 	const std::string	formatDataStr	= getShaderImageDataType(m_format);
     49 	const std::string	formatQualStr	= getShaderImageFormatQualifier(m_format);
     50 
     51 	const std::string  coordString		= getShaderImageCoordinates(m_imageType,
     52 																	"%local_int_GlobalInvocationID_x",
     53 																	"%local_ivec2_GlobalInvocationID_xy",
     54 																	"%local_ivec3_GlobalInvocationID_xyz");
     55 	// Create compute program
     56 	std::ostringstream	src;
     57 
     58 	const std::string	typeImgComp					= getImageComponentTypeName(m_format);
     59 	const std::string	typeImgCompVec4				= getImageComponentVec4TypeName(m_format);
     60 	const std::string	typeImageSparse				= getSparseImageTypeName();
     61 	const std::string	typeUniformConstImageSparse	= getUniformConstSparseImageTypeName();
     62 
     63 	src << "OpCapability Shader\n"
     64 		<< "OpCapability ImageCubeArray\n"
     65 		<< "OpCapability SparseResidency\n"
     66 		<< "OpCapability StorageImageExtendedFormats\n"
     67 
     68 		<< "%ext_import = OpExtInstImport \"GLSL.std.450\"\n"
     69 		<< "OpMemoryModel Logical GLSL450\n"
     70 		<< "OpEntryPoint GLCompute %func_main \"main\" %input_GlobalInvocationID\n"
     71 		<< "OpExecutionMode %func_main LocalSize 1 1 1\n"
     72 		<< "OpSource GLSL 440\n"
     73 
     74 		<< "OpName %func_main \"main\"\n"
     75 
     76 		<< "OpName %input_GlobalInvocationID \"gl_GlobalInvocationID\"\n"
     77 		<< "OpName %input_WorkGroupSize \"gl_WorkGroupSize\"\n"
     78 
     79 		<< "OpName %uniform_image_sparse \"u_imageSparse\"\n"
     80 		<< "OpName %uniform_image_texels \"u_imageTexels\"\n"
     81 		<< "OpName %uniform_image_residency \"u_imageResidency\"\n"
     82 
     83 		<< "OpDecorate %input_GlobalInvocationID BuiltIn GlobalInvocationId\n"
     84 
     85 		<< "OpDecorate %input_WorkGroupSize BuiltIn WorkgroupSize\n"
     86 
     87 		<< "OpDecorate %constant_uint_grid_x SpecId 1\n"
     88 		<< "OpDecorate %constant_uint_grid_y SpecId 2\n"
     89 		<< "OpDecorate %constant_uint_grid_z SpecId 3\n"
     90 
     91 		<< "OpDecorate %constant_uint_work_group_size_x SpecId 4\n"
     92 		<< "OpDecorate %constant_uint_work_group_size_y SpecId 5\n"
     93 		<< "OpDecorate %constant_uint_work_group_size_z SpecId 6\n"
     94 
     95 		<< "OpDecorate %uniform_image_sparse DescriptorSet 0\n"
     96 		<< "OpDecorate %uniform_image_sparse Binding " << BINDING_IMAGE_SPARSE << "\n"
     97 
     98 		<< "OpDecorate %uniform_image_texels DescriptorSet 0\n"
     99 		<< "OpDecorate %uniform_image_texels Binding " << BINDING_IMAGE_TEXELS << "\n"
    100 		<< "OpDecorate %uniform_image_texels NonReadable\n"
    101 
    102 		<< "OpDecorate %uniform_image_residency DescriptorSet 0\n"
    103 		<< "OpDecorate %uniform_image_residency Binding " << BINDING_IMAGE_RESIDENCY << "\n"
    104 		<< "OpDecorate %uniform_image_residency NonReadable\n"
    105 
    106 		// Declare data types
    107 		<< "%type_bool						= OpTypeBool\n"
    108 		<< "%type_int						= OpTypeInt 32 1\n"
    109 		<< "%type_uint						= OpTypeInt 32 0\n"
    110 		<< "%type_ivec2						= OpTypeVector %type_int  2\n"
    111 		<< "%type_ivec3						= OpTypeVector %type_int  3\n"
    112 		<< "%type_ivec4						= OpTypeVector %type_int  4\n"
    113 		<< "%type_uvec3						= OpTypeVector %type_uint 3\n"
    114 		<< "%type_uvec4						= OpTypeVector %type_uint 4\n"
    115 		<< "%type_struct_int_img_comp_vec4	= OpTypeStruct %type_int " << typeImgCompVec4 << "\n"
    116 
    117 		<< "%type_input_uint		= OpTypePointer Input %type_uint\n"
    118 		<< "%type_input_uvec3		= OpTypePointer Input %type_uvec3\n"
    119 
    120 		<< "%type_function_int			 = OpTypePointer Function %type_int\n"
    121 		<< "%type_function_img_comp_vec4 = OpTypePointer Function " << typeImgCompVec4 << "\n"
    122 
    123 		<< "%type_void				= OpTypeVoid\n"
    124 		<< "%type_void_func			= OpTypeFunction %type_void\n"
    125 
    126 		// Sparse image without sampler type declaration
    127 		<< "%type_image_sparse = " << getOpTypeImageSparse(m_imageType, m_format, typeImgComp, false) << "\n"
    128 		<< "%type_uniformconst_image_sparse = OpTypePointer UniformConstant %type_image_sparse\n"
    129 
    130 		// Sparse image with sampler type declaration
    131 		<< "%type_image_sparse_with_sampler = " << getOpTypeImageSparse(m_imageType, m_format, typeImgComp, true) << "\n"
    132 		<< "%type_uniformconst_image_sparse_with_sampler = OpTypePointer UniformConstant %type_image_sparse_with_sampler\n"
    133 
    134 		// Residency image type declaration
    135 		<< "%type_image_residency				= " << getOpTypeImageResidency(m_imageType) << "\n"
    136 		<< "%type_uniformconst_image_residency	= OpTypePointer UniformConstant %type_image_residency\n"
    137 
    138 		// Declare sparse image variable
    139 		<< "%uniform_image_sparse = OpVariable " << typeUniformConstImageSparse << " UniformConstant\n"
    140 
    141 		// Declare output image variable for storing texels
    142 		<< "%uniform_image_texels = OpVariable %type_uniformconst_image_sparse UniformConstant\n"
    143 
    144 		// Declare output image variable for storing residency information
    145 		<< "%uniform_image_residency = OpVariable %type_uniformconst_image_residency UniformConstant\n"
    146 
    147 		// Declare input variables
    148 		<< "%input_GlobalInvocationID = OpVariable %type_input_uvec3 Input\n"
    149 
    150 		<< "%constant_uint_grid_x				= OpSpecConstant %type_uint 1\n"
    151 		<< "%constant_uint_grid_y				= OpSpecConstant %type_uint 1\n"
    152 		<< "%constant_uint_grid_z				= OpSpecConstant %type_uint 1\n"
    153 
    154 		<< "%constant_uint_work_group_size_x	= OpSpecConstant %type_uint 1\n"
    155 		<< "%constant_uint_work_group_size_y	= OpSpecConstant %type_uint 1\n"
    156 		<< "%constant_uint_work_group_size_z	= OpSpecConstant %type_uint 1\n"
    157 		<< "%input_WorkGroupSize = OpSpecConstantComposite %type_uvec3 %constant_uint_work_group_size_x %constant_uint_work_group_size_y %constant_uint_work_group_size_z\n"
    158 
    159 		// Declare constants
    160 		<< "%constant_uint_0				= OpConstant %type_uint 0\n"
    161 		<< "%constant_uint_1				= OpConstant %type_uint 1\n"
    162 		<< "%constant_uint_2				= OpConstant %type_uint 2\n"
    163 		<< "%constant_int_0					= OpConstant %type_int 0\n"
    164 		<< "%constant_int_1					= OpConstant %type_int 1\n"
    165 		<< "%constant_int_2					= OpConstant %type_int 2\n"
    166 		<< "%constant_bool_true				= OpConstantTrue %type_bool\n"
    167 		<< "%constant_uint_resident			= OpConstant %type_uint " << MEMORY_BLOCK_BOUND_VALUE << "\n"
    168 		<< "%constant_uvec4_resident		= OpConstantComposite %type_uvec4 %constant_uint_resident %constant_uint_resident %constant_uint_resident %constant_uint_resident\n"
    169 		<< "%constant_uint_not_resident		= OpConstant %type_uint " << MEMORY_BLOCK_NOT_BOUND_VALUE << "\n"
    170 		<< "%constant_uvec4_not_resident	= OpConstantComposite %type_uvec4 %constant_uint_not_resident %constant_uint_not_resident %constant_uint_not_resident %constant_uint_not_resident\n"
    171 
    172 		// Call main function
    173 		<< "%func_main		 = OpFunction %type_void None %type_void_func\n"
    174 		<< "%label_func_main = OpLabel\n"
    175 
    176 		// Load GlobalInvocationID.xyz into local variables
    177 		<< "%access_GlobalInvocationID_x		= OpAccessChain %type_input_uint %input_GlobalInvocationID %constant_uint_0\n"
    178 		<< "%local_uint_GlobalInvocationID_x	= OpLoad %type_uint %access_GlobalInvocationID_x\n"
    179 		<< "%local_int_GlobalInvocationID_x		= OpBitcast %type_int %local_uint_GlobalInvocationID_x\n"
    180 
    181 		<< "%access_GlobalInvocationID_y		= OpAccessChain %type_input_uint %input_GlobalInvocationID %constant_uint_1\n"
    182 		<< "%local_uint_GlobalInvocationID_y	= OpLoad %type_uint %access_GlobalInvocationID_y\n"
    183 		<< "%local_int_GlobalInvocationID_y		= OpBitcast %type_int %local_uint_GlobalInvocationID_y\n"
    184 
    185 		<< "%access_GlobalInvocationID_z		= OpAccessChain %type_input_uint %input_GlobalInvocationID %constant_uint_2\n"
    186 		<< "%local_uint_GlobalInvocationID_z	= OpLoad %type_uint %access_GlobalInvocationID_z\n"
    187 		<< "%local_int_GlobalInvocationID_z		= OpBitcast %type_int %local_uint_GlobalInvocationID_z\n"
    188 
    189 		<< "%local_ivec2_GlobalInvocationID_xy	= OpCompositeConstruct %type_ivec2 %local_int_GlobalInvocationID_x %local_int_GlobalInvocationID_y\n"
    190 		<< "%local_ivec3_GlobalInvocationID_xyz = OpCompositeConstruct %type_ivec3 %local_int_GlobalInvocationID_x %local_int_GlobalInvocationID_y %local_int_GlobalInvocationID_z\n"
    191 
    192 		<< "%comparison_range_x = OpULessThan %type_bool %local_uint_GlobalInvocationID_x %constant_uint_grid_x\n"
    193 		<< "OpSelectionMerge %label_out_range_x None\n"
    194 		<< "OpBranchConditional %comparison_range_x %label_in_range_x %label_out_range_x\n"
    195 		<< "%label_in_range_x = OpLabel\n"
    196 
    197 		<< "%comparison_range_y = OpULessThan %type_bool %local_uint_GlobalInvocationID_y %constant_uint_grid_y\n"
    198 		<< "OpSelectionMerge %label_out_range_y None\n"
    199 		<< "OpBranchConditional %comparison_range_y %label_in_range_y %label_out_range_y\n"
    200 		<< "%label_in_range_y = OpLabel\n"
    201 
    202 		<< "%comparison_range_z = OpULessThan %type_bool %local_uint_GlobalInvocationID_z %constant_uint_grid_z\n"
    203 		<< "OpSelectionMerge %label_out_range_z None\n"
    204 		<< "OpBranchConditional %comparison_range_z %label_in_range_z %label_out_range_z\n"
    205 		<< "%label_in_range_z = OpLabel\n"
    206 
    207 		// Load sparse image
    208 		<< "%local_image_sparse = OpLoad " << typeImageSparse << " %uniform_image_sparse\n"
    209 
    210 		// Call OpImageSparse*
    211 		<< sparseImageOpString("%local_sparse_op_result", "%type_struct_int_img_comp_vec4", "%local_image_sparse", coordString, "%constant_int_0") << "\n"
    212 
    213 		// Load the texel from the sparse image to local variable for OpImageSparse*
    214 		<< "%local_img_comp_vec4 = OpCompositeExtract " << typeImgCompVec4 << " %local_sparse_op_result 1\n"
    215 
    216 		// Load residency code for OpImageSparse*
    217 		<< "%local_residency_code = OpCompositeExtract %type_int %local_sparse_op_result 0\n"
    218 		// End Call OpImageSparse*
    219 
    220 		// Load texels image
    221 		<< "%local_image_texels = OpLoad %type_image_sparse %uniform_image_texels\n"
    222 
    223 		// Write the texel to output image via OpImageWrite
    224 		<< "OpImageWrite %local_image_texels " << coordString << " %local_img_comp_vec4\n"
    225 
    226 		// Load residency info image
    227 		<< "%local_image_residency	= OpLoad %type_image_residency %uniform_image_residency\n"
    228 
    229 		// Check if loaded texel is placed in resident memory
    230 		<< "%local_texel_resident = OpImageSparseTexelsResident %type_bool %local_residency_code\n"
    231 		<< "OpSelectionMerge %branch_texel_resident None\n"
    232 		<< "OpBranchConditional %local_texel_resident %label_texel_resident %label_texel_not_resident\n"
    233 		<< "%label_texel_resident = OpLabel\n"
    234 
    235 		// Loaded texel is in resident memory
    236 		<< "OpImageWrite %local_image_residency " << coordString << " %constant_uvec4_resident\n"
    237 
    238 		<< "OpBranch %branch_texel_resident\n"
    239 		<< "%label_texel_not_resident = OpLabel\n"
    240 
    241 		// Loaded texel is not in resident memory
    242 		<< "OpImageWrite %local_image_residency " << coordString << " %constant_uvec4_not_resident\n"
    243 
    244 		<< "OpBranch %branch_texel_resident\n"
    245 		<< "%branch_texel_resident = OpLabel\n"
    246 
    247 		<< "OpBranch %label_out_range_z\n"
    248 		<< "%label_out_range_z = OpLabel\n"
    249 
    250 		<< "OpBranch %label_out_range_y\n"
    251 		<< "%label_out_range_y = OpLabel\n"
    252 
    253 		<< "OpBranch %label_out_range_x\n"
    254 		<< "%label_out_range_x = OpLabel\n"
    255 
    256 		<< "OpReturn\n"
    257 		<< "OpFunctionEnd\n";
    258 
    259 	programCollection.spirvAsmSources.add("compute") << src.str();
    260 }
    261 
    262 std::string	SparseCaseOpImageSparseFetch::getSparseImageTypeName (void) const
    263 {
    264 	return "%type_image_sparse_with_sampler";
    265 }
    266 
    267 std::string	SparseCaseOpImageSparseFetch::getUniformConstSparseImageTypeName (void) const
    268 {
    269 	return "%type_uniformconst_image_sparse_with_sampler";
    270 }
    271 
    272 std::string	SparseCaseOpImageSparseFetch::sparseImageOpString  (const std::string& resultVariable,
    273 																const std::string& resultType,
    274 																const std::string& image,
    275 																const std::string& coord,
    276 																const std::string& mipLevel) const
    277 {
    278 	std::ostringstream	src;
    279 
    280 	src << resultVariable << " = OpImageSparseFetch " << resultType << " " << image << " " << coord << " Lod " << mipLevel << "\n";
    281 
    282 	return src.str();
    283 }
    284 
    285 std::string	SparseCaseOpImageSparseRead::getSparseImageTypeName (void) const
    286 {
    287 	return "%type_image_sparse";
    288 }
    289 
    290 std::string	SparseCaseOpImageSparseRead::getUniformConstSparseImageTypeName (void) const
    291 {
    292 	return "%type_uniformconst_image_sparse";
    293 }
    294 
    295 std::string	SparseCaseOpImageSparseRead::sparseImageOpString (const std::string& resultVariable,
    296 															  const std::string& resultType,
    297 															  const std::string& image,
    298 															  const std::string& coord,
    299 															  const std::string& mipLevel) const
    300 {
    301 	DE_UNREF(mipLevel);
    302 
    303 	std::ostringstream	src;
    304 
    305 	src << resultVariable << " = OpImageSparseRead " << resultType << " " << image << " " << coord << "\n";
    306 
    307 	return src.str();
    308 }
    309 
    310 class SparseShaderIntrinsicsInstanceStorage : public SparseShaderIntrinsicsInstanceBase
    311 {
    312 public:
    313 	SparseShaderIntrinsicsInstanceStorage	(Context&					context,
    314 											 const SpirVFunction		function,
    315 											 const ImageType			imageType,
    316 											 const tcu::UVec3&			imageSize,
    317 											 const tcu::TextureFormat&	format)
    318 		: SparseShaderIntrinsicsInstanceBase(context, function, imageType, imageSize, format) {}
    319 
    320 	VkImageUsageFlags				imageOutputUsageFlags	(void) const;
    321 
    322 	VkQueueFlags					getQueueFlags			(void) const;
    323 
    324 	void							recordCommands			(const VkCommandBuffer		commandBuffer,
    325 															 const VkImageCreateInfo&	imageSparseInfo,
    326 															 const VkImage				imageSparse,
    327 															 const VkImage				imageTexels,
    328 															 const VkImage				imageResidency);
    329 
    330 	virtual VkDescriptorType		imageSparseDescType		(void) const = 0;
    331 };
    332 
    333 VkImageUsageFlags SparseShaderIntrinsicsInstanceStorage::imageOutputUsageFlags (void) const
    334 {
    335 	return VK_IMAGE_USAGE_STORAGE_BIT;
    336 }
    337 
    338 VkQueueFlags SparseShaderIntrinsicsInstanceStorage::getQueueFlags (void) const
    339 {
    340 	return VK_QUEUE_COMPUTE_BIT;
    341 }
    342 
    343 void SparseShaderIntrinsicsInstanceStorage::recordCommands (const VkCommandBuffer		commandBuffer,
    344 															const VkImageCreateInfo&	imageSparseInfo,
    345 															const VkImage				imageSparse,
    346 															const VkImage				imageTexels,
    347 															const VkImage				imageResidency)
    348 {
    349 	const InstanceInterface&	instance		= m_context.getInstanceInterface();
    350 	const DeviceInterface&		deviceInterface = getDeviceInterface();
    351 	const VkPhysicalDevice		physicalDevice	= m_context.getPhysicalDevice();
    352 
    353 	// Check if device supports image format for storage image
    354 	if (!checkImageFormatFeatureSupport(instance, physicalDevice, imageSparseInfo.format, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
    355 		TCU_THROW(NotSupportedError, "Device does not support image format for storage image");
    356 
    357 	// Make sure device supports VK_FORMAT_R32_UINT format for storage image
    358 	if (!checkImageFormatFeatureSupport(instance, physicalDevice, mapTextureFormat(m_residencyFormat), VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
    359 		TCU_THROW(TestError, "Device does not support VK_FORMAT_R32_UINT format for storage image");
    360 
    361 	pipelines.resize(imageSparseInfo.mipLevels);
    362 	descriptorSets.resize(imageSparseInfo.mipLevels);
    363 	imageSparseViews.resize(imageSparseInfo.mipLevels);
    364 	imageTexelsViews.resize(imageSparseInfo.mipLevels);
    365 	imageResidencyViews.resize(imageSparseInfo.mipLevels);
    366 
    367 	// Create descriptor set layout
    368 	DescriptorSetLayoutBuilder descriptorLayerBuilder;
    369 
    370 	descriptorLayerBuilder.addSingleBinding(imageSparseDescType(), VK_SHADER_STAGE_COMPUTE_BIT);
    371 	descriptorLayerBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT);
    372 	descriptorLayerBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT);
    373 
    374 	const Unique<VkDescriptorSetLayout> descriptorSetLayout(descriptorLayerBuilder.build(deviceInterface, getDevice()));
    375 
    376 	// Create pipeline layout
    377 	const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(deviceInterface, getDevice(), *descriptorSetLayout));
    378 
    379 	// Create descriptor pool
    380 	DescriptorPoolBuilder descriptorPoolBuilder;
    381 
    382 	descriptorPoolBuilder.addType(imageSparseDescType(), imageSparseInfo.mipLevels);
    383 	descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, imageSparseInfo.mipLevels);
    384 	descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, imageSparseInfo.mipLevels);
    385 
    386 	descriptorPool = descriptorPoolBuilder.build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, imageSparseInfo.mipLevels);
    387 
    388 	const VkImageSubresourceRange fullImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageSparseInfo.mipLevels, 0u, imageSparseInfo.arrayLayers);
    389 
    390 	{
    391 		VkImageMemoryBarrier imageShaderAccessBarriers[3];
    392 
    393 		imageShaderAccessBarriers[0] = makeImageMemoryBarrier
    394 		(
    395 			VK_ACCESS_TRANSFER_WRITE_BIT,
    396 			VK_ACCESS_SHADER_READ_BIT,
    397 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
    398 			VK_IMAGE_LAYOUT_GENERAL,
    399 			imageSparse,
    400 			fullImageSubresourceRange
    401 		);
    402 
    403 		imageShaderAccessBarriers[1] = makeImageMemoryBarrier
    404 		(
    405 			0u,
    406 			VK_ACCESS_SHADER_WRITE_BIT,
    407 			VK_IMAGE_LAYOUT_UNDEFINED,
    408 			VK_IMAGE_LAYOUT_GENERAL,
    409 			imageTexels,
    410 			fullImageSubresourceRange
    411 		);
    412 
    413 		imageShaderAccessBarriers[2] = makeImageMemoryBarrier
    414 		(
    415 			0u,
    416 			VK_ACCESS_SHADER_WRITE_BIT,
    417 			VK_IMAGE_LAYOUT_UNDEFINED,
    418 			VK_IMAGE_LAYOUT_GENERAL,
    419 			imageResidency,
    420 			fullImageSubresourceRange
    421 		);
    422 
    423 		deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 3u, imageShaderAccessBarriers);
    424 	}
    425 
    426 	const VkSpecializationMapEntry specializationMapEntries[6] =
    427 	{
    428 		{ 1u, 0u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // GridSize.x
    429 		{ 2u, 1u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // GridSize.y
    430 		{ 3u, 2u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // GridSize.z
    431 		{ 4u, 3u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // WorkGroupSize.x
    432 		{ 5u, 4u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // WorkGroupSize.y
    433 		{ 6u, 5u * (deUint32)sizeof(deUint32), sizeof(deUint32) }, // WorkGroupSize.z
    434 	};
    435 
    436 	Unique<VkShaderModule> shaderModule(createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("compute"), 0u));
    437 
    438 	for (deUint32 mipLevelNdx = 0u; mipLevelNdx < imageSparseInfo.mipLevels; ++mipLevelNdx)
    439 	{
    440 		const tcu::UVec3  gridSize				= getShaderGridSize(m_imageType, m_imageSize, mipLevelNdx);
    441 		const tcu::UVec3  workGroupSize			= computeWorkGroupSize(gridSize);
    442 		const tcu::UVec3 specializationData[2]	= { gridSize, workGroupSize };
    443 
    444 		const VkSpecializationInfo specializationInfo =
    445 		{
    446 			(deUint32)DE_LENGTH_OF_ARRAY(specializationMapEntries),	// mapEntryCount
    447 			specializationMapEntries,								// pMapEntries
    448 			sizeof(specializationData),								// dataSize
    449 			specializationData,										// pData
    450 		};
    451 
    452 		// Create and bind compute pipeline
    453 		pipelines[mipLevelNdx] = makeVkSharedPtr(makeComputePipeline(deviceInterface, getDevice(), *pipelineLayout, *shaderModule, &specializationInfo));
    454 		const VkPipeline computePipeline = **pipelines[mipLevelNdx];
    455 
    456 		deviceInterface.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline);
    457 
    458 		// Create descriptor set
    459 		descriptorSets[mipLevelNdx] = makeVkSharedPtr(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout));
    460 		const VkDescriptorSet descriptorSet = **descriptorSets[mipLevelNdx];
    461 
    462 		// Bind resources
    463 		const VkImageSubresourceRange mipLevelRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevelNdx, 1u, 0u, imageSparseInfo.arrayLayers);
    464 
    465 		imageSparseViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageSparse, mapImageViewType(m_imageType), imageSparseInfo.format, mipLevelRange));
    466 		const VkDescriptorImageInfo imageSparseDescInfo = makeDescriptorImageInfo(DE_NULL, **imageSparseViews[mipLevelNdx], VK_IMAGE_LAYOUT_GENERAL);
    467 
    468 		imageTexelsViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageTexels, mapImageViewType(m_imageType), imageSparseInfo.format, mipLevelRange));
    469 		const VkDescriptorImageInfo imageTexelsDescInfo = makeDescriptorImageInfo(DE_NULL, **imageTexelsViews[mipLevelNdx], VK_IMAGE_LAYOUT_GENERAL);
    470 
    471 		imageResidencyViews[mipLevelNdx] = makeVkSharedPtr(makeImageView(deviceInterface, getDevice(), imageResidency, mapImageViewType(m_imageType), mapTextureFormat(m_residencyFormat), mipLevelRange));
    472 		const VkDescriptorImageInfo imageResidencyDescInfo = makeDescriptorImageInfo(DE_NULL, **imageResidencyViews[mipLevelNdx], VK_IMAGE_LAYOUT_GENERAL);
    473 
    474 		DescriptorSetUpdateBuilder descriptorUpdateBuilder;
    475 		descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_SPARSE), imageSparseDescType(), &imageSparseDescInfo);
    476 		descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_TEXELS), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageTexelsDescInfo);
    477 		descriptorUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(BINDING_IMAGE_RESIDENCY), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageResidencyDescInfo);
    478 
    479 		descriptorUpdateBuilder.update(deviceInterface, getDevice());
    480 
    481 		deviceInterface.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
    482 
    483 		const deUint32		xWorkGroupCount = gridSize.x() / workGroupSize.x() + (gridSize.x() % workGroupSize.x() ? 1u : 0u);
    484 		const deUint32		yWorkGroupCount = gridSize.y() / workGroupSize.y() + (gridSize.y() % workGroupSize.y() ? 1u : 0u);
    485 		const deUint32		zWorkGroupCount = gridSize.z() / workGroupSize.z() + (gridSize.z() % workGroupSize.z() ? 1u : 0u);
    486 		const tcu::UVec3	maxWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u);
    487 
    488 		if (maxWorkGroupCount.x() < xWorkGroupCount ||
    489 			maxWorkGroupCount.y() < yWorkGroupCount ||
    490 			maxWorkGroupCount.z() < zWorkGroupCount)
    491 		{
    492 			TCU_THROW(NotSupportedError, "Image size exceeds compute invocations limit");
    493 		}
    494 
    495 		deviceInterface.cmdDispatch(commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount);
    496 	}
    497 
    498 	{
    499 		VkImageMemoryBarrier imageOutputTransferSrcBarriers[2];
    500 
    501 		imageOutputTransferSrcBarriers[0] = makeImageMemoryBarrier
    502 		(
    503 			VK_ACCESS_SHADER_WRITE_BIT,
    504 			VK_ACCESS_TRANSFER_READ_BIT,
    505 			VK_IMAGE_LAYOUT_GENERAL,
    506 			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
    507 			imageTexels,
    508 			fullImageSubresourceRange
    509 		);
    510 
    511 		imageOutputTransferSrcBarriers[1] = makeImageMemoryBarrier
    512 		(
    513 			VK_ACCESS_SHADER_WRITE_BIT,
    514 			VK_ACCESS_TRANSFER_READ_BIT,
    515 			VK_IMAGE_LAYOUT_GENERAL,
    516 			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
    517 			imageResidency,
    518 			fullImageSubresourceRange
    519 		);
    520 
    521 		deviceInterface.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 2u, imageOutputTransferSrcBarriers);
    522 	}
    523 }
    524 
    525 class SparseShaderIntrinsicsInstanceFetch : public SparseShaderIntrinsicsInstanceStorage
    526 {
    527 public:
    528 	SparseShaderIntrinsicsInstanceFetch			(Context&					context,
    529 												 const SpirVFunction		function,
    530 												 const ImageType			imageType,
    531 												 const tcu::UVec3&			imageSize,
    532 												 const tcu::TextureFormat&	format)
    533 	: SparseShaderIntrinsicsInstanceStorage (context, function, imageType, imageSize, format) {}
    534 
    535 	VkImageUsageFlags	imageSparseUsageFlags	(void) const { return VK_IMAGE_USAGE_SAMPLED_BIT; }
    536 	VkDescriptorType	imageSparseDescType		(void) const { return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; }
    537 };
    538 
    539 TestInstance* SparseCaseOpImageSparseFetch::createInstance (Context& context) const
    540 {
    541 	return new SparseShaderIntrinsicsInstanceFetch(context, m_function, m_imageType, m_imageSize, m_format);
    542 }
    543 
    544 class SparseShaderIntrinsicsInstanceRead : public SparseShaderIntrinsicsInstanceStorage
    545 {
    546 public:
    547 	SparseShaderIntrinsicsInstanceRead			(Context&					context,
    548 												 const SpirVFunction		function,
    549 												 const ImageType			imageType,
    550 												 const tcu::UVec3&			imageSize,
    551 												 const tcu::TextureFormat&	format)
    552 	: SparseShaderIntrinsicsInstanceStorage (context, function, imageType, imageSize, format) {}
    553 
    554 	VkImageUsageFlags	imageSparseUsageFlags	(void) const { return VK_IMAGE_USAGE_STORAGE_BIT; }
    555 	VkDescriptorType	imageSparseDescType		(void) const { return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; }
    556 };
    557 
    558 TestInstance* SparseCaseOpImageSparseRead::createInstance (Context& context) const
    559 {
    560 	return new SparseShaderIntrinsicsInstanceRead(context, m_function, m_imageType, m_imageSize, m_format);
    561 }
    562 
    563 } // sparse
    564 } // vkt
    565