• 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 vktPipelineMultisampleBaseResolveAndPerSampleFetch.cpp
21 * \brief Base class for tests that check results of multisample resolve
22 *		  and/or values of individual samples
23 *//*--------------------------------------------------------------------*/
24 
25 #include "vktPipelineMultisampleBaseResolveAndPerSampleFetch.hpp"
26 #include "vktPipelineMakeUtil.hpp"
27 #include "vkBarrierUtil.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "tcuTestLog.hpp"
36 #include <vector>
37 
38 namespace vkt
39 {
40 namespace pipeline
41 {
42 namespace multisample
43 {
44 
45 using namespace vk;
46 
initPrograms(vk::SourceCollections & programCollection) const47 void MSCaseBaseResolveAndPerSampleFetch::initPrograms (vk::SourceCollections& programCollection) const
48 {
49 	// Create vertex shader
50 	std::ostringstream vs;
51 
52 	vs << "#version 440\n"
53 		<< "layout(location = 0) in vec4 vs_in_position_ndc;\n"
54 		<< "\n"
55 		<< "out gl_PerVertex {\n"
56 		<< "	vec4  gl_Position;\n"
57 		<< "};\n"
58 		<< "void main (void)\n"
59 		<< "{\n"
60 		<< "	gl_Position	= vs_in_position_ndc;\n"
61 		<< "}\n";
62 
63 	programCollection.glslSources.add("per_sample_fetch_vs") << glu::VertexSource(vs.str());
64 
65 	// Create fragment shader
66 	std::ostringstream fs;
67 
68 	fs << "#version 440\n"
69 		<< "\n"
70 		<< "layout(location = 0) out vec4 fs_out_color;\n"
71 		<< "\n"
72 		<< "layout(set = 0, binding = 0, input_attachment_index = 0) uniform subpassInputMS imageMS;\n"
73 		<< "\n"
74 		<< "layout(set = 0, binding = 1, std140) uniform SampleBlock {\n"
75 		<< "    int sampleNdx;\n"
76 		<< "};\n"
77 		<< "void main (void)\n"
78 		<< "{\n"
79 		<< "	fs_out_color = subpassLoad(imageMS, sampleNdx);\n"
80 		<< "}\n";
81 
82 	programCollection.glslSources.add("per_sample_fetch_fs") << glu::FragmentSource(fs.str());
83 }
84 
MSInstanceBaseResolveAndPerSampleFetch(Context & context,const ImageMSParams & imageMSParams)85 MSInstanceBaseResolveAndPerSampleFetch::MSInstanceBaseResolveAndPerSampleFetch (Context& context, const ImageMSParams& imageMSParams)
86 	: MultisampleInstanceBase(context, imageMSParams) {}
87 
getMSStateCreateInfo(const ImageMSParams & imageMSParams) const88 VkPipelineMultisampleStateCreateInfo MSInstanceBaseResolveAndPerSampleFetch::getMSStateCreateInfo (const ImageMSParams& imageMSParams) const
89 {
90 	const VkPipelineMultisampleStateCreateInfo multisampleStateInfo =
91 	{
92 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
93 		DE_NULL,														// const void*								pNext;
94 		(VkPipelineMultisampleStateCreateFlags)0u,						// VkPipelineMultisampleStateCreateFlags	flags;
95 		imageMSParams.numSamples,										// VkSampleCountFlagBits					rasterizationSamples;
96 		VK_TRUE,														// VkBool32									sampleShadingEnable;
97 		1.0f,															// float									minSampleShading;
98 		DE_NULL,														// const VkSampleMask*						pSampleMask;
99 		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
100 		VK_FALSE,														// VkBool32									alphaToOneEnable;
101 	};
102 
103 	return multisampleStateInfo;
104 }
105 
createMSPassDescSetLayout(const ImageMSParams & imageMSParams)106 const VkDescriptorSetLayout* MSInstanceBaseResolveAndPerSampleFetch::createMSPassDescSetLayout(const ImageMSParams& imageMSParams)
107 {
108 	DE_UNREF(imageMSParams);
109 
110 	return DE_NULL;
111 }
112 
createMSPassDescSet(const ImageMSParams & imageMSParams,const VkDescriptorSetLayout * descSetLayout)113 const VkDescriptorSet* MSInstanceBaseResolveAndPerSampleFetch::createMSPassDescSet(const ImageMSParams& imageMSParams, const VkDescriptorSetLayout* descSetLayout)
114 {
115 	DE_UNREF(imageMSParams);
116 	DE_UNREF(descSetLayout);
117 
118 	return DE_NULL;
119 }
120 
iterate(void)121 tcu::TestStatus MSInstanceBaseResolveAndPerSampleFetch::iterate (void)
122 {
123 	const InstanceInterface&	instance			= m_context.getInstanceInterface();
124 	const DeviceInterface&		deviceInterface		= m_context.getDeviceInterface();
125 	const VkDevice				device				= m_context.getDevice();
126 	const VkPhysicalDevice		physicalDevice		= m_context.getPhysicalDevice();
127 	Allocator&					allocator			= m_context.getDefaultAllocator();
128 	const VkQueue				queue				= m_context.getUniversalQueue();
129 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
130 
131 	VkImageCreateInfo			imageMSInfo;
132 	VkImageCreateInfo			imageRSInfo;
133 	const deUint32				firstSubpassAttachmentsCount = 2u;
134 
135 	// Check if image size does not exceed device limits
136 	validateImageSize(instance, physicalDevice, m_imageType, m_imageMSParams.imageSize);
137 
138 	// Check if device supports image format as color attachment
139 	validateImageFeatureFlags(instance, physicalDevice, mapTextureFormat(m_imageFormat), VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
140 
141 	imageMSInfo.sType					= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
142 	imageMSInfo.pNext					= DE_NULL;
143 	imageMSInfo.flags					= 0u;
144 	imageMSInfo.imageType				= mapImageType(m_imageType);
145 	imageMSInfo.format					= mapTextureFormat(m_imageFormat);
146 	imageMSInfo.extent					= makeExtent3D(getLayerSize(m_imageType, m_imageMSParams.imageSize));
147 	imageMSInfo.arrayLayers				= getNumLayers(m_imageType, m_imageMSParams.imageSize);
148 	imageMSInfo.mipLevels				= 1u;
149 	imageMSInfo.samples					= m_imageMSParams.numSamples;
150 	imageMSInfo.tiling					= VK_IMAGE_TILING_OPTIMAL;
151 	imageMSInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;
152 	imageMSInfo.usage					= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
153 	imageMSInfo.sharingMode				= VK_SHARING_MODE_EXCLUSIVE;
154 	imageMSInfo.queueFamilyIndexCount	= 0u;
155 	imageMSInfo.pQueueFamilyIndices		= DE_NULL;
156 
157 	if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
158 	{
159 		imageMSInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
160 	}
161 
162 	validateImageInfo(instance, physicalDevice, imageMSInfo);
163 
164 	const de::UniquePtr<ImageWithMemory> imageMS(new ImageWithMemory(deviceInterface, device, allocator, imageMSInfo, MemoryRequirement::Any));
165 
166 	imageRSInfo			= imageMSInfo;
167 	imageRSInfo.samples	= VK_SAMPLE_COUNT_1_BIT;
168 	imageRSInfo.usage	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
169 
170 	validateImageInfo(instance, physicalDevice, imageRSInfo);
171 
172 	const de::UniquePtr<ImageWithMemory> imageRS(new ImageWithMemory(deviceInterface, device, allocator, imageRSInfo, MemoryRequirement::Any));
173 
174 	const deUint32 numSamples = static_cast<deUint32>(imageMSInfo.samples);
175 
176 	std::vector<de::SharedPtr<ImageWithMemory> > imagesPerSampleVec(numSamples);
177 
178 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
179 	{
180 		imagesPerSampleVec[sampleNdx] = de::SharedPtr<ImageWithMemory>(new ImageWithMemory(deviceInterface, device, allocator, imageRSInfo, MemoryRequirement::Any));
181 	}
182 
183 	// Create render pass
184 	std::vector<VkAttachmentDescription> attachments(firstSubpassAttachmentsCount + numSamples);
185 
186 	{
187 		const VkAttachmentDescription attachmentMSDesc =
188 		{
189 			(VkAttachmentDescriptionFlags)0u,			// VkAttachmentDescriptionFlags		flags;
190 			imageMSInfo.format,							// VkFormat							format;
191 			imageMSInfo.samples,						// VkSampleCountFlagBits			samples;
192 			VK_ATTACHMENT_LOAD_OP_CLEAR,				// VkAttachmentLoadOp				loadOp;
193 			VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp				storeOp;
194 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp				stencilLoadOp;
195 			VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp				stencilStoreOp;
196 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout					initialLayout;
197 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL	// VkImageLayout					finalLayout;
198 		};
199 
200 		attachments[0] = attachmentMSDesc;
201 
202 		const VkAttachmentDescription attachmentRSDesc =
203 		{
204 			(VkAttachmentDescriptionFlags)0u,			// VkAttachmentDescriptionFlags		flags;
205 			imageRSInfo.format,							// VkFormat							format;
206 			imageRSInfo.samples,						// VkSampleCountFlagBits			samples;
207 			VK_ATTACHMENT_LOAD_OP_CLEAR,				// VkAttachmentLoadOp				loadOp;
208 			VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp				storeOp;
209 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp				stencilLoadOp;
210 			VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp				stencilStoreOp;
211 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout					initialLayout;
212 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout					finalLayout;
213 		};
214 
215 		attachments[1] = attachmentRSDesc;
216 
217 		for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
218 		{
219 			attachments[firstSubpassAttachmentsCount + sampleNdx] = attachmentRSDesc;
220 		}
221 	}
222 
223 	const VkAttachmentReference attachmentMSColorRef =
224 	{
225 		0u,											// deUint32			attachment;
226 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
227 	};
228 
229 	const VkAttachmentReference attachmentMSInputRef =
230 	{
231 		0u,											// deUint32			attachment;
232 		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL	// VkImageLayout	layout;
233 	};
234 
235 	const VkAttachmentReference attachmentRSColorRef =
236 	{
237 		1u,											// deUint32			attachment;
238 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
239 	};
240 
241 	std::vector<VkAttachmentReference> perSampleAttachmentRef(numSamples);
242 
243 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
244 	{
245 		const VkAttachmentReference attachmentRef =
246 		{
247 			firstSubpassAttachmentsCount + sampleNdx,	// deUint32			attachment;
248 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
249 		};
250 
251 		perSampleAttachmentRef[sampleNdx] = attachmentRef;
252 	}
253 
254 	std::vector<deUint32> preserveAttachments(1u + numSamples);
255 
256 	for (deUint32 attachNdx = 0u; attachNdx < 1u + numSamples; ++attachNdx)
257 	{
258 		preserveAttachments[attachNdx] = 1u + attachNdx;
259 	}
260 
261 	std::vector<VkSubpassDescription> subpasses(1u + numSamples);
262 	std::vector<VkSubpassDependency>  subpassDependencies;
263 
264 	const VkSubpassDescription firstSubpassDesc =
265 	{
266 		(VkSubpassDescriptionFlags)0u,		// VkSubpassDescriptionFlags		flags;
267 		VK_PIPELINE_BIND_POINT_GRAPHICS,	// VkPipelineBindPoint				pipelineBindPoint;
268 		0u,									// deUint32							inputAttachmentCount;
269 		DE_NULL,							// const VkAttachmentReference*		pInputAttachments;
270 		1u,									// deUint32							colorAttachmentCount;
271 		&attachmentMSColorRef,				// const VkAttachmentReference*		pColorAttachments;
272 		&attachmentRSColorRef,				// const VkAttachmentReference*		pResolveAttachments;
273 		DE_NULL,							// const VkAttachmentReference*		pDepthStencilAttachment;
274 		0u,									// deUint32							preserveAttachmentCount;
275 		DE_NULL								// const deUint32*					pPreserveAttachments;
276 	};
277 
278 	subpasses[0] = firstSubpassDesc;
279 
280 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
281 	{
282 		const VkSubpassDescription subpassDesc =
283 		{
284 			(VkSubpassDescriptionFlags)0u,			// VkSubpassDescriptionFlags		flags;
285 			VK_PIPELINE_BIND_POINT_GRAPHICS,		// VkPipelineBindPoint				pipelineBindPoint;
286 			1u,										// deUint32							inputAttachmentCount;
287 			&attachmentMSInputRef,					// const VkAttachmentReference*		pInputAttachments;
288 			1u,										// deUint32							colorAttachmentCount;
289 			&perSampleAttachmentRef[sampleNdx],		// const VkAttachmentReference*		pColorAttachments;
290 			DE_NULL,								// const VkAttachmentReference*		pResolveAttachments;
291 			DE_NULL,								// const VkAttachmentReference*		pDepthStencilAttachment;
292 			1u + sampleNdx,							// deUint32							preserveAttachmentCount;
293 			dataPointer(preserveAttachments)		// const deUint32*					pPreserveAttachments;
294 		};
295 
296 		subpasses[1u + sampleNdx] = subpassDesc;
297 
298 		if (sampleNdx == 0u)
299 		{
300 			// The second subpass will be in charge of transitioning the multisample attachment from
301 			// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
302 			const VkSubpassDependency subpassDependency =
303 			{
304 				0u,												// uint32_t                srcSubpass;
305 				1u + sampleNdx,									// uint32_t                dstSubpass;
306 				VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	// VkPipelineStageFlags    srcStageMask;
307 				VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,			// VkPipelineStageFlags    dstStageMask;
308 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags           srcAccessMask;
309 				VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,			// VkAccessFlags           dstAccessMask;
310 				0u,												// VkDependencyFlags       dependencyFlags;
311 			};
312 
313 			subpassDependencies.push_back(subpassDependency);
314 		}
315 		else
316 		{
317 			// Make sure subpass reads are in order. This serializes subpasses to make sure there are no layout transition hazards
318 			// in the multisample image, from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
319 			// caused by parallel execution of several subpasses.
320 			const VkSubpassDependency readDependency =
321 			{
322 				sampleNdx,										// uint32_t                srcSubpass;
323 				1u + sampleNdx,									// uint32_t                dstSubpass;
324 				VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,			// VkPipelineStageFlags    srcStageMask;
325 				VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,			// VkPipelineStageFlags    dstStageMask;
326 				VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,			// VkAccessFlags           srcAccessMask;
327 				VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,			// VkAccessFlags           dstAccessMask;
328 				0u,												// VkDependencyFlags       dependencyFlags;
329 			};
330 
331 			subpassDependencies.push_back(readDependency);
332 		}
333 	}
334 
335 	const VkRenderPassCreateInfo renderPassInfo =
336 	{
337 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
338 		DE_NULL,											// const void*						pNext;
339 		(VkRenderPassCreateFlags)0u,						// VkRenderPassCreateFlags			flags;
340 		static_cast<deUint32>(attachments.size()),			// deUint32							attachmentCount;
341 		dataPointer(attachments),							// const VkAttachmentDescription*	pAttachments;
342 		static_cast<deUint32>(subpasses.size()),			// deUint32							subpassCount;
343 		dataPointer(subpasses),								// const VkSubpassDescription*		pSubpasses;
344 		static_cast<deUint32>(subpassDependencies.size()),	// deUint32							dependencyCount;
345 		dataPointer(subpassDependencies)					// const VkSubpassDependency*		pDependencies;
346 	};
347 
348 	const Unique<VkRenderPass> renderPass(createRenderPass(deviceInterface, device, &renderPassInfo));
349 
350 	const VkImageSubresourceRange fullImageRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageMSInfo.mipLevels, 0u, imageMSInfo.arrayLayers);
351 
352 	// Create color attachments image views
353 	typedef de::SharedPtr<Unique<VkImageView> > VkImageViewSp;
354 	std::vector<VkImageViewSp>	imageViewsShPtrs(firstSubpassAttachmentsCount + numSamples);
355 	std::vector<VkImageView>	imageViews(firstSubpassAttachmentsCount + numSamples);
356 
357 	imageViewsShPtrs[0] = makeVkSharedPtr(makeImageView(deviceInterface, device, **imageMS, mapImageViewType(m_imageType), imageMSInfo.format, fullImageRange));
358 	imageViewsShPtrs[1] = makeVkSharedPtr(makeImageView(deviceInterface, device, **imageRS, mapImageViewType(m_imageType), imageRSInfo.format, fullImageRange));
359 
360 	imageViews[0] = **imageViewsShPtrs[0];
361 	imageViews[1] = **imageViewsShPtrs[1];
362 
363 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
364 	{
365 		imageViewsShPtrs[firstSubpassAttachmentsCount + sampleNdx] = makeVkSharedPtr(makeImageView(deviceInterface, device, **imagesPerSampleVec[sampleNdx], mapImageViewType(m_imageType), imageRSInfo.format, fullImageRange));
366 		imageViews[firstSubpassAttachmentsCount + sampleNdx] = **imageViewsShPtrs[firstSubpassAttachmentsCount + sampleNdx];
367 	}
368 
369 	// Create framebuffer
370 	const VkFramebufferCreateInfo framebufferInfo =
371 	{
372 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	// VkStructureType							   sType;
373 		DE_NULL,									// const void*                                 pNext;
374 		(VkFramebufferCreateFlags)0u,				// VkFramebufferCreateFlags                    flags;
375 		*renderPass,								// VkRenderPass                                renderPass;
376 		static_cast<deUint32>(imageViews.size()),	// uint32_t                                    attachmentCount;
377 		dataPointer(imageViews),					// const VkImageView*                          pAttachments;
378 		imageMSInfo.extent.width,					// uint32_t                                    width;
379 		imageMSInfo.extent.height,					// uint32_t                                    height;
380 		imageMSInfo.arrayLayers,					// uint32_t                                    layers;
381 	};
382 
383 	const Unique<VkFramebuffer> framebuffer(createFramebuffer(deviceInterface, device, &framebufferInfo));
384 
385 	const VkDescriptorSetLayout* descriptorSetLayoutMSPass = createMSPassDescSetLayout(m_imageMSParams);
386 
387 	// Create pipeline layout
388 	const VkPipelineLayoutCreateInfo pipelineLayoutMSPassParams =
389 	{
390 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// VkStructureType					sType;
391 		DE_NULL,										// const void*						pNext;
392 		(VkPipelineLayoutCreateFlags)0u,				// VkPipelineLayoutCreateFlags		flags;
393 		descriptorSetLayoutMSPass ? 1u : 0u,			// deUint32							setLayoutCount;
394 		descriptorSetLayoutMSPass,						// const VkDescriptorSetLayout*		pSetLayouts;
395 		0u,												// deUint32							pushConstantRangeCount;
396 		DE_NULL,										// const VkPushConstantRange*		pPushConstantRanges;
397 	};
398 
399 	const Unique<VkPipelineLayout> pipelineLayoutMSPass(createPipelineLayout(deviceInterface, device, &pipelineLayoutMSPassParams));
400 
401 	// Create vertex attributes data
402 	const VertexDataDesc vertexDataDesc = getVertexDataDescripton();
403 
404 	de::SharedPtr<BufferWithMemory> vertexBuffer = de::SharedPtr<BufferWithMemory>(new BufferWithMemory(deviceInterface, device, allocator, makeBufferCreateInfo(vertexDataDesc.dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible));
405 	const Allocation& vertexBufferAllocation = vertexBuffer->getAllocation();
406 
407 	uploadVertexData(vertexBufferAllocation, vertexDataDesc);
408 
409 	flushAlloc(deviceInterface, device, vertexBufferAllocation);
410 
411 	const VkVertexInputBindingDescription vertexBinding =
412 	{
413 		0u,							// deUint32				binding;
414 		vertexDataDesc.dataStride,	// deUint32				stride;
415 		VK_VERTEX_INPUT_RATE_VERTEX	// VkVertexInputRate	inputRate;
416 	};
417 
418 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
419 	{
420 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,			// VkStructureType                             sType;
421 		DE_NULL,															// const void*                                 pNext;
422 		(VkPipelineVertexInputStateCreateFlags)0u,							// VkPipelineVertexInputStateCreateFlags       flags;
423 		1u,																	// uint32_t                                    vertexBindingDescriptionCount;
424 		&vertexBinding,														// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
425 		static_cast<deUint32>(vertexDataDesc.vertexAttribDescVec.size()),	// uint32_t                                    vertexAttributeDescriptionCount;
426 		dataPointer(vertexDataDesc.vertexAttribDescVec),					// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
427 	};
428 
429 	const std::vector<VkViewport>	viewports	{ makeViewport(imageMSInfo.extent) };
430 	const std::vector<VkRect2D>		scissors	{ makeRect2D(imageMSInfo.extent) };
431 
432 	const VkPipelineMultisampleStateCreateInfo multisampleStateInfo = getMSStateCreateInfo(m_imageMSParams);
433 
434 	// Create graphics pipeline for multisample pass
435 	const Unique<VkShaderModule> vsMSPassModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get("vertex_shader"), (VkShaderModuleCreateFlags)0u));
436 	const Unique<VkShaderModule> fsMSPassModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get("fragment_shader"), (VkShaderModuleCreateFlags)0u));
437 
438 	GraphicsPipelineWrapper graphicsPipelineMSPass(deviceInterface, device, m_imageMSParams.pipelineConstructionType);
439 	graphicsPipelineMSPass.setDefaultColorBlendState()
440 						  .setDefaultDepthStencilState()
441 						  .setDefaultRasterizationState()
442 						  .setDefaultTopology(vertexDataDesc.primitiveTopology)
443 						  .setupVertexInputState(&vertexInputStateInfo)
444 						  .setupPreRasterizationShaderState(viewports, scissors, *pipelineLayoutMSPass, *renderPass, 0u, *vsMSPassModule)
445 						  .setupFragmentShaderState(*pipelineLayoutMSPass, *renderPass, 0u, *fsMSPassModule, DE_NULL, &multisampleStateInfo)
446 						  .setupFragmentOutputState(*renderPass, 0u, DE_NULL, &multisampleStateInfo)
447 						  .setMonolithicPipelineLayout(*pipelineLayoutMSPass)
448 						  .buildPipeline();
449 
450 	std::vector<GraphicsPipelineWrapper> graphicsPipelinesPerSampleFetch;
451 	graphicsPipelinesPerSampleFetch.reserve(numSamples);
452 
453 	// Create descriptor set layout
454 	const Unique<VkDescriptorSetLayout> descriptorSetLayout(
455 		DescriptorSetLayoutBuilder()
456 		.addSingleBinding(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_SHADER_STAGE_FRAGMENT_BIT)
457 		.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_SHADER_STAGE_FRAGMENT_BIT)
458 		.build(deviceInterface, device));
459 
460 	const Unique<VkPipelineLayout> pipelineLayoutPerSampleFetchPass(makePipelineLayout(deviceInterface, device, *descriptorSetLayout));
461 
462 	const deUint32 bufferPerSampleFetchPassSize = 4u * (deUint32)sizeof(tcu::Vec4);
463 
464 	de::SharedPtr<BufferWithMemory> vertexBufferPerSampleFetchPass = de::SharedPtr<BufferWithMemory>(new BufferWithMemory(deviceInterface, device, allocator, makeBufferCreateInfo(bufferPerSampleFetchPassSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible));
465 
466 	// Create graphics pipelines for per sample texel fetch passes
467 	{
468 		const Unique<VkShaderModule> vsPerSampleFetchPassModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get("per_sample_fetch_vs"), (VkShaderModuleCreateFlags)0u));
469 		const Unique<VkShaderModule> fsPerSampleFetchPassModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get("per_sample_fetch_fs"), (VkShaderModuleCreateFlags)0u));
470 
471 		std::vector<tcu::Vec4> vertices;
472 
473 		vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
474 		vertices.push_back(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f));
475 		vertices.push_back(tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f));
476 		vertices.push_back(tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f));
477 
478 		const Allocation& vertexAllocPerSampleFetchPass = vertexBufferPerSampleFetchPass->getAllocation();
479 
480 		deMemcpy(vertexAllocPerSampleFetchPass.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(bufferPerSampleFetchPassSize));
481 
482 		flushAlloc(deviceInterface, device, vertexAllocPerSampleFetchPass);
483 
484 		for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
485 		{
486 			const deUint32 subpass = 1u + sampleNdx;
487 			graphicsPipelinesPerSampleFetch.emplace_back(deviceInterface, device, m_imageMSParams.pipelineConstructionType);
488 			graphicsPipelinesPerSampleFetch.back()
489 				.setDefaultMultisampleState()
490 				.setDefaultColorBlendState()
491 				.setDefaultDepthStencilState()
492 				.setDefaultRasterizationState()
493 				.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
494 				.setupVertexInputState()
495 				.setupPreRasterizationShaderState(viewports, scissors, *pipelineLayoutPerSampleFetchPass, *renderPass, subpass, *vsPerSampleFetchPassModule)
496 				.setupFragmentShaderState(*pipelineLayoutPerSampleFetchPass, *renderPass, subpass, *fsPerSampleFetchPassModule)
497 				.setupFragmentOutputState(*renderPass, subpass)
498 				.setMonolithicPipelineLayout(*pipelineLayoutPerSampleFetchPass)
499 				.buildPipeline();
500 		}
501 	}
502 
503 	// Create descriptor pool
504 	const Unique<VkDescriptorPool> descriptorPool(
505 		DescriptorPoolBuilder()
506 		.addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u)
507 		.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1u)
508 		.build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
509 
510 	// Create descriptor set
511 	const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(deviceInterface, device, *descriptorPool, *descriptorSetLayout));
512 
513 	const VkPhysicalDeviceLimits deviceLimits = getPhysicalDeviceProperties(instance, physicalDevice).limits;
514 
515 	VkDeviceSize uboOffsetAlignment = sizeof(deInt32) < deviceLimits.minUniformBufferOffsetAlignment ? deviceLimits.minUniformBufferOffsetAlignment : sizeof(deInt32);
516 
517 	uboOffsetAlignment += (deviceLimits.minUniformBufferOffsetAlignment - uboOffsetAlignment % deviceLimits.minUniformBufferOffsetAlignment) % deviceLimits.minUniformBufferOffsetAlignment;
518 
519 	const VkBufferCreateInfo	bufferSampleIDInfo = makeBufferCreateInfo(uboOffsetAlignment * numSamples, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
520 	const de::UniquePtr<BufferWithMemory>	bufferSampleID(new BufferWithMemory(deviceInterface, device, allocator, bufferSampleIDInfo, MemoryRequirement::HostVisible));
521 
522 	std::vector<deUint32> sampleIDsOffsets(numSamples);
523 
524 	{
525 		deInt8* sampleIDs = new deInt8[static_cast<deUint32>(uboOffsetAlignment) * numSamples];
526 
527 		for (deInt32 sampleNdx = 0u; sampleNdx < static_cast<deInt32>(numSamples); ++sampleNdx)
528 		{
529 			sampleIDsOffsets[sampleNdx] = static_cast<deUint32>(sampleNdx * uboOffsetAlignment);
530 			deInt8* samplePtr = sampleIDs + sampleIDsOffsets[sampleNdx];
531 
532 			deMemcpy(samplePtr, &sampleNdx, sizeof(deInt32));
533 		}
534 
535 		deMemcpy(bufferSampleID->getAllocation().getHostPtr(), sampleIDs, static_cast<deUint32>(uboOffsetAlignment * numSamples));
536 
537 		flushAlloc(deviceInterface, device, bufferSampleID->getAllocation());
538 
539 		delete[] sampleIDs;
540 	}
541 
542 	{
543 		const VkDescriptorImageInfo	 descImageInfo  = makeDescriptorImageInfo(DE_NULL, imageViews[0], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
544 		const VkDescriptorBufferInfo descBufferInfo	= makeDescriptorBufferInfo(**bufferSampleID, 0u, sizeof(deInt32));
545 
546 		DescriptorSetUpdateBuilder()
547 			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &descImageInfo)
548 			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &descBufferInfo)
549 			.update(deviceInterface, device);
550 	}
551 
552 	// Create command buffer for compute and transfer oparations
553 	const Unique<VkCommandPool>	  commandPool(createCommandPool(deviceInterface, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
554 	const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, device, *commandPool));
555 
556 	// Start recording commands
557 	beginCommandBuffer(deviceInterface, *commandBuffer);
558 
559 	{
560 		std::vector<VkImageMemoryBarrier> imageOutputAttachmentBarriers(firstSubpassAttachmentsCount + numSamples);
561 
562 		imageOutputAttachmentBarriers[0] = makeImageMemoryBarrier
563 		(
564 			0u,
565 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
566 			VK_IMAGE_LAYOUT_UNDEFINED,
567 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
568 			**imageMS,
569 			fullImageRange
570 		);
571 
572 		imageOutputAttachmentBarriers[1] = makeImageMemoryBarrier
573 		(
574 			0u,
575 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
576 			VK_IMAGE_LAYOUT_UNDEFINED,
577 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
578 			**imageRS,
579 			fullImageRange
580 		);
581 
582 		for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
583 		{
584 			imageOutputAttachmentBarriers[firstSubpassAttachmentsCount + sampleNdx] = makeImageMemoryBarrier
585 			(
586 				0u,
587 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
588 				VK_IMAGE_LAYOUT_UNDEFINED,
589 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
590 				**imagesPerSampleVec[sampleNdx],
591 				fullImageRange
592 			);
593 		}
594 
595 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
596 			static_cast<deUint32>(imageOutputAttachmentBarriers.size()), dataPointer(imageOutputAttachmentBarriers));
597 	}
598 
599 	{
600 		const VkDeviceSize vertexStartOffset = 0u;
601 
602 		std::vector<VkClearValue> clearValues(firstSubpassAttachmentsCount + numSamples);
603 		for (deUint32 attachmentNdx = 0u; attachmentNdx < firstSubpassAttachmentsCount + numSamples; ++attachmentNdx)
604 		{
605 			clearValues[attachmentNdx] = makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
606 		}
607 
608 		beginRenderPass(deviceInterface, *commandBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, imageMSInfo.extent.width, imageMSInfo.extent.height), (deUint32)clearValues.size(), dataPointer(clearValues));
609 
610 		// Bind graphics pipeline
611 		deviceInterface.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineMSPass.getPipeline());
612 
613 		const VkDescriptorSet* descriptorSetMSPass = createMSPassDescSet(m_imageMSParams, descriptorSetLayoutMSPass);
614 
615 		if (descriptorSetMSPass)
616 		{
617 			// Bind descriptor set
618 			deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayoutMSPass, 0u, 1u, descriptorSetMSPass, 0u, DE_NULL);
619 		}
620 
621 		// Bind vertex buffer
622 		deviceInterface.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer->get(), &vertexStartOffset);
623 
624 		// Perform a draw
625 		deviceInterface.cmdDraw(*commandBuffer, vertexDataDesc.verticesCount, 1u, 0u, 0u);
626 
627 		for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
628 		{
629 			deviceInterface.cmdNextSubpass(*commandBuffer, VK_SUBPASS_CONTENTS_INLINE);
630 
631 			// Bind graphics pipeline
632 			deviceInterface.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelinesPerSampleFetch[sampleNdx].getPipeline());
633 
634 			// Bind descriptor set
635 			deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayoutPerSampleFetchPass, 0u, 1u, &descriptorSet.get(), 1u, &sampleIDsOffsets[sampleNdx]);
636 
637 			// Bind vertex buffer
638 			deviceInterface.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBufferPerSampleFetchPass->get(), &vertexStartOffset);
639 
640 			// Perform a draw
641 			deviceInterface.cmdDraw(*commandBuffer, 4u, 1u, 0u, 0u);
642 		}
643 
644 		// End render pass
645 		endRenderPass(deviceInterface, *commandBuffer);
646 	}
647 
648 	{
649 		const VkImageMemoryBarrier imageRSTransferBarrier = makeImageMemoryBarrier
650 		(
651 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
652 			VK_ACCESS_TRANSFER_READ_BIT,
653 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
654 			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
655 			**imageRS,
656 			fullImageRange
657 		);
658 
659 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageRSTransferBarrier);
660 	}
661 
662 	// Copy data from imageRS to buffer
663 	const deUint32				imageRSSizeInBytes = getImageSizeInBytes(imageRSInfo.extent, imageRSInfo.arrayLayers, m_imageFormat, imageRSInfo.mipLevels, 1u);
664 
665 	const VkBufferCreateInfo				bufferRSInfo = makeBufferCreateInfo(imageRSSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
666 	const de::UniquePtr<BufferWithMemory>	bufferRS(new BufferWithMemory(deviceInterface, device, allocator, bufferRSInfo, MemoryRequirement::HostVisible));
667 
668 	{
669 		const VkBufferImageCopy bufferImageCopy =
670 		{
671 			0u,																						//	VkDeviceSize				bufferOffset;
672 			0u,																						//	deUint32					bufferRowLength;
673 			0u,																						//	deUint32					bufferImageHeight;
674 			makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, imageRSInfo.arrayLayers),	//	VkImageSubresourceLayers	imageSubresource;
675 			makeOffset3D(0, 0, 0),																	//	VkOffset3D					imageOffset;
676 			imageRSInfo.extent,																		//	VkExtent3D					imageExtent;
677 		};
678 
679 		deviceInterface.cmdCopyImageToBuffer(*commandBuffer, **imageRS, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, bufferRS->get(), 1u, &bufferImageCopy);
680 	}
681 
682 	{
683 		const VkBufferMemoryBarrier bufferRSHostReadBarrier = makeBufferMemoryBarrier
684 		(
685 			VK_ACCESS_TRANSFER_WRITE_BIT,
686 			VK_ACCESS_HOST_READ_BIT,
687 			bufferRS->get(),
688 			0u,
689 			imageRSSizeInBytes
690 		);
691 
692 		deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &bufferRSHostReadBarrier, 0u, DE_NULL);
693 	}
694 
695 	// Copy data from per sample images to buffers
696 	std::vector<VkImageMemoryBarrier> imagesPerSampleTransferBarriers(numSamples);
697 
698 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
699 	{
700 		imagesPerSampleTransferBarriers[sampleNdx] = makeImageMemoryBarrier
701 		(
702 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
703 			VK_ACCESS_TRANSFER_READ_BIT,
704 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
705 			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
706 			**imagesPerSampleVec[sampleNdx],
707 			fullImageRange
708 		);
709 	}
710 
711 	deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
712 		static_cast<deUint32>(imagesPerSampleTransferBarriers.size()), dataPointer(imagesPerSampleTransferBarriers));
713 
714 	std::vector<de::SharedPtr<BufferWithMemory> > buffersPerSample(numSamples);
715 
716 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
717 	{
718 		buffersPerSample[sampleNdx] = de::SharedPtr<BufferWithMemory>(new BufferWithMemory(deviceInterface, device, allocator, bufferRSInfo, MemoryRequirement::HostVisible));
719 
720 		const VkBufferImageCopy bufferImageCopy =
721 		{
722 			0u,																						//	VkDeviceSize				bufferOffset;
723 			0u,																						//	deUint32					bufferRowLength;
724 			0u,																						//	deUint32					bufferImageHeight;
725 			makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, imageRSInfo.arrayLayers),	//	VkImageSubresourceLayers	imageSubresource;
726 			makeOffset3D(0, 0, 0),																	//	VkOffset3D					imageOffset;
727 			imageRSInfo.extent,																		//	VkExtent3D					imageExtent;
728 		};
729 
730 		deviceInterface.cmdCopyImageToBuffer(*commandBuffer, **imagesPerSampleVec[sampleNdx], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **buffersPerSample[sampleNdx], 1u, &bufferImageCopy);
731 	}
732 
733 	std::vector<VkBufferMemoryBarrier> buffersPerSampleHostReadBarriers(numSamples);
734 
735 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
736 	{
737 		buffersPerSampleHostReadBarriers[sampleNdx] = makeBufferMemoryBarrier
738 		(
739 			VK_ACCESS_TRANSFER_WRITE_BIT,
740 			VK_ACCESS_HOST_READ_BIT,
741 			**buffersPerSample[sampleNdx],
742 			0u,
743 			imageRSSizeInBytes
744 		);
745 	}
746 
747 	deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL,
748 		static_cast<deUint32>(buffersPerSampleHostReadBarriers.size()), dataPointer(buffersPerSampleHostReadBarriers), 0u, DE_NULL);
749 
750 	// End recording commands
751 	endCommandBuffer(deviceInterface, *commandBuffer);
752 
753 	// Submit commands for execution and wait for completion
754 	submitCommandsAndWait(deviceInterface, device, queue, *commandBuffer);
755 
756 	// Retrieve data from bufferRS to host memory
757 	const Allocation& bufferRSAlloc = bufferRS->getAllocation();
758 
759 	invalidateAlloc(deviceInterface, device, bufferRSAlloc);
760 
761 	const tcu::ConstPixelBufferAccess bufferRSData (m_imageFormat,
762 													imageRSInfo.extent.width,
763 													imageRSInfo.extent.height,
764 													imageRSInfo.extent.depth * imageRSInfo.arrayLayers,
765 													bufferRSAlloc.getHostPtr());
766 
767 	std::stringstream resolveName;
768 	resolveName << "Resolve image " << getImageTypeName(m_imageType) << "_" << bufferRSData.getWidth() << "_" << bufferRSData.getHeight() << "_" << bufferRSData.getDepth() << std::endl;
769 
770 	m_context.getTestContext().getLog()
771 		<< tcu::TestLog::Section(resolveName.str(), resolveName.str())
772 		<< tcu::LogImage("resolve", "", bufferRSData)
773 		<< tcu::TestLog::EndSection;
774 
775 	std::vector<tcu::ConstPixelBufferAccess> buffersPerSampleData(numSamples);
776 
777 	// Retrieve data from per sample buffers to host memory
778 	for (deUint32 sampleNdx = 0u; sampleNdx < numSamples; ++sampleNdx)
779 	{
780 		const Allocation& bufferAlloc = buffersPerSample[sampleNdx]->getAllocation();
781 
782 		invalidateAlloc(deviceInterface, device, bufferAlloc);
783 
784 		buffersPerSampleData[sampleNdx] = tcu::ConstPixelBufferAccess
785 		(
786 			m_imageFormat,
787 			imageRSInfo.extent.width,
788 			imageRSInfo.extent.height,
789 			imageRSInfo.extent.depth * imageRSInfo.arrayLayers,
790 			bufferAlloc.getHostPtr()
791 		);
792 
793 		std::stringstream sampleName;
794 		sampleName << "Sample " << sampleNdx << " image" << std::endl;
795 
796 		m_context.getTestContext().getLog()
797 			<< tcu::TestLog::Section(sampleName.str(), sampleName.str())
798 			<< tcu::LogImage("sample", "", buffersPerSampleData[sampleNdx])
799 			<< tcu::TestLog::EndSection;
800 	}
801 
802 	return verifyImageData(imageMSInfo, imageRSInfo, buffersPerSampleData, bufferRSData);
803 }
804 
805 } // multisample
806 } // pipeline
807 } // vkt
808