1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 Google Inc.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file vktPipelineMultisampleResolveRenderAreaTests.hpp
24 * \brief Multisample resolve tests where a render area is less than an
25 *        attachment size.
26 *//*--------------------------------------------------------------------*/
27
28#include "vktPipelineMultisampleResolveRenderAreaTests.hpp"
29#include "vktTestCaseUtil.hpp"
30#include "vktTestGroupUtil.hpp"
31
32#include "vkCmdUtil.hpp"
33#include "vkImageUtil.hpp"
34#include "vkMemUtil.hpp"
35#include "vkObjUtil.hpp"
36#include "vkRefUtil.hpp"
37#include "vkTypeUtil.hpp"
38
39#include "tcuImageCompare.hpp"
40#include "tcuTestLog.hpp"
41
42namespace vkt
43{
44namespace pipeline
45{
46using namespace vk;
47using de::UniquePtr;
48
49namespace
50{
51
52enum class TestShape
53{
54	SHAPE_RECTANGLE,
55	SHAPE_DIAMOND,
56	SHAPE_PARALLELOGRAM
57};
58
59class MultisampleRenderAreaTestInstance : public TestInstance
60{
61public:
62					MultisampleRenderAreaTestInstance	(Context&							context,
63														 const PipelineConstructionType		pipelineConstructionType,
64														 const deUint32						sampleCount,
65														 const tcu::IVec2					framebufferSize,
66														 const TestShape					testShape,
67														 const VkFormat						colorFormat)
68														: TestInstance					(context)
69														, m_pipelineConstructionType	(pipelineConstructionType)
70														, m_sampleCount					(sampleCount)
71														, m_framebufferSize				(framebufferSize)
72														, m_testShape					(testShape)
73														, m_colorFormat					(colorFormat)
74														{}
75
76	tcu::TestStatus	iterate								(void);
77
78private:
79	VkImageCreateInfo	makeImageCreateInfo		(const tcu::IVec2& imageSize, const deUint32 sampleCount);
80
81	RenderPassWrapper	makeRenderPass			(const DeviceInterface&			vk,
82												 const VkDevice					device,
83												 const VkFormat					colorFormat,
84												 const VkImageLayout			initialLayout);
85
86	void				preparePipelineWrapper	(GraphicsPipelineWrapper&		gpw,
87												 const PipelineLayoutWrapper&	pipelineLayout,
88												 const VkRenderPass				renderPass,
89												 const ShaderWrapper			vertexModule,
90												 const ShaderWrapper			fragmentModule,
91												 const tcu::IVec2&				framebufferSize);
92
93	const PipelineConstructionType		m_pipelineConstructionType;
94	const deUint32						m_sampleCount;
95	const tcu::IVec2					m_framebufferSize;
96	const TestShape						m_testShape;
97	const VkFormat						m_colorFormat;
98};
99
100VkImageCreateInfo MultisampleRenderAreaTestInstance::makeImageCreateInfo(const tcu::IVec2& imageSize, const deUint32 sampleCount)
101{
102	const VkImageCreateInfo imageParams =
103	{
104		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,												// VkStructureType			sType;
105		DE_NULL,																			// const void*				pNext;
106		(VkImageCreateFlags)0,																// VkImageCreateFlags		flags;
107		VK_IMAGE_TYPE_2D,																	// VkImageType				imageType;
108		m_colorFormat,																		// VkFormat					format;
109		makeExtent3D(imageSize.x(), imageSize.y(), 1),										// VkExtent3D				extent;
110		1u,																					// deUint32					mipLevels;
111		1u,																					// deUint32					arrayLayers;
112		sampleCount < 2u ? VK_SAMPLE_COUNT_1_BIT : (VkSampleCountFlagBits)m_sampleCount,	// VkSampleCountFlagBits	samples;
113		VK_IMAGE_TILING_OPTIMAL,															// VkImageTiling			tiling;
114		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,				// VkImageUsageFlags		usage;
115		VK_SHARING_MODE_EXCLUSIVE,															// VkSharingMode			sharingMode;
116		0u,																					// deUint32					queueFamilyIndexCount;
117		DE_NULL,																			// const deUint32*			pQueueFamilyIndices;
118		VK_IMAGE_LAYOUT_UNDEFINED,															// VkImageLayout			initialLayout;
119	};
120
121	return imageParams;
122}
123
124RenderPassWrapper MultisampleRenderAreaTestInstance::makeRenderPass (const DeviceInterface&			vk,
125																	 const VkDevice					device,
126																	 const VkFormat					colorFormat,
127																	 const VkImageLayout			initialLayout)
128{
129	const VkAttachmentDescription			colorAttachmentDescription		=
130	{
131		(VkAttachmentDescriptionFlags)0,			// VkAttachmentDescriptionFlags	flags;
132		colorFormat,								// VkFormat						format;
133		(VkSampleCountFlagBits)m_sampleCount,		// VkSampleCountFlagBits		samples;
134		VK_ATTACHMENT_LOAD_OP_CLEAR,				// VkAttachmentLoadOp			loadOp;
135		VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp			storeOp;
136		VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp			stencilLoadOp;
137		VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp			stencilStoreOp;
138		initialLayout,								// VkImageLayout				initialLayout;
139		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout				finalLayout;
140	};
141
142	const VkAttachmentDescription			resolveAttachmentDescription	=
143	{
144		(VkAttachmentDescriptionFlags)0,			// VkAttachmentDescriptionFlags	flags;
145		colorFormat,								// VkFormat						format;
146		VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits		samples;
147		VK_ATTACHMENT_LOAD_OP_CLEAR,				// VkAttachmentLoadOp			loadOp;
148		VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp			storeOp;
149		VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp			stencilLoadOp;
150		VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp			stencilStoreOp;
151		initialLayout,								// VkImageLayout				initialLayout;
152		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout				finalLayout;
153	};
154
155	std::vector<VkAttachmentDescription>	attachmentDescriptions;
156
157	attachmentDescriptions.push_back(colorAttachmentDescription);
158	attachmentDescriptions.push_back(resolveAttachmentDescription);
159
160	const VkAttachmentReference				colorAttachmentRef				=
161	{
162		0u,											// uint32_t			attachment;
163		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
164	};
165
166	const VkAttachmentReference				resolveAttachmentRef			=
167	{
168		1u,											// uint32_t			attachment;
169		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
170	};
171
172	const VkSubpassDescription				subpassDescription				=
173	{
174		(VkSubpassDescriptionFlags)0,		// VkSubpassDescriptionFlags		flags;
175		VK_PIPELINE_BIND_POINT_GRAPHICS,	// VkPipelineBindPoint				pipelineBindPoint;
176		0u,									// uint32_t							inputAttachmentCount;
177		DE_NULL,							// const VkAttachmentReference*		pInputAttachments;
178		1u,									// uint32_t							colorAttachmentCount;
179		&colorAttachmentRef,				// const VkAttachmentReference*		pColorAttachments;
180		&resolveAttachmentRef,				// const VkAttachmentReference*		pResolveAttachments;
181		DE_NULL,							// const VkAttachmentReference*		pDepthStencilAttachment;
182		0u,									// uint32_t							preserveAttachmentCount;
183		DE_NULL								// const uint32_t*					pPreserveAttachments;
184	};
185
186	const VkRenderPassCreateInfo			renderPassInfo					=
187	{
188		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,	// VkStructureType					sType;
189		DE_NULL,									// const void*						pNext;
190		(VkRenderPassCreateFlags)0,					// VkRenderPassCreateFlags			flags;
191		(deUint32)attachmentDescriptions.size(),	// uint32_t							attachmentCount;
192		attachmentDescriptions.data(),				// const VkAttachmentDescription*	pAttachments;
193		1u,											// uint32_t							subpassCount;
194		&subpassDescription,						// const VkSubpassDescription*		pSubpasses;
195		0u,											// uint32_t							dependencyCount;
196		DE_NULL,									// const VkSubpassDependency*		pDependencies;
197	};
198
199	return RenderPassWrapper(m_pipelineConstructionType, vk, device, &renderPassInfo);
200}
201
202void MultisampleRenderAreaTestInstance::preparePipelineWrapper (GraphicsPipelineWrapper&		gpw,
203																const PipelineLayoutWrapper&	pipelineLayout,
204																const VkRenderPass				renderPass,
205																const ShaderWrapper				vertexModule,
206																const ShaderWrapper				fragmentModule,
207																const tcu::IVec2&				framebufferSize)
208{
209	const std::vector<VkViewport>	viewports		{ makeViewport(framebufferSize) };
210	const std::vector<VkRect2D>		scissors		{ makeRect2D(framebufferSize) };
211	VkSampleMask					sampleMask		= 0xffff;
212
213	const VkPipelineMultisampleStateCreateInfo	multisampleStateCreateInfo
214	{
215		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType
216		DE_NULL,													// const void*								pNext
217		0u,															// VkPipelineMultisampleStateCreateFlags	flags
218		(VkSampleCountFlagBits)m_sampleCount,						// VkSampleCountFlagBits					rasterizationSamples
219		DE_FALSE,													// VkBool32									sampleShadingEnable
220		0.0f,														// float									minSampleShading
221		&sampleMask,												// const VkSampleMask*						pSampleMask
222		DE_FALSE,													// VkBool32									alphaToCoverageEnable
223		DE_FALSE,													// VkBool32									alphaToOneEnable
224	};
225
226	gpw.setDefaultDepthStencilState()
227	   .setDefaultColorBlendState()
228	   .setDefaultRasterizationState()
229	   .setupVertexInputState()
230	   .setupPreRasterizationShaderState(viewports,
231			scissors,
232			pipelineLayout,
233			renderPass,
234			0u,
235			vertexModule)
236	   .setupFragmentShaderState(pipelineLayout,
237			renderPass,
238			0u,
239			fragmentModule,
240			DE_NULL,
241			&multisampleStateCreateInfo)
242	   .setupFragmentOutputState(renderPass, 0u, DE_NULL, &multisampleStateCreateInfo)
243	   .setMonolithicPipelineLayout(pipelineLayout)
244	   .buildPipeline();
245}
246
247tcu::TestStatus	MultisampleRenderAreaTestInstance::iterate (void)
248{
249	const InstanceInterface&		vki						= m_context.getInstanceInterface();
250	const DeviceInterface&			vk						= m_context.getDeviceInterface();
251	const VkPhysicalDevice			physicalDevice			= m_context.getPhysicalDevice();
252	const VkDevice					device					= m_context.getDevice();
253	Allocator&						allocator				= m_context.getDefaultAllocator();
254	const VkQueue					queue					= m_context.getUniversalQueue();
255	const deUint32					queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
256	const VkImageSubresourceRange	colorSubresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
257
258	const ShaderWrapper				vertexModule			(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
259	const ShaderWrapper				fragmentModule			(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
260
261	const Unique<VkImage>			colorImage				(makeImage(vk, device, makeImageCreateInfo(m_framebufferSize, m_sampleCount)));
262	const UniquePtr<Allocation>		colorImageAlloc			(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
263	const Unique<VkImageView>		colorImageView			(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, colorSubresourceRange));
264
265	const Unique<VkImage>			resolveColorImage		(makeImage(vk, device, makeImageCreateInfo(m_framebufferSize, 1u)));
266	const UniquePtr<Allocation>		resolveColorImageAlloc	(bindImage(vk, device, allocator, *resolveColorImage, MemoryRequirement::Any));
267	const Unique<VkImageView>		resolveColorImageView	(makeImageView(vk, device, *resolveColorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, colorSubresourceRange));
268
269	const VkImage					images[]				= { *colorImage, *resolveColorImage };
270	const VkImageView				attachmentImages[]		= { *colorImageView, *resolveColorImageView };
271	const deUint32					numUsedAttachmentImages	= DE_LENGTH_OF_ARRAY(attachmentImages);
272
273	const VkDeviceSize				colorBufferSizeBytes	= tcu::getPixelSize(mapVkFormat(m_colorFormat)) * m_framebufferSize.x() * m_framebufferSize.y();
274	const Unique<VkBuffer>			colorBufferResults		(makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
275	const UniquePtr<Allocation>		colorBufferAlloc		(bindBuffer(vk, device, allocator, *colorBufferResults, MemoryRequirement::HostVisible));
276
277	RenderPassWrapper				renderPassOne			(makeRenderPass(vk, device, m_colorFormat, VK_IMAGE_LAYOUT_UNDEFINED));
278	RenderPassWrapper				renderPassTwo			(makeRenderPass(vk, device, m_colorFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
279	renderPassOne.createFramebuffer(vk, device, numUsedAttachmentImages, images, attachmentImages, m_framebufferSize.x(), m_framebufferSize.y());
280	renderPassTwo.createFramebuffer(vk, device, numUsedAttachmentImages, images, attachmentImages, m_framebufferSize.x(), m_framebufferSize.y());
281
282	const PipelineLayoutWrapper		pipelineLayout			(m_pipelineConstructionType, vk, device);
283	GraphicsPipelineWrapper			graphicsPipeline		{vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_pipelineConstructionType};
284
285	const Unique<VkCommandPool>		cmdPool					(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
286	const Unique<VkCommandBuffer>	commandBuffer			(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
287
288	// Main vertex buffer
289	const deUint32					numVertices				= 6;
290	const VkDeviceSize				vertexBufferSizeBytes	= 256;
291	const Unique<VkBuffer>			vertexBuffer			(makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
292	const UniquePtr<Allocation>		vertexBufferAlloc		(bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
293
294	preparePipelineWrapper(graphicsPipeline, pipelineLayout, *renderPassOne, vertexModule, fragmentModule, m_framebufferSize);
295
296	{
297		tcu::Vec4* const pVertices = reinterpret_cast<tcu::Vec4*>(vertexBufferAlloc->getHostPtr());
298
299		// The shapes should fit just and just inside the renderArea.
300		if (m_testShape == TestShape::SHAPE_RECTANGLE)
301		{
302			float size = 0.5f;
303
304			pVertices[0] = tcu::Vec4(size, -size, 0.0f, 1.0f);
305			pVertices[1] = tcu::Vec4(-size, -size, 0.0f, 1.0f);
306			pVertices[2] = tcu::Vec4(-size, size, 0.0f, 1.0f);
307
308			pVertices[3] = tcu::Vec4(-size, size, 0.0f, 1.0f);
309			pVertices[4] = tcu::Vec4(size, size, 0.0f, 1.0f);
310			pVertices[5] = tcu::Vec4(size, -size, 0.0f, 1.0f);
311		}
312
313		if (m_testShape == TestShape::SHAPE_DIAMOND)
314		{
315			float size		= 0.5f;
316
317			pVertices[0]	= tcu::Vec4( size,  0.0f, 0.0f, 1.0f);
318			pVertices[1]	= tcu::Vec4(-0.0f, -size, 0.0f, 1.0f);
319			pVertices[2]	= tcu::Vec4(-size,  0.0f, 0.0f, 1.0f);
320
321			pVertices[3]	= tcu::Vec4( size,  0.0f, 0.0f, 1.0f);
322			pVertices[4]	= tcu::Vec4(-size,  0.0f, 0.0f, 1.0f);
323			pVertices[5]	= tcu::Vec4(-0.0f,  size, 0.0f, 1.0f);
324		}
325
326		if (m_testShape == TestShape::SHAPE_PARALLELOGRAM)
327		{
328			float size = 0.3125f;
329
330			pVertices[0] = tcu::Vec4(size, -size, 0.0f, 1.0f);
331			pVertices[1] = tcu::Vec4(-0.5f, -size, 0.0f, 1.0f);
332			pVertices[2] = tcu::Vec4(-size, size, 0.0f, 1.0f);
333
334			pVertices[3] = tcu::Vec4(-size, size, 0.0f, 1.0f);
335			pVertices[4] = tcu::Vec4(0.5f, size, 0.0f, 1.0f);
336			pVertices[5] = tcu::Vec4(size, -size, 0.0f, 1.0f);
337		}
338
339		flushAlloc(vk, device, *vertexBufferAlloc);
340	}
341
342	const VkDeviceSize				vertexBufferOffset		= 0ull;
343
344	const VkRect2D					testRenderArea			=
345	{
346		makeOffset2D(m_framebufferSize.x() / 4u, m_framebufferSize.x() / 4u),
347		makeExtent2D(m_framebufferSize.x() / 2u, m_framebufferSize.y() / 2u),
348	};
349
350	const std::vector<VkClearValue>	clearValuesFullArea		= { makeClearValueColor(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)), makeClearValueColor(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)) };
351	const std::vector<VkClearValue>	clearValuesTestArea		= { makeClearValueColor(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)), makeClearValueColor(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)) };
352
353	beginCommandBuffer(vk, *commandBuffer);
354
355	const VkRect2D					fullRenderArea			=
356	{
357		makeOffset2D(0u, 0u),
358		makeExtent2D(m_framebufferSize.x(), m_framebufferSize.y()),
359	};
360
361	// Clear whole render area with red color.
362	renderPassOne.begin(vk, *commandBuffer, fullRenderArea, static_cast<deUint32>(clearValuesFullArea.size()), clearValuesFullArea.data());
363	renderPassTwo.end(vk, *commandBuffer);
364
365	// Draw shape when render area size is halved.
366	renderPassTwo.begin(vk, *commandBuffer, testRenderArea, static_cast<deUint32>(clearValuesTestArea.size()), clearValuesTestArea.data());
367	vk.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
368	graphicsPipeline.bind(*commandBuffer);
369	vk.cmdDraw(*commandBuffer, numVertices, 1u, 0u, 0u);
370	renderPassTwo.end(vk, *commandBuffer);
371
372	copyImageToBuffer(vk, *commandBuffer, *resolveColorImage, *colorBufferResults, m_framebufferSize, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
373
374	endCommandBuffer(vk, *commandBuffer);
375	submitCommandsAndWait(vk, device, queue, *commandBuffer);
376
377	// Verify color output
378	{
379		invalidateAlloc(vk, device, *colorBufferAlloc);
380
381		tcu::TestLog&						log					= m_context.getTestContext().getLog();
382		const Unique<VkBuffer>				testBufferResults	(makeBuffer(vk, device, colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
383		tcu::ConstPixelBufferAccess			imageAccess			(mapVkFormat(m_colorFormat), m_framebufferSize.x(), m_framebufferSize.y(), 1, colorBufferAlloc->getHostPtr());
384
385		// Color check for rendered shape. Shape color is yellow.
386		if (imageAccess.getPixel(m_framebufferSize.x() / 2, m_framebufferSize.y() / 2) != tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f))
387		{
388			log << tcu::TestLog::Image("color0", "Rendered image", imageAccess);
389			return tcu::TestStatus::fail("Pixel check failed: shape color");
390		}
391
392		// Color check for the second render area. Clear color should be green.
393		if (m_testShape != TestShape::SHAPE_RECTANGLE)	// In this case the shape has covered the whole render area.
394		{
395			if (imageAccess.getPixel(m_framebufferSize.x() / 4 + 1, m_framebufferSize.y() / 4 + 1) != tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f))
396			{
397				log << tcu::TestLog::Image("color0", "Rendered image", imageAccess);
398				return tcu::TestStatus::fail("Pixel check failed inside the render area");
399			}
400		}
401
402		// Color check for possible overflowed multisample pixels outside of the second render area.
403		// Clear color after the first beginRenderPass should be red.
404		const int							minValue			= m_framebufferSize.y() / 4 - 1;
405		const int							maxValue			= m_framebufferSize.y() - m_framebufferSize.y() / 4;
406
407		for (int y = 0; y < m_framebufferSize.y(); y++)
408		{
409			for (int x = 0; x < m_framebufferSize.x(); x++)
410			{
411				if (!(x > minValue && y > minValue && x < maxValue && y < maxValue))
412				{
413					if (imageAccess.getPixel(x, y) != tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f))
414					{
415						log << tcu::TestLog::Message << "Incorrect color value " << imageAccess.getPixel(x, y) << " at location (" << x << ", " << y << ")" << tcu::TestLog::EndMessage;
416						log << tcu::TestLog::Image("color0", "Rendered image", imageAccess);
417						return tcu::TestStatus::fail("Pixel check failed outside the render area");
418					}
419				}
420			}
421		}
422	}
423
424	return tcu::TestStatus::pass("Success");
425}
426
427class MultisampleRenderAreaTest : public TestCase
428{
429public:
430						MultisampleRenderAreaTest	(tcu::TestContext&					testCtx,
431													 const std::string					name,
432													 const PipelineConstructionType		pipelineConstructionType,
433													 const deUint32						sampleCount,
434													 const tcu::IVec2					framebufferSize,
435													 const TestShape					testShape,
436													 const VkFormat						colorFormat	= VK_FORMAT_R8G8B8A8_UNORM)
437													: TestCase(testCtx,	name)
438													, m_pipelineConstructionType	(pipelineConstructionType)
439													, m_sampleCount					(sampleCount)
440													, m_framebufferSize				(framebufferSize)
441													, m_testShape					(testShape)
442													, m_colorFormat					(colorFormat)
443													{}
444
445	void				initPrograms				(SourceCollections&	programCollection) const;
446	TestInstance*		createInstance				(Context&			context) const;
447	virtual void		checkSupport				(Context&			context) const;
448
449private:
450
451	const PipelineConstructionType	m_pipelineConstructionType;
452	const deUint32					m_sampleCount;
453	const tcu::IVec2				m_framebufferSize;
454	const TestShape					m_testShape;
455	const VkFormat					m_colorFormat;
456};
457
458void MultisampleRenderAreaTest::initPrograms(SourceCollections& programCollection) const
459{
460	// Vertex shader
461	{
462		std::ostringstream src;
463		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
464			<< "\n"
465			<< "layout(location = 0) in vec4 position;\n"
466			<< "\n"
467			<< "void main (void)\n"
468			<< "{\n"
469			<< "	gl_Position = position;\n"
470			<< "}\n";
471
472		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
473	}
474
475	// Fragment shader
476	{
477		std::ostringstream frg;
478		frg << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
479			<< "\n"
480			<< "layout(location = 0) out vec4 fragColor;\n"
481			<< "\n"
482			<< "void main (void)\n"
483			<< "{\n"
484			<< "	fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
485			<< "}\n";
486
487		programCollection.glslSources.add("frag") << glu::FragmentSource(frg.str());
488	}
489}
490
491TestInstance* MultisampleRenderAreaTest::createInstance(Context& context) const
492{
493	return new MultisampleRenderAreaTestInstance(context, m_pipelineConstructionType, m_sampleCount, m_framebufferSize, m_testShape, m_colorFormat);
494}
495
496void MultisampleRenderAreaTest::checkSupport(Context& context) const
497{
498	// Check support for MSAA image format used in the test.
499	const InstanceInterface&	vki				= context.getInstanceInterface();
500	const VkPhysicalDevice		physDevice		= context.getPhysicalDevice();
501
502	VkImageFormatProperties		formatProperties;
503
504	vki.getPhysicalDeviceImageFormatProperties	(physDevice, m_colorFormat,
505												VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
506												VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
507												0u, &formatProperties);
508
509	if ((formatProperties.sampleCounts & m_sampleCount) == 0)
510		TCU_THROW(NotSupportedError, "Format does not support this number of samples");
511
512	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
513}
514
515} // anonymous
516
517tcu::TestCaseGroup* createMultisampleResolveRenderpassRenderAreaTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
518{
519	// resolving multisample image tests
520	de::MovePtr<tcu::TestCaseGroup> testGroupResolve(new tcu::TestCaseGroup(testCtx, "resolve"));
521
522	de::MovePtr<tcu::TestCaseGroup> testGroupRenderArea(new tcu::TestCaseGroup(testCtx, "renderpass_renderarea", "renderpass render area tests"));
523
524	static const struct
525	{
526		std::string					shapeName;
527		TestShape					testShape;
528	} shapes[]	=
529	{
530		{ "rectangle",		TestShape::SHAPE_RECTANGLE		},
531		{ "diamond",		TestShape::SHAPE_DIAMOND		},
532		{ "parallelogram",	TestShape::SHAPE_PARALLELOGRAM	}
533	};
534
535	static const struct
536	{
537		std::string		caseName;
538		const deUint32	sampleCount;
539	} cases[]	=
540	{
541		{ "samples_2",	2u,	},
542		{ "samples_4",	4u,	},
543		{ "samples_8",	8u,	},
544		{ "samples_16",	16u	},
545	};
546
547	for (const auto& testShape : shapes)
548	{
549		for (const auto& testCase : cases)
550		{
551			testGroupRenderArea->addChild(new MultisampleRenderAreaTest(testCtx, testShape.shapeName + "_" + testCase.caseName, pipelineConstructionType, testCase.sampleCount, tcu::IVec2(32, 32), testShape.testShape));
552		}
553	}
554
555	testGroupResolve->addChild(testGroupRenderArea.release());
556
557	return testGroupResolve.release();
558}
559
560} // pipeline
561} // vkt
562