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