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
48namespace vkt
49{
50namespace image
51{
52namespace
53{
54using namespace vk;
55using de::MovePtr;
56using de::UniquePtr;
57using tcu::IVec3;
58
59static const VkFormat CHECKSUM_IMAGE_FORMAT = VK_FORMAT_R32_SINT;
60
61struct 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
76void 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
179void 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.
199void 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.
223void 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
240tcu::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
463tcu::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