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