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 
42 namespace vkt
43 {
44 namespace pipeline
45 {
46 using namespace vk;
47 using de::UniquePtr;
48 
49 namespace
50 {
51 
52 enum class TestShape
53 {
54 	SHAPE_RECTANGLE,
55 	SHAPE_DIAMOND,
56 	SHAPE_PARALLELOGRAM
57 };
58 
59 class MultisampleRenderAreaTestInstance : public TestInstance
60 {
61 public:
MultisampleRenderAreaTestInstance(Context& context, const PipelineConstructionType pipelineConstructionType, const deUint32 sampleCount, const tcu::IVec2 framebufferSize, const TestShape testShape, const VkFormat colorFormat)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 
78 private:
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 
makeImageCreateInfo(const tcu::IVec2& imageSize, const deUint32 sampleCount)100 VkImageCreateInfo 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 
makeRenderPass(const DeviceInterface& vk, const VkDevice device, const VkFormat colorFormat, const VkImageLayout initialLayout)124 RenderPassWrapper 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 
preparePipelineWrapper(GraphicsPipelineWrapper& gpw, const PipelineLayoutWrapper& pipelineLayout, const VkRenderPass renderPass, const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule, const tcu::IVec2& framebufferSize)202 void 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 
iterate(void)247 tcu::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 
427 class MultisampleRenderAreaTest : public TestCase
428 {
429 public:
MultisampleRenderAreaTest(tcu::TestContext& testCtx, const std::string name, const PipelineConstructionType pipelineConstructionType, const deUint32 sampleCount, const tcu::IVec2 framebufferSize, const TestShape testShape, const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM)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 
449 private:
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 
initPrograms(SourceCollections& programCollection) const458 void 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 
createInstance(Context& context) const491 TestInstance* MultisampleRenderAreaTest::createInstance(Context& context) const
492 {
493 	return new MultisampleRenderAreaTestInstance(context, m_pipelineConstructionType, m_sampleCount, m_framebufferSize, m_testShape, m_colorFormat);
494 }
495 
checkSupport(Context& context) const496 void 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 
createMultisampleResolveRenderpassRenderAreaTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)517 tcu::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