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