• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Multisampled image load/store Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktImageMultisampleLoadStoreTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTestsUtil.hpp"
28 #include "vktImageLoadStoreUtil.hpp"
29 #include "vktImageTexture.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkImageUtil.hpp"
40 
41 #include "deUniquePtr.hpp"
42 
43 #include "tcuTextureUtil.hpp"
44 #include "tcuTestLog.hpp"
45 
46 #include <string>
47 #include <vector>
48 
49 namespace vkt
50 {
51 namespace image
52 {
53 namespace
54 {
55 using namespace vk;
56 using de::MovePtr;
57 using de::UniquePtr;
58 using tcu::IVec3;
59 
60 static const VkFormat CHECKSUM_IMAGE_FORMAT = VK_FORMAT_R32_SINT;
61 
62 struct CaseDef
63 {
64 	Texture					texture;
65 	VkFormat				format;
66 	VkSampleCountFlagBits	numSamples;
67 	bool					singleLayerBind;
68 };
69 
70 //  Multisampled storage image test.
71 //
72 //  Pass 1: Write a slightly different color pattern per-sample to the whole image.
73 //  Pass 2: Read samples of the same image and check if color values are in the expected range.
74 //          Write back results as a checksum image and verify them on the host.
75 //  Each checksum image pixel should contain an integer equal to the number of samples.
76 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)77 void initPrograms (SourceCollections& programCollection, const  CaseDef caseDef)
78 {
79 	const int			dimension			= (caseDef.singleLayerBind ? caseDef.texture.layerDimension() : caseDef.texture.dimension());
80 	const std::string	texelCoordStr		= (dimension == 1 ? "gx" : dimension == 2 ? "ivec2(gx, gy)" : dimension == 3 ? "ivec3(gx, gy, gz)" : "");
81 
82 	const ImageType		usedImageType		= (caseDef.singleLayerBind ? getImageTypeForSingleLayer(caseDef.texture.type()) : caseDef.texture.type());
83 	const std::string	formatQualifierStr	= getShaderImageFormatQualifier(mapVkFormat(caseDef.format));
84 	const std::string	msImageTypeStr		= getShaderImageType(mapVkFormat(caseDef.format), usedImageType, (caseDef.texture.numSamples() > 1));
85 
86 	const std::string	xMax				= de::toString(caseDef.texture.size().x() - 1);
87 	const std::string	yMax				= de::toString(caseDef.texture.size().y() - 1);
88 	const std::string	signednessPrefix	= isUintFormat(caseDef.format) ? "u" : isIntFormat(caseDef.format) ? "i" : "";
89 	const std::string	gvec4Expr			= signednessPrefix + "vec4";
90 	const int			numColorComponents	= tcu::getNumUsedChannels(mapVkFormat(caseDef.format).order);
91 
92 	const float			storeColorScale		= computeStoreColorScale(caseDef.format, caseDef.texture.size());
93 	const float			storeColorBias		= computeStoreColorBias(caseDef.format);
94 	DE_ASSERT(colorScaleAndBiasAreValid(caseDef.format, storeColorScale, storeColorBias));
95 
96 	const std::string	colorScaleExpr		= (storeColorScale == 1.0f ? "" : "*" + de::toString(storeColorScale))
97 											+ (storeColorBias == 0.0f ? "" : " + float(" + de::toString(storeColorBias) + ")");
98 	const std::string	colorExpr			=
99 		gvec4Expr + "("
100 		+                           "gx^gy^gz^(sampleNdx >> 5)^(sampleNdx & 31), "		// we "split" sampleNdx to keep this value in [0, 31] range for numSamples = 64 case
101 		+ (numColorComponents > 1 ? "(" + xMax + "-gx)^gy^gz, "              : "0, ")
102 		+ (numColorComponents > 2 ? "gx^(" + yMax + "-gy)^gz, "              : "0, ")
103 		+ (numColorComponents > 3 ? "(" + xMax + "-gx)^(" + yMax + "-gy)^gz" : "1")
104 		+ ")" + colorScaleExpr;
105 
106 	// Store shader
107 	{
108 		std::ostringstream src;
109 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
110 			<< "\n"
111 			<< "layout(local_size_x = 1) in;\n"
112 			<< "layout(set = 0, binding = 1, " << formatQualifierStr << ") writeonly uniform " << msImageTypeStr << " u_msImage;\n";
113 
114 		if (caseDef.singleLayerBind)
115 			src << "layout(set = 0, binding = 0) readonly uniform Constants {\n"
116 				<< "    int u_layerNdx;\n"
117 				<< "};\n";
118 
119 		src << "\n"
120 			<< "void main (void)\n"
121 			<< "{\n"
122 			<< "    int gx = int(gl_GlobalInvocationID.x);\n"
123 			<< "    int gy = int(gl_GlobalInvocationID.y);\n"
124 			<< "    int gz = " << (caseDef.singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") << ";\n"
125 			<< "\n"
126 			<< "    for (int sampleNdx = 0; sampleNdx < " << caseDef.texture.numSamples() <<"; ++sampleNdx) {\n"
127 			<< "        imageStore(u_msImage, " << texelCoordStr << ", sampleNdx, " << colorExpr << ");\n"
128 			<< "    }\n"
129 			<< "}\n";
130 
131 		programCollection.glslSources.add("comp_store") << glu::ComputeSource(src.str());
132 	}
133 
134 	// Load shader
135 	{
136 		const tcu::TextureFormat	checksumFormat			= mapVkFormat(CHECKSUM_IMAGE_FORMAT);
137 		const std::string			checksumImageTypeStr	= getShaderImageType(checksumFormat, usedImageType);
138 		const bool					useExactCompare			= isIntegerFormat(caseDef.format);
139 
140 		std::ostringstream src;
141 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
142 			<< "\n"
143 			<< "layout(local_size_x = 1) in;\n"
144 			<< "layout(set = 0, binding = 1, " << formatQualifierStr << ") readonly  uniform " << msImageTypeStr << " u_msImage;\n"
145 			<< "layout(set = 0, binding = 2, " << getShaderImageFormatQualifier(checksumFormat) << ") writeonly uniform " << checksumImageTypeStr << " u_checksumImage;\n";
146 
147 		if (caseDef.singleLayerBind)
148 			src << "layout(set = 0, binding = 0) readonly uniform Constants {\n"
149 				<< "    int u_layerNdx;\n"
150 				<< "};\n";
151 
152 		src << "\n"
153 			<< "void main (void)\n"
154 			<< "{\n"
155 			<< "    int gx = int(gl_GlobalInvocationID.x);\n"
156 			<< "    int gy = int(gl_GlobalInvocationID.y);\n"
157 			<< "    int gz = " << (caseDef.singleLayerBind ? "u_layerNdx" : "int(gl_GlobalInvocationID.z)") << ";\n"
158 			<< "\n"
159 			<< "    int checksum = 0;\n"
160 			<< "    for (int sampleNdx = 0; sampleNdx < " << caseDef.texture.numSamples() <<"; ++sampleNdx) {\n"
161 			<< "        " << gvec4Expr << " color = imageLoad(u_msImage, " << texelCoordStr << ", sampleNdx);\n";
162 
163 		if (useExactCompare)
164 			src << "        if (color == " << colorExpr << ")\n"
165 				<< "            ++checksum;\n";
166 		else
167 			src << "        " << gvec4Expr << " diff  = abs(abs(color) - abs(" << colorExpr << "));\n"
168 				<< "        if (all(lessThan(diff, " << gvec4Expr << "(0.02))))\n"
169 				<< "            ++checksum;\n";
170 
171 		src << "    }\n"
172 			<< "\n"
173 			<< "    imageStore(u_checksumImage, " << texelCoordStr << ", ivec4(checksum));\n"
174 			<< "}\n";
175 
176 		programCollection.glslSources.add("comp_load") << glu::ComputeSource(src.str());
177 	}
178 }
179 
checkRequirements(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const CaseDef & caseDef)180 void checkRequirements (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const CaseDef& caseDef)
181 {
182 	VkPhysicalDeviceFeatures	features;
183 	vki.getPhysicalDeviceFeatures(physDevice, &features);
184 
185 	if (!features.shaderStorageImageMultisample)
186 		TCU_THROW(NotSupportedError, "Multisampled storage images are not supported");
187 
188 	VkImageFormatProperties		imageFormatProperties;
189 	const VkResult				imageFormatResult		= vki.getPhysicalDeviceImageFormatProperties(
190 		physDevice, caseDef.format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT, (VkImageCreateFlags)0, &imageFormatProperties);
191 
192 	if (imageFormatResult == VK_ERROR_FORMAT_NOT_SUPPORTED)
193 		TCU_THROW(NotSupportedError, "Format is not supported");
194 
195 	if ((imageFormatProperties.sampleCounts & caseDef.numSamples) != caseDef.numSamples)
196 		TCU_THROW(NotSupportedError, "Requested sample count is not supported");
197 }
198 
199 //! Helper function to deal with per-layer resources.
insertImageViews(const DeviceInterface & vk,const VkDevice device,const CaseDef & caseDef,const VkFormat format,const VkImage image,std::vector<SharedVkImageView> * const pOutImageViews)200 void insertImageViews (const DeviceInterface& vk, const VkDevice device, const CaseDef& caseDef, const VkFormat format, const VkImage image, std::vector<SharedVkImageView>* const pOutImageViews)
201 {
202 	if (caseDef.singleLayerBind)
203 	{
204 		pOutImageViews->clear();
205 		pOutImageViews->resize(caseDef.texture.numLayers());
206 		for (int layerNdx = 0; layerNdx < caseDef.texture.numLayers(); ++layerNdx)
207 		{
208 			(*pOutImageViews)[layerNdx] = makeVkSharedPtr(makeImageView(
209 				vk, device, image, mapImageViewType(getImageTypeForSingleLayer(caseDef.texture.type())), format,
210 				makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, layerNdx, 1u)));
211 		}
212 	}
213 	else // bind all layers at once
214 	{
215 		pOutImageViews->clear();
216 		pOutImageViews->resize(1);
217 		(*pOutImageViews)[0] = makeVkSharedPtr(makeImageView(
218 			vk, device, image, mapImageViewType(caseDef.texture.type()), format,
219 			makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, caseDef.texture.numLayers())));
220 	}
221 }
222 
223 //! Helper function to deal with per-layer resources.
insertDescriptorSets(const DeviceInterface & vk,const VkDevice device,const CaseDef & caseDef,const VkDescriptorPool descriptorPool,const VkDescriptorSetLayout descriptorSetLayout,std::vector<SharedVkDescriptorSet> * const pOutDescriptorSets)224 void insertDescriptorSets (const DeviceInterface& vk, const VkDevice device, const CaseDef& caseDef, const VkDescriptorPool descriptorPool, const VkDescriptorSetLayout descriptorSetLayout, std::vector<SharedVkDescriptorSet>* const pOutDescriptorSets)
225 {
226 	if (caseDef.singleLayerBind)
227 	{
228 		pOutDescriptorSets->clear();
229 		pOutDescriptorSets->resize(caseDef.texture.numLayers());
230 		for (int layerNdx = 0; layerNdx < caseDef.texture.numLayers(); ++layerNdx)
231 			(*pOutDescriptorSets)[layerNdx] = makeVkSharedPtr(makeDescriptorSet(vk, device, descriptorPool, descriptorSetLayout));
232 	}
233 	else // bind all layers at once
234 	{
235 		pOutDescriptorSets->clear();
236 		pOutDescriptorSets->resize(1);
237 		(*pOutDescriptorSets)[0] = makeVkSharedPtr(makeDescriptorSet(vk, device, descriptorPool, descriptorSetLayout));
238 	}
239 }
240 
test(Context & context,const CaseDef caseDef)241 tcu::TestStatus test (Context& context, const CaseDef caseDef)
242 {
243 	const InstanceInterface&	vki					= context.getInstanceInterface();
244 	const VkPhysicalDevice		physDevice			= context.getPhysicalDevice();
245 	const DeviceInterface&		vk					= context.getDeviceInterface();
246 	const VkDevice				device				= context.getDevice();
247 	const VkQueue				queue				= context.getUniversalQueue();
248 	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
249 	Allocator&					allocator			= context.getDefaultAllocator();
250 
251 	checkRequirements(vki, physDevice, caseDef);
252 
253 	// Images
254 
255 	const UniquePtr<Image> msImage(new Image(
256 		vk, device, allocator, makeImageCreateInfo(caseDef.texture, caseDef.format, VK_IMAGE_USAGE_STORAGE_BIT, 0u), MemoryRequirement::Any));
257 
258 	const UniquePtr<Image> checksumImage(new Image(
259 		vk, device, allocator,
260 		makeImageCreateInfo(Texture(caseDef.texture, 1), CHECKSUM_IMAGE_FORMAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0u),
261 		MemoryRequirement::Any));
262 
263 	// Buffer used to pass constants to the shader.
264 
265 	const int			numLayers					= caseDef.texture.numLayers();
266 	const VkDeviceSize	bufferChunkSize				= getOptimalUniformBufferChunkSize(vki, physDevice, sizeof(deInt32));
267 	const VkDeviceSize	constantsBufferSizeBytes	= numLayers * bufferChunkSize;
268 	UniquePtr<Buffer>	constantsBuffer				(new Buffer(vk, device, allocator, makeBufferCreateInfo(constantsBufferSizeBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),
269 													 MemoryRequirement::HostVisible));
270 
271 	{
272 		const Allocation&	alloc	= constantsBuffer->getAllocation();
273 		deUint8* const		basePtr = static_cast<deUint8*>(alloc.getHostPtr());
274 
275 		deMemset(alloc.getHostPtr(), 0, static_cast<size_t>(constantsBufferSizeBytes));
276 
277 		for (int layerNdx = 0; layerNdx < numLayers; ++layerNdx)
278 		{
279 			deInt32* const valuePtr = reinterpret_cast<deInt32*>(basePtr + layerNdx * bufferChunkSize);
280 			*valuePtr = layerNdx;
281 		}
282 
283 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), constantsBufferSizeBytes);
284 	}
285 
286 	const VkDeviceSize	resultBufferSizeBytes	= getImageSizeBytes(caseDef.texture.size(), CHECKSUM_IMAGE_FORMAT);
287 	UniquePtr<Buffer>	resultBuffer			(new Buffer(vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
288 												 MemoryRequirement::HostVisible));
289 
290 	{
291 		const Allocation& alloc = resultBuffer->getAllocation();
292 		deMemset(alloc.getHostPtr(), 0, static_cast<size_t>(resultBufferSizeBytes));
293 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), resultBufferSizeBytes);
294 	}
295 
296 	// Descriptors
297 
298 	Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
299 		.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
300 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
301 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
302 		.build(vk, device));
303 
304 	Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
305 		.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, numLayers)
306 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
307 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, numLayers)
308 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, numLayers));
309 
310 	std::vector<SharedVkDescriptorSet>	allDescriptorSets;
311 	std::vector<SharedVkImageView>		allMultisampledImageViews;
312 	std::vector<SharedVkImageView>		allChecksumImageViews;
313 
314 	insertDescriptorSets(vk, device, caseDef, *descriptorPool, *descriptorSetLayout, &allDescriptorSets);
315 	insertImageViews	(vk, device, caseDef, caseDef.format, **msImage, &allMultisampledImageViews);
316 	insertImageViews	(vk, device, caseDef, CHECKSUM_IMAGE_FORMAT, **checksumImage, &allChecksumImageViews);
317 
318 	// Prepare commands
319 
320 	const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout(vk, device, *descriptorSetLayout));
321 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
322 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
323 
324 	const tcu::IVec3				workSize				= (caseDef.singleLayerBind ? caseDef.texture.layerSize() : caseDef.texture.size());
325 	const int						loopNumLayers			= (caseDef.singleLayerBind ? numLayers : 1);
326 	const VkImageSubresourceRange	subresourceAllLayers	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, caseDef.texture.numLayers());
327 
328 	// Pass 1: Write MS image
329 	{
330 		const Unique<VkShaderModule>	shaderModule	(createShaderModule	(vk, device, context.getBinaryCollection().get("comp_store"), 0));
331 		const Unique<VkPipeline>		pipeline		(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
332 
333 		beginCommandBuffer(vk, *cmdBuffer);
334 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
335 
336 		{
337 			const VkImageMemoryBarrier barriers[] =
338 			{
339 				makeImageMemoryBarrier((VkAccessFlags)0, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, **msImage, subresourceAllLayers),
340 				makeImageMemoryBarrier((VkAccessFlags)0, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, **checksumImage, subresourceAllLayers),
341 			};
342 
343 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0,
344 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
345 		}
346 
347 		for (int layerNdx = 0; layerNdx < loopNumLayers; ++layerNdx)
348 		{
349 			const VkDescriptorSet			descriptorSet					= **allDescriptorSets[layerNdx];
350 			const VkDescriptorImageInfo		descriptorMultiImageInfo		= makeDescriptorImageInfo(DE_NULL, **allMultisampledImageViews[layerNdx], VK_IMAGE_LAYOUT_GENERAL);
351 			const VkDescriptorBufferInfo	descriptorConstantsBufferInfo	= makeDescriptorBufferInfo(constantsBuffer->get(), layerNdx*bufferChunkSize, bufferChunkSize);
352 
353 			DescriptorSetUpdateBuilder()
354 				.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorConstantsBufferInfo)
355 				.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorMultiImageInfo)
356 				.update(vk, device);
357 
358 			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
359 			vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
360 		}
361 
362 		endCommandBuffer(vk, *cmdBuffer);
363 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
364 	}
365 
366 	// Pass 2: "Resolve" MS image in compute shader
367 	{
368 		const Unique<VkShaderModule>	shaderModule	(createShaderModule	(vk, device, context.getBinaryCollection().get("comp_load"), 0));
369 		const Unique<VkPipeline>		pipeline		(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
370 
371 		beginCommandBuffer(vk, *cmdBuffer);
372 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
373 
374 		{
375 			const VkImageMemoryBarrier barriers[] =
376 			{
377 				makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, **msImage, subresourceAllLayers),
378 			};
379 
380 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0,
381 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
382 		}
383 
384 		for (int layerNdx = 0; layerNdx < loopNumLayers; ++layerNdx)
385 		{
386 			const VkDescriptorSet			descriptorSet					= **allDescriptorSets[layerNdx];
387 			const VkDescriptorImageInfo		descriptorMultiImageInfo		= makeDescriptorImageInfo(DE_NULL, **allMultisampledImageViews[layerNdx], VK_IMAGE_LAYOUT_GENERAL);
388 			const VkDescriptorImageInfo		descriptorChecksumImageInfo		= makeDescriptorImageInfo(DE_NULL, **allChecksumImageViews[layerNdx], VK_IMAGE_LAYOUT_GENERAL);
389 			const VkDescriptorBufferInfo	descriptorConstantsBufferInfo	= makeDescriptorBufferInfo(constantsBuffer->get(), layerNdx*bufferChunkSize, bufferChunkSize);
390 
391 			DescriptorSetUpdateBuilder()
392 				.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptorConstantsBufferInfo)
393 				.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorMultiImageInfo)
394 				.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorChecksumImageInfo)
395 				.update(vk, device);
396 
397 			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
398 			vk.cmdDispatch(*cmdBuffer, workSize.x(), workSize.y(), workSize.z());
399 		}
400 
401 		endCommandBuffer(vk, *cmdBuffer);
402 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
403 	}
404 
405 	// Retrieve result
406 	{
407 		beginCommandBuffer(vk, *cmdBuffer);
408 
409 		{
410 			const VkImageMemoryBarrier barriers[] =
411 			{
412 				makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **checksumImage, subresourceAllLayers),
413 			};
414 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0,
415 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
416 		}
417 		{
418 			const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(caseDef.texture.layerSize()), caseDef.texture.numLayers());
419 			vk.cmdCopyImageToBuffer(*cmdBuffer, **checksumImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer, 1u, &copyRegion);
420 		}
421 		{
422 			const VkBufferMemoryBarrier barriers[] =
423 			{
424 				makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, **resultBuffer, 0ull, resultBufferSizeBytes),
425 			};
426 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
427 				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, 0u, DE_NULL);
428 		}
429 
430 		endCommandBuffer(vk, *cmdBuffer);
431 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
432 	}
433 
434 	// Verify
435 	{
436 		const Allocation& alloc = resultBuffer->getAllocation();
437 		invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), resultBufferSizeBytes);
438 
439 		const IVec3		imageSize			= caseDef.texture.size();
440 		const deInt32*	pDataPtr			= static_cast<deInt32*>(alloc.getHostPtr());
441 		const deInt32	expectedChecksum	= caseDef.texture.numSamples();
442 
443 		for (int layer = 0; layer < imageSize.z(); ++layer)
444 		for (int y = 0; y < imageSize.y(); ++y)
445 		for (int x = 0; x < imageSize.x(); ++x)
446 		{
447 			if (*pDataPtr != expectedChecksum)
448 			{
449 				context.getTestContext().getLog()
450 					<< tcu::TestLog::Message << "Some sample colors were incorrect at (x, y, layer) = (" << x << ", " << y << ", " << layer << ")"	<< tcu::TestLog::EndMessage
451 					<< tcu::TestLog::Message << "Checksum value is " << *pDataPtr << " but expected " << expectedChecksum << tcu::TestLog::EndMessage;
452 
453 				return tcu::TestStatus::fail("Some sample colors were incorrect");
454 			}
455 			++pDataPtr;
456 		}
457 
458 		return tcu::TestStatus::pass("OK");
459 	}
460 }
461 
462 } // anonymous ns
463 
createImageMultisampleLoadStoreTests(tcu::TestContext & testCtx)464 tcu::TestCaseGroup* createImageMultisampleLoadStoreTests (tcu::TestContext& testCtx)
465 {
466 	const Texture textures[] =
467 	{
468 		// \note Shader code is tweaked to work with image size of 32, take a look if this needs to be modified.
469 		Texture(IMAGE_TYPE_2D,			tcu::IVec3(32,	32,	1),		1),
470 		Texture(IMAGE_TYPE_2D_ARRAY,	tcu::IVec3(32,	32,	1),		4),
471 	};
472 
473 	static const VkFormat formats[] =
474 	{
475 		VK_FORMAT_R32G32B32A32_SFLOAT,
476 		VK_FORMAT_R16G16B16A16_SFLOAT,
477 		VK_FORMAT_R32_SFLOAT,
478 
479 		VK_FORMAT_R32G32B32A32_UINT,
480 		VK_FORMAT_R16G16B16A16_UINT,
481 		VK_FORMAT_R8G8B8A8_UINT,
482 		VK_FORMAT_R32_UINT,
483 
484 		VK_FORMAT_R32G32B32A32_SINT,
485 		VK_FORMAT_R16G16B16A16_SINT,
486 		VK_FORMAT_R8G8B8A8_SINT,
487 		VK_FORMAT_R32_SINT,
488 
489 		VK_FORMAT_R8G8B8A8_UNORM,
490 
491 		VK_FORMAT_R8G8B8A8_SNORM,
492 	};
493 
494 	static const VkSampleCountFlagBits samples[] =
495 	{
496 		VK_SAMPLE_COUNT_2_BIT,
497 		VK_SAMPLE_COUNT_4_BIT,
498 		VK_SAMPLE_COUNT_8_BIT,
499 		VK_SAMPLE_COUNT_16_BIT,
500 		VK_SAMPLE_COUNT_32_BIT,
501 		VK_SAMPLE_COUNT_64_BIT,
502 	};
503 
504 	MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "load_store_multisample", "Multisampled image store and load"));
505 
506 	for (int baseTextureNdx = 0; baseTextureNdx < DE_LENGTH_OF_ARRAY(textures); ++baseTextureNdx)
507 	{
508 		const Texture&				baseTexture			= textures[baseTextureNdx];
509 		MovePtr<tcu::TestCaseGroup>	imageViewGroup		(new tcu::TestCaseGroup(testCtx, getImageTypeName(baseTexture.type()).c_str(), ""));
510 		const int					numLayerBindModes	= (baseTexture.numLayers() == 1 ? 1 : 2);
511 
512 		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
513 		for (int layerBindMode = 0; layerBindMode < numLayerBindModes; ++layerBindMode)
514 		{
515 			const bool					singleLayerBind	= (layerBindMode != 0);
516 			const std::string			formatGroupName	= getFormatShortString(formats[formatNdx]) + (singleLayerBind ? "_single_layer" : "");
517 			MovePtr<tcu::TestCaseGroup>	formatGroup		(new tcu::TestCaseGroup(testCtx, formatGroupName.c_str(), ""));
518 
519 			for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
520 			{
521 				const std::string	samplesCaseName = "samples_" + de::toString(samples[samplesNdx]);
522 
523 				const CaseDef		caseDef =
524 				{
525 					Texture(baseTexture, samples[samplesNdx]),
526 					formats[formatNdx],
527 					samples[samplesNdx],
528 					singleLayerBind,
529 				};
530 
531 				addFunctionCaseWithPrograms(formatGroup.get(), samplesCaseName, "", initPrograms, test, caseDef);
532 			}
533 			imageViewGroup->addChild(formatGroup.release());
534 		}
535 		testGroup->addChild(imageViewGroup.release());
536 	}
537 
538 	return testGroup.release();
539 }
540 
541 } // image
542 } // vkt
543