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