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