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