1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google 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
21  * \brief Tests for render pass multisample resolve
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktRenderPassMultisampleResolveTests.hpp"
25 #include "vktRenderPassTestsUtil.hpp"
26 
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkDeviceUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkRef.hpp"
38 #include "vkRefUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42 
43 #include "tcuFloat.hpp"
44 #include "tcuImageCompare.hpp"
45 #include "tcuFormatUtil.hpp"
46 #include "tcuMaybe.hpp"
47 #include "tcuResultCollector.hpp"
48 #include "tcuTestLog.hpp"
49 #include "tcuTextureUtil.hpp"
50 #include "tcuVectorUtil.hpp"
51 #include "tcuStringTemplate.hpp"
52 
53 #include "deUniquePtr.hpp"
54 #include "deSharedPtr.hpp"
55 
56 using namespace vk;
57 
58 using tcu::BVec4;
59 using tcu::IVec2;
60 using tcu::IVec4;
61 using tcu::UVec2;
62 using tcu::UVec4;
63 using tcu::Vec2;
64 using tcu::Vec3;
65 using tcu::Vec4;
66 
67 using tcu::ConstPixelBufferAccess;
68 using tcu::PixelBufferAccess;
69 using tcu::TestLog;
70 
71 using std::vector;
72 
73 typedef de::SharedPtr<Allocation>							AllocationSp;
74 typedef de::SharedPtr<vk::Unique<VkImage> >					VkImageSp;
75 typedef de::SharedPtr<vk::Unique<VkImageView> >				VkImageViewSp;
76 typedef de::SharedPtr<vk::Unique<VkBuffer> >				VkBufferSp;
77 typedef de::SharedPtr<vk::Unique<VkSampler> >				VkSamplerSp;
78 typedef de::SharedPtr<vk::Unique<VkPipeline> >				VkPipelineSp;
79 typedef de::SharedPtr<vk::Unique<VkDescriptorSetLayout> >	VkDescriptorSetLayoutSp;
80 typedef de::SharedPtr<vk::Unique<VkDescriptorPool> >		VkDescriptorPoolSp;
81 typedef de::SharedPtr<vk::Unique<VkDescriptorSet> >			VkDescriptorSetSp;
82 
83 namespace vkt
84 {
85 namespace
86 {
87 
88 using namespace renderpass;
89 
90 template<typename T>
safeSharedPtr(T * ptr)91 de::SharedPtr<T> safeSharedPtr (T* ptr)
92 {
93 	try
94 	{
95 		return de::SharedPtr<T>(ptr);
96 	}
97 	catch (...)
98 	{
99 		delete ptr;
100 		throw;
101 	}
102 }
103 
104 enum TestType
105 {
106 	RESOLVE			= 0,
107 	MAX_ATTACHMENTS,
108 	COMPATIBILITY
109 };
110 
111 struct TestConfig
112 {
113 	TestType		testType;
114 	VkFormat		format;
115 	deUint32		sampleCount;
116 	deUint32		layerCount;
117 	deUint32		attachmentCount;
118 	deUint32		width;
119 	deUint32		height;
120 	RenderPassType	renderPassType;
121 };
122 
123 // Render pass traits that groups render pass related types together and by that help
124 // to reduce number of template parrameters passed to number of functions in those tests
125 struct RenderPass1Trait
126 {
127 	typedef AttachmentDescription1	AttDesc;
128 	typedef AttachmentReference1	AttRef;
129 	typedef SubpassDescription1		SubpassDesc;
130 	typedef SubpassDependency1		SubpassDep;
131 	typedef RenderPassCreateInfo1	RenderPassCreateInfo;
132 };
133 struct RenderPass2Trait
134 {
135 	typedef AttachmentDescription2	AttDesc;
136 	typedef AttachmentReference2	AttRef;
137 	typedef SubpassDescription2		SubpassDesc;
138 	typedef SubpassDependency2		SubpassDep;
139 	typedef RenderPassCreateInfo2	RenderPassCreateInfo;
140 };
141 
142 class MultisampleRenderPassTestBase : public TestInstance
143 {
144 public:
145 	MultisampleRenderPassTestBase	(Context& context, TestConfig config);
146 	~MultisampleRenderPassTestBase	(void);
147 
148 protected:
149 
150 	Move<VkImage>			createImage			(VkSampleCountFlagBits		sampleCountBit,
151 												 VkImageUsageFlags			usage) const;
152 	vector<VkImageSp>		createImages		(VkSampleCountFlagBits		sampleCountBit,
153 												 VkImageUsageFlags			usage) const;
154 	vector<AllocationSp>	createImageMemory	(const vector<VkImageSp>&	images) const;
155 	vector<VkImageViewSp>	createImageViews	(const vector<VkImageSp>&	images) const;
156 
157 	vector<VkBufferSp>		createBuffers		() const;
158 	vector<AllocationSp>	createBufferMemory	(const vector<VkBufferSp>& buffers) const;
159 
160 	Move<VkFramebuffer>		createFramebuffer	(const std::vector<VkImageViewSp>	multisampleImageViews,
161 												 const std::vector<VkImageViewSp>	singlesampleImageViews,
162 												 VkRenderPass						renderPass) const;
163 
164 	bool					featuresSupported				(Context& context, TestConfig config) const;
165 	void					clearAttachments				(VkCommandBuffer commandBuffer) const;
166 	VkDeviceSize			getPixelSize					() const;
167 	tcu::Vec4				getFormatThreshold				() const;
168 	VkSampleCountFlagBits	sampleCountBitFromSampleCount	(deUint32 count) const;
169 	void					logImage						(const std::string& name,
170 															 const tcu::ConstPixelBufferAccess& image) const;
171 
172 protected:
173 
174 	const bool						m_featuresSupported;
175 	const bool						m_extensionSupported;
176 	const bool						m_testCompatibility;
177 	const RenderPassType			m_renderPassType;
178 
179 	const VkFormat					m_format;
180 	const VkSampleCountFlagBits		m_sampleCount;
181 	const deUint32					m_layerCount;
182 	const deUint32					m_attachmentsCount;
183 	const deUint32					m_width;
184 	const deUint32					m_height;
185 };
186 
MultisampleRenderPassTestBase(Context & context,TestConfig config)187 MultisampleRenderPassTestBase::MultisampleRenderPassTestBase (Context& context, TestConfig config)
188 	: TestInstance				(context)
189 	, m_featuresSupported		(featuresSupported(context, config))
190 	, m_extensionSupported		((config.renderPassType == RENDERPASS_TYPE_RENDERPASS2) && context.requireDeviceFunctionality("VK_KHR_create_renderpass2"))
191 	, m_testCompatibility		(config.testType == COMPATIBILITY)
192 	, m_renderPassType			(config.renderPassType)
193 	, m_format					(config.format)
194 	, m_sampleCount				(sampleCountBitFromSampleCount(config.sampleCount))
195 	, m_layerCount				(config.layerCount)
196 	, m_attachmentsCount		(config.attachmentCount)
197 	, m_width					(config.width)
198 	, m_height					(config.height)
199 {
200 }
201 
~MultisampleRenderPassTestBase()202 MultisampleRenderPassTestBase::~MultisampleRenderPassTestBase ()
203 {
204 }
205 
createImage(VkSampleCountFlagBits sampleCountBit,VkImageUsageFlags usage) const206 Move<VkImage> MultisampleRenderPassTestBase::createImage (VkSampleCountFlagBits sampleCountBit, VkImageUsageFlags usage) const
207 {
208 	const InstanceInterface&		vki						= m_context.getInstanceInterface();
209 	const DeviceInterface&			vkd						= m_context.getDeviceInterface();
210 	VkDevice						device					= m_context.getDevice();
211 	VkPhysicalDevice				physicalDevice			= m_context.getPhysicalDevice();
212 	const tcu::TextureFormat		format					(mapVkFormat(m_format));
213 	const VkImageType				imageType				(VK_IMAGE_TYPE_2D);
214 	const VkImageTiling				imageTiling				(VK_IMAGE_TILING_OPTIMAL);
215 	const VkFormatProperties		formatProperties		(getPhysicalDeviceFormatProperties(vki, physicalDevice, m_format));
216 	const VkExtent3D				imageExtent =
217 	{
218 		m_width,
219 		m_height,
220 		1u
221 	};
222 
223 	try
224 	{
225 		const VkImageFormatProperties	imageFormatProperties(getPhysicalDeviceImageFormatProperties(vki, physicalDevice, m_format, imageType, imageTiling, usage, 0u));
226 
227 		if ((tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))
228 			&& (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)
229 			TCU_THROW(NotSupportedError, "Format can't be used as depth stencil attachment");
230 
231 		if (!(tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))
232 			&& (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0)
233 			TCU_THROW(NotSupportedError, "Format can't be used as color attachment");
234 
235 		if (imageFormatProperties.maxExtent.width < imageExtent.width
236 			|| imageFormatProperties.maxExtent.height < imageExtent.height
237 			|| ((imageFormatProperties.sampleCounts & m_sampleCount) == 0)
238 			|| imageFormatProperties.maxArrayLayers < m_layerCount)
239 		{
240 			TCU_THROW(NotSupportedError, "Image type not supported");
241 		}
242 
243 		const VkImageCreateInfo pCreateInfo =
244 		{
245 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
246 			DE_NULL,
247 			0u,
248 			imageType,
249 			m_format,
250 			imageExtent,
251 			1u,
252 			m_layerCount,
253 			sampleCountBit,
254 			imageTiling,
255 			usage,
256 			VK_SHARING_MODE_EXCLUSIVE,
257 			0u,
258 			DE_NULL,
259 			VK_IMAGE_LAYOUT_UNDEFINED
260 		};
261 
262 		return ::createImage(vkd, device, &pCreateInfo);
263 	}
264 	catch (const vk::Error& error)
265 	{
266 		if (error.getError() == VK_ERROR_FORMAT_NOT_SUPPORTED)
267 			TCU_THROW(NotSupportedError, "Image format not supported");
268 
269 		throw;
270 	}
271 }
272 
createImages(VkSampleCountFlagBits sampleCountBit,VkImageUsageFlags usage) const273 vector<VkImageSp> MultisampleRenderPassTestBase::createImages (VkSampleCountFlagBits sampleCountBit, VkImageUsageFlags usage) const
274 {
275 	std::vector<VkImageSp> images (m_attachmentsCount);
276 	for (size_t imageNdx = 0; imageNdx < m_attachmentsCount; imageNdx++)
277 		images[imageNdx] = safeSharedPtr(new Unique<VkImage>(createImage(sampleCountBit, usage)));
278 	return images;
279 }
280 
createImageMemory(const vector<VkImageSp> & images) const281 vector<AllocationSp> MultisampleRenderPassTestBase::createImageMemory (const vector<VkImageSp>& images) const
282 {
283 	const DeviceInterface&		vkd			= m_context.getDeviceInterface();
284 	VkDevice					device		= m_context.getDevice();
285 	Allocator&					allocator	= m_context.getDefaultAllocator();
286 	std::vector<AllocationSp>	memory		(images.size());
287 
288 	for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++)
289 	{
290 		VkImage					image			= **images[memoryNdx];
291 		VkMemoryRequirements	requirements	= getImageMemoryRequirements(vkd, device, image);
292 
293 		de::MovePtr<Allocation>	allocation		(allocator.allocate(requirements, MemoryRequirement::Any));
294 		VK_CHECK(vkd.bindImageMemory(device, image, allocation->getMemory(), allocation->getOffset()));
295 		memory[memoryNdx] = safeSharedPtr(allocation.release());
296 	}
297 	return memory;
298 }
299 
createImageViews(const vector<VkImageSp> & images) const300 vector<VkImageViewSp> MultisampleRenderPassTestBase::createImageViews (const vector<VkImageSp>& images) const
301 {
302 	const DeviceInterface&			vkd		= m_context.getDeviceInterface();
303 	VkDevice						device	= m_context.getDevice();
304 	std::vector<VkImageViewSp>		views	(images.size());
305 	const VkImageSubresourceRange	range =
306 	{
307 		VK_IMAGE_ASPECT_COLOR_BIT,
308 		0u,
309 		1u,
310 		0u,
311 		m_layerCount
312 	};
313 
314 	for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++)
315 	{
316 		const VkImageViewCreateInfo pCreateInfo =
317 		{
318 			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
319 			DE_NULL,
320 			0u,
321 			**images[imageNdx],
322 			VK_IMAGE_VIEW_TYPE_2D_ARRAY,
323 			m_format,
324 			makeComponentMappingRGBA(),
325 			range,
326 		};
327 		views[imageNdx] = safeSharedPtr(new Unique<VkImageView>(createImageView(vkd, device, &pCreateInfo)));
328 	}
329 
330 	return views;
331 }
332 
createBuffers() const333 vector<VkBufferSp> MultisampleRenderPassTestBase::createBuffers () const
334 {
335 	const DeviceInterface&		vkd			= m_context.getDeviceInterface();
336 	VkDevice					device		= m_context.getDevice();
337 	std::vector<VkBufferSp>		buffers		(m_attachmentsCount);
338 	const VkDeviceSize			pixelSize	(getPixelSize());
339 	const VkBufferCreateInfo	createInfo =
340 	{
341 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
342 		DE_NULL,
343 		0u,
344 
345 		m_width * m_height * m_layerCount * pixelSize,
346 		VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
347 
348 		VK_SHARING_MODE_EXCLUSIVE,
349 		0u,
350 		DE_NULL
351 	};
352 
353 	for (size_t bufferNdx = 0; bufferNdx < buffers.size(); bufferNdx++)
354 		buffers[bufferNdx] = safeSharedPtr(new Unique<VkBuffer>(createBuffer(vkd, device, &createInfo)));
355 
356 	return buffers;
357 }
358 
createBufferMemory(const vector<VkBufferSp> & buffers) const359 vector<AllocationSp> MultisampleRenderPassTestBase::createBufferMemory (const vector<VkBufferSp>& buffers) const
360 {
361 	const DeviceInterface&					vkd			= m_context.getDeviceInterface();
362 	VkDevice								device		= m_context.getDevice();
363 	Allocator&								allocator	= m_context.getDefaultAllocator();
364 	std::vector<de::SharedPtr<Allocation> >	memory		(buffers.size());
365 
366 	for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++)
367 	{
368 		VkBuffer				buffer			= **buffers[memoryNdx];
369 		VkMemoryRequirements	requirements	= getBufferMemoryRequirements(vkd, device, buffer);
370 		de::MovePtr<Allocation> allocation		(allocator.allocate(requirements, MemoryRequirement::HostVisible));
371 
372 		VK_CHECK(vkd.bindBufferMemory(device, buffer, allocation->getMemory(), allocation->getOffset()));
373 		memory[memoryNdx] = safeSharedPtr(allocation.release());
374 	}
375 	return memory;
376 }
377 
createFramebuffer(const std::vector<VkImageViewSp> multisampleImageViews,const std::vector<VkImageViewSp> singlesampleImageViews,VkRenderPass renderPass) const378 Move<VkFramebuffer> MultisampleRenderPassTestBase::createFramebuffer (const std::vector<VkImageViewSp>	multisampleImageViews,
379 																	  const std::vector<VkImageViewSp>	singlesampleImageViews,
380 																	  VkRenderPass						renderPass) const
381 {
382 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
383 	VkDevice				device	= m_context.getDevice();
384 
385 	std::vector<VkImageView> attachments;
386 	attachments.reserve(multisampleImageViews.size() + singlesampleImageViews.size());
387 
388 	DE_ASSERT(multisampleImageViews.size() == singlesampleImageViews.size());
389 
390 	for (size_t ndx = 0; ndx < multisampleImageViews.size(); ndx++)
391 	{
392 		attachments.push_back(**multisampleImageViews[ndx]);
393 		attachments.push_back(**singlesampleImageViews[ndx]);
394 	}
395 
396 	const VkFramebufferCreateInfo createInfo =
397 	{
398 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
399 		DE_NULL,
400 		0u,
401 
402 		renderPass,
403 		(deUint32)attachments.size(),
404 		&attachments[0],
405 
406 		m_width,
407 		m_height,
408 		m_layerCount
409 	};
410 
411 	return ::createFramebuffer(vkd, device, &createInfo);
412 }
413 
featuresSupported(Context & context,TestConfig config) const414 bool MultisampleRenderPassTestBase::featuresSupported (Context& context, TestConfig config) const
415 {
416 	bool result = ((config.layerCount > 1) && context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER));
417 
418 	const InstanceInterface&				vki				= context.getInstanceInterface();
419 	vk::VkPhysicalDevice					physicalDevice	= context.getPhysicalDevice();
420 	const vk::VkPhysicalDeviceProperties	properties		= vk::getPhysicalDeviceProperties(vki, physicalDevice);
421 
422 	if (config.attachmentCount > properties.limits.maxColorAttachments)
423 		TCU_THROW(NotSupportedError, "Required number of color attachments not supported.");
424 
425 	return result;
426 }
427 
clearAttachments(VkCommandBuffer commandBuffer) const428 void MultisampleRenderPassTestBase::clearAttachments (VkCommandBuffer commandBuffer) const
429 {
430 	const DeviceInterface&			vkd				= m_context.getDeviceInterface();
431 	const tcu::TextureFormat		format			(mapVkFormat(m_format));
432 	const tcu::TextureChannelClass	channelClass	(tcu::getTextureChannelClass(format.type));
433 	VkClearValue					value;
434 
435 	// Clear everything to black
436 	switch (channelClass)
437 	{
438 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
439 			value = makeClearValueColorF32(-1.0f, -1.0f, -1.0f, -1.0f);
440 			break;
441 
442 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
443 			value = makeClearValueColorF32(0.0f, 0.0f, 0.0f, 0.0f);
444 			break;
445 
446 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
447 			value = makeClearValueColorF32(-1.0f, -1.0f, -1.0f, -1.0f);
448 			break;
449 
450 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
451 			value = makeClearValueColorI32(-128, -128, -128, -128);
452 			break;
453 
454 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
455 			value = makeClearValueColorU32(0u, 0u, 0u, 0u);
456 			break;
457 
458 		default:
459 			DE_FATAL("Unknown channel class");
460 	}
461 	std::vector<VkClearAttachment> colors(m_attachmentsCount);
462 	for (deUint32 attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
463 	{
464 		colors[attachmentNdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
465 		colors[attachmentNdx].colorAttachment = attachmentNdx;
466 		colors[attachmentNdx].clearValue = value;
467 	}
468 	const VkClearRect rect =
469 	{
470 		{
471 			{ 0u, 0u },
472 			{ m_width, m_height }
473 		},
474 		0u,
475 		m_layerCount,
476 	};
477 	vkd.cmdClearAttachments(commandBuffer, deUint32(colors.size()), &colors[0], 1u, &rect);
478 }
479 
getPixelSize() const480 VkDeviceSize MultisampleRenderPassTestBase::getPixelSize () const
481 {
482 	const tcu::TextureFormat format(mapVkFormat(m_format));
483 	return format.getPixelSize();
484 }
485 
getFormatThreshold() const486 tcu::Vec4 MultisampleRenderPassTestBase::getFormatThreshold () const
487 {
488 	const tcu::TextureFormat	tcuFormat		(mapVkFormat(m_format));
489 	const deUint32				componentCount	(tcu::getNumUsedChannels(tcuFormat.order));
490 
491 	if (isSnormFormat(m_format))
492 	{
493 		return Vec4((componentCount >= 1) ? 1.5f * getRepresentableDiffSnorm(m_format, 0) : 0.0f,
494 					(componentCount >= 2) ? 1.5f * getRepresentableDiffSnorm(m_format, 1) : 0.0f,
495 					(componentCount >= 3) ? 1.5f * getRepresentableDiffSnorm(m_format, 2) : 0.0f,
496 					(componentCount == 4) ? 1.5f * getRepresentableDiffSnorm(m_format, 3) : 0.0f);
497 	}
498 	else if (isUnormFormat(m_format))
499 	{
500 		return Vec4((componentCount >= 1) ? 1.5f * getRepresentableDiffUnorm(m_format, 0) : 0.0f,
501 					(componentCount >= 2) ? 1.5f * getRepresentableDiffUnorm(m_format, 1) : 0.0f,
502 					(componentCount >= 3) ? 1.5f * getRepresentableDiffUnorm(m_format, 2) : 0.0f,
503 					(componentCount == 4) ? 1.5f * getRepresentableDiffUnorm(m_format, 3) : 0.0f);
504 	}
505 	else if (isFloatFormat(m_format))
506 	{
507 		return (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT) ? tcu::Vec4(0.005f) : Vec4(0.00001f);
508 	}
509 	else
510 		return Vec4(0.001f);
511 }
512 
sampleCountBitFromSampleCount(deUint32 count) const513 VkSampleCountFlagBits MultisampleRenderPassTestBase::sampleCountBitFromSampleCount (deUint32 count) const
514 {
515 	switch (count)
516 	{
517 		case 1:  return VK_SAMPLE_COUNT_1_BIT;
518 		case 2:  return VK_SAMPLE_COUNT_2_BIT;
519 		case 4:  return VK_SAMPLE_COUNT_4_BIT;
520 		case 8:  return VK_SAMPLE_COUNT_8_BIT;
521 		case 16: return VK_SAMPLE_COUNT_16_BIT;
522 		case 32: return VK_SAMPLE_COUNT_32_BIT;
523 		case 64: return VK_SAMPLE_COUNT_64_BIT;
524 
525 		default:
526 			DE_FATAL("Invalid sample count");
527 			return (VkSampleCountFlagBits)0x0;
528 	}
529 }
530 
logImage(const std::string & name,const tcu::ConstPixelBufferAccess & image) const531 void MultisampleRenderPassTestBase::logImage (const std::string& name, const tcu::ConstPixelBufferAccess& image) const
532 {
533 	m_context.getTestContext().getLog() << tcu::LogImage(name.c_str(), name.c_str(), image);
534 
535 	for (deUint32 layerNdx = 0; layerNdx < m_layerCount; ++layerNdx)
536 	{
537 		const std::string			layerName	(name + " Layer:" + de::toString(layerNdx));
538 		tcu::ConstPixelBufferAccess	layerImage	(image.getFormat(), m_width, m_height, 1, image.getPixelPtr(0, 0, layerNdx));
539 
540 		m_context.getTestContext().getLog() << tcu::LogImage(layerName.c_str(), layerName.c_str(), layerImage);
541 	}
542 }
543 
544 class MultisampleRenderPassTestInstance : public MultisampleRenderPassTestBase
545 {
546 public:
547 	MultisampleRenderPassTestInstance	(Context& context, TestConfig config);
548 	~MultisampleRenderPassTestInstance	(void);
549 
550 	tcu::TestStatus			iterate		(void);
551 
552 private:
553 
554 	template<typename RenderpassSubpass>
555 	void					submit						(void);
556 	void					submitSwitch				(RenderPassType renderPassType);
557 	void					verify						(void);
558 
559 	template<typename RenderPassTrait>
560 	Move<VkRenderPass>		createRenderPass			(bool usedResolveAttachment);
561 	Move<VkRenderPass>		createRenderPassSwitch		(bool usedResolveAttachment);
562 	Move<VkRenderPass>		createRenderPassCompatible	(void);
563 	Move<VkPipelineLayout>	createRenderPipelineLayout	(void);
564 	Move<VkPipeline>		createRenderPipeline		(void);
565 
566 private:
567 
568 	const std::vector<VkImageSp>		m_multisampleImages;
569 	const std::vector<AllocationSp>		m_multisampleImageMemory;
570 	const std::vector<VkImageViewSp>	m_multisampleImageViews;
571 
572 	const std::vector<VkImageSp>		m_singlesampleImages;
573 	const std::vector<AllocationSp>		m_singlesampleImageMemory;
574 	const std::vector<VkImageViewSp>	m_singlesampleImageViews;
575 
576 	const Unique<VkRenderPass>			m_renderPass;
577 	const Unique<VkRenderPass>			m_renderPassCompatible;
578 	const Unique<VkFramebuffer>			m_framebuffer;
579 
580 	const Unique<VkPipelineLayout>		m_renderPipelineLayout;
581 	const Unique<VkPipeline>			m_renderPipeline;
582 
583 	const std::vector<VkBufferSp>		m_buffers;
584 	const std::vector<AllocationSp>		m_bufferMemory;
585 
586 	const Unique<VkCommandPool>			m_commandPool;
587 	tcu::TextureLevel					m_sum;
588 	tcu::TextureLevel					m_sumSrgb;
589 	deUint32							m_sampleMask;
590 	tcu::ResultCollector				m_resultCollector;
591 };
592 
MultisampleRenderPassTestInstance(Context & context,TestConfig config)593 MultisampleRenderPassTestInstance::MultisampleRenderPassTestInstance (Context& context, TestConfig config)
594 	: MultisampleRenderPassTestBase(context, config)
595 
596 	, m_multisampleImages		(createImages(m_sampleCount, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
597 	, m_multisampleImageMemory	(createImageMemory(m_multisampleImages))
598 	, m_multisampleImageViews	(createImageViews(m_multisampleImages))
599 
600 	, m_singlesampleImages		(createImages(VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT))
601 	, m_singlesampleImageMemory	(createImageMemory(m_singlesampleImages))
602 	, m_singlesampleImageViews	(createImageViews(m_singlesampleImages))
603 
604 	// The "normal" render pass has an unused resolve attachment when testing compatibility.
605 	, m_renderPass				(createRenderPassSwitch(!m_testCompatibility))
606 	, m_renderPassCompatible	(createRenderPassCompatible())
607 	, m_framebuffer				(createFramebuffer(m_multisampleImageViews, m_singlesampleImageViews, *m_renderPass))
608 
609 	, m_renderPipelineLayout	(createRenderPipelineLayout())
610 	, m_renderPipeline			(createRenderPipeline())
611 
612 	, m_buffers					(createBuffers())
613 	, m_bufferMemory			(createBufferMemory(m_buffers))
614 
615 	, m_commandPool				(createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex()))
616 	, m_sum						(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), m_width, m_height, m_layerCount)
617 	, m_sumSrgb					(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), m_width, m_height, m_layerCount)
618 	, m_sampleMask				(0x0u)
619 {
620 	tcu::clear(m_sum.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 0.0f));
621 	tcu::clear(m_sumSrgb.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 0.0f));
622 }
623 
~MultisampleRenderPassTestInstance(void)624 MultisampleRenderPassTestInstance::~MultisampleRenderPassTestInstance (void)
625 {
626 }
627 
628 template<typename RenderpassSubpass>
submit(void)629 void MultisampleRenderPassTestInstance::submit (void)
630 {
631 	const DeviceInterface&								vkd					(m_context.getDeviceInterface());
632 	const VkDevice										device				(m_context.getDevice());
633 	const Unique<VkCommandBuffer>						commandBuffer		(allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
634 	const typename RenderpassSubpass::SubpassBeginInfo	subpassBeginInfo	(DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
635 	const typename RenderpassSubpass::SubpassEndInfo	subpassEndInfo		(DE_NULL);
636 
637 	beginCommandBuffer(vkd, *commandBuffer);
638 
639 	// Memory barriers between previous copies and rendering
640 	{
641 		std::vector<VkImageMemoryBarrier> barriers;
642 
643 		for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++)
644 		{
645 			const VkImageMemoryBarrier barrier =
646 			{
647 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
648 				DE_NULL,
649 
650 				VK_ACCESS_TRANSFER_READ_BIT,
651 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
652 
653 				VK_IMAGE_LAYOUT_UNDEFINED,
654 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
655 
656 				VK_QUEUE_FAMILY_IGNORED,
657 				VK_QUEUE_FAMILY_IGNORED,
658 
659 				**m_singlesampleImages[dstNdx],
660 				{
661 					VK_IMAGE_ASPECT_COLOR_BIT,
662 					0u,
663 					1u,
664 					0u,
665 					m_layerCount
666 				}
667 			};
668 
669 			barriers.push_back(barrier);
670 		}
671 
672 		vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]);
673 	}
674 
675 	{
676 		const VkRenderPassBeginInfo beginInfo =
677 		{
678 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
679 			DE_NULL,
680 
681 			m_testCompatibility ? *m_renderPassCompatible : *m_renderPass,
682 			*m_framebuffer,
683 
684 			{
685 				{ 0u, 0u },
686 				{ m_width, m_height }
687 			},
688 
689 			0u,
690 			DE_NULL
691 		};
692 		RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
693 	}
694 
695 	// Clear everything to black
696 	clearAttachments(*commandBuffer);
697 
698 	// Render black samples
699 	{
700 		vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline);
701 		vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(m_sampleMask), &m_sampleMask);
702 		vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
703 	}
704 
705 	RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
706 
707 	for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++)
708 		copyImageToBuffer(vkd, *commandBuffer, **m_singlesampleImages[dstNdx], **m_buffers[dstNdx], tcu::IVec2(m_width, m_height), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_layerCount);
709 
710 	endCommandBuffer(vkd, *commandBuffer);
711 
712 	submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), *commandBuffer);
713 
714 	for (size_t memoryBufferNdx = 0; memoryBufferNdx < m_bufferMemory.size(); memoryBufferNdx++)
715 		invalidateMappedMemoryRange(vkd, device, m_bufferMemory[memoryBufferNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
716 }
717 
submitSwitch(RenderPassType renderPassType)718 void MultisampleRenderPassTestInstance::submitSwitch (RenderPassType renderPassType)
719 {
720 	switch (renderPassType)
721 	{
722 		case RENDERPASS_TYPE_LEGACY:
723 			submit<RenderpassSubpass1>();
724 			break;
725 		case RENDERPASS_TYPE_RENDERPASS2:
726 			submit<RenderpassSubpass2>();
727 			break;
728 		default:
729 			TCU_THROW(InternalError, "Impossible");
730 	}
731 }
732 
verify(void)733 void MultisampleRenderPassTestInstance::verify (void)
734 {
735 	const Vec4							errorColor		(1.0f, 0.0f, 0.0f, 1.0f);
736 	const Vec4							okColor			(0.0f, 1.0f, 0.0f, 1.0f);
737 	const tcu::TextureFormat			format			(mapVkFormat(m_format));
738 	const tcu::TextureChannelClass		channelClass	(tcu::getTextureChannelClass(format.type));
739 
740 	std::vector<tcu::ConstPixelBufferAccess> accesses;
741 	for (deUint32 attachmentIdx = 0; attachmentIdx < m_attachmentsCount; ++attachmentIdx)
742 	{
743 		void* const ptr = m_bufferMemory[attachmentIdx]->getHostPtr();
744 		accesses.push_back(tcu::ConstPixelBufferAccess(format, m_width, m_height, m_layerCount, ptr));
745 	}
746 
747 	tcu::TextureLevel					errorMask		(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height, m_layerCount);
748 	tcu::TestLog&						log				(m_context.getTestContext().getLog());
749 
750 	switch (channelClass)
751 	{
752 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
753 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
754 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
755 		{
756 			const int	componentCount	(tcu::getNumUsedChannels(format.order));
757 			bool		isOk			= true;
758 			float		clearValue;
759 			float		renderValue;
760 
761 			switch (channelClass)
762 			{
763 				case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
764 				case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
765 					clearValue	= -1.0f;
766 					renderValue	= 1.0f;
767 					break;
768 
769 				case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
770 					clearValue	= 0.0f;
771 					renderValue	= 1.0f;
772 					break;
773 
774 				default:
775 					clearValue	= 0.0f;
776 					renderValue	= 0.0f;
777 					DE_FATAL("Unknown channel class");
778 			}
779 
780 			for (deUint32 z = 0; z < m_layerCount; z++)
781 			for (deUint32 y = 0; y < m_height; y++)
782 			for (deUint32 x = 0; x < m_width; x++)
783 			{
784 				// Color has to be black if no samples were covered, white if all samples were covered or same in every attachment
785 				const Vec4	firstColor	(accesses[0].getPixel(x, y, z));
786 				const Vec4	refColor	(m_sampleMask == 0x0u
787 										? Vec4(clearValue,
788 												componentCount > 1 ? clearValue : 0.0f,
789 												componentCount > 2 ? clearValue : 0.0f,
790 												componentCount > 3 ? clearValue : 1.0f)
791 										: m_sampleMask == ((0x1u << m_sampleCount) - 1u)
792 										? Vec4(renderValue,
793 												componentCount > 1 ? renderValue : 0.0f,
794 												componentCount > 2 ? renderValue : 0.0f,
795 												componentCount > 3 ? renderValue : 1.0f)
796 										: firstColor);
797 
798 				errorMask.getAccess().setPixel(okColor, x, y, z);
799 
800 				for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
801 				{
802 					const Vec4 color (accesses[attachmentNdx].getPixel(x, y, z));
803 
804 					if (refColor != color)
805 					{
806 						isOk = false;
807 						errorMask.getAccess().setPixel(errorColor, x, y, z);
808 						break;
809 					}
810 				}
811 
812 				{
813 					const Vec4 old = m_sum.getAccess().getPixel(x, y, z);
814 					m_sum.getAccess().setPixel(old + (tcu::isSRGB(format) ? tcu::sRGBToLinear(firstColor) : firstColor), x, y, z);
815 
816 					const Vec4 oldSrgb = m_sumSrgb.getAccess().getPixel(x, y, z);
817 					m_sumSrgb.getAccess().setPixel(oldSrgb + firstColor, x, y, z);
818 				}
819 			}
820 
821 			if (!isOk)
822 			{
823 				const std::string			sectionName	("ResolveVerifyWithMask" + de::toString(m_sampleMask));
824 				const tcu::ScopedLogSection	section		(log, sectionName, sectionName);
825 
826 				for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
827 					logImage(std::string("Attachment") + de::toString(attachmentNdx), accesses[attachmentNdx]);
828 
829 				logImage("ErrorMask", errorMask.getAccess());
830 
831 				if (m_sampleMask == 0x0u)
832 				{
833 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage;
834 					m_resultCollector.fail("Empty sample mask didn't produce correct pixel values");
835 				}
836 				else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u))
837 				{
838 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage;
839 					m_resultCollector.fail("Full sample mask didn't produce correct pixel values");
840 				}
841 				else
842 				{
843 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve is inconsistent between attachments" << tcu::TestLog::EndMessage;
844 					m_resultCollector.fail("Resolve is inconsistent between attachments");
845 				}
846 			}
847 			break;
848 		}
849 
850 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
851 		{
852 			const int		componentCount			(tcu::getNumUsedChannels(format.order));
853 			const UVec4		bitDepth				(tcu::getTextureFormatBitDepth(format).cast<deUint32>());
854 			const UVec4		renderValue				(tcu::select((UVec4(1u) << tcu::min(UVec4(8u), bitDepth)) - UVec4(1u),
855 																  UVec4(0u, 0u, 0u, 1u),
856 																  tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount))));
857 			const UVec4		clearValue				(tcu::select(UVec4(0u),
858 																 UVec4(0u, 0u, 0u, 1u),
859 																 tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount))));
860 			bool			unexpectedValues		= false;
861 			bool			inconsistentComponents	= false;
862 			bool			inconsistentAttachments	= false;
863 
864 			for (deUint32 z = 0; z < m_layerCount; z++)
865 			for (deUint32 y = 0; y < m_height; y++)
866 			for (deUint32 x = 0; x < m_width; x++)
867 			{
868 				// Color has to be all zeros if no samples were covered, all 255 if all samples were covered or consistent across all attachments
869 				const UVec4 refColor	(m_sampleMask == 0x0u
870 										? clearValue
871 										: m_sampleMask == ((0x1u << m_sampleCount) - 1u)
872 										? renderValue
873 										: accesses[0].getPixelUint(x, y, z));
874 				bool		isOk		= true;
875 
876 				// If reference value was taken from first attachment, check that it is valid value i.e. clear or render value
877 				if (m_sampleMask != 0x0u && m_sampleMask != ((0x1u << m_sampleCount) - 1u))
878 				{
879 					// Each component must be resolved same way
880 					const BVec4		isRenderValue			(refColor == renderValue);
881 					const BVec4		isClearValue			(refColor == clearValue);
882 					const bool		unexpectedValue			(tcu::anyNotEqual(tcu::logicalOr(isRenderValue, isClearValue), BVec4(true)));
883 					const bool		inconsistentComponent	(!(tcu::allEqual(isRenderValue, BVec4(true)) || tcu::allEqual(isClearValue, BVec4(true))));
884 
885 					unexpectedValues		|= unexpectedValue;
886 					inconsistentComponents	|= inconsistentComponent;
887 
888 					if (unexpectedValue || inconsistentComponent)
889 						isOk = false;
890 				}
891 
892 				for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
893 				{
894 					const UVec4 color (accesses[attachmentNdx].getPixelUint(x, y, z));
895 
896 					if (refColor != color)
897 					{
898 						isOk = false;
899 						inconsistentAttachments = true;
900 						break;
901 					}
902 				}
903 
904 				errorMask.getAccess().setPixel((isOk ? okColor : errorColor), x, y, z);
905 			}
906 
907 			if (unexpectedValues || inconsistentComponents || inconsistentAttachments)
908 			{
909 				const std::string			sectionName	("ResolveVerifyWithMask" + de::toString(m_sampleMask));
910 				const tcu::ScopedLogSection	section		(log, sectionName, sectionName);
911 
912 				for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
913 					logImage(std::string("Attachment") + de::toString(attachmentNdx), accesses[attachmentNdx]);
914 
915 				logImage("ErrorMask", errorMask.getAccess());
916 
917 				if (m_sampleMask == 0x0u)
918 				{
919 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage;
920 					m_resultCollector.fail("Empty sample mask didn't produce correct pixels");
921 				}
922 				else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u))
923 				{
924 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage;
925 					m_resultCollector.fail("Full sample mask didn't produce correct pixels");
926 				}
927 				else
928 				{
929 					if (unexpectedValues)
930 					{
931 						m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve produced unexpected values i.e. not " << clearValue << " or " << renderValue << tcu::TestLog::EndMessage;
932 						m_resultCollector.fail("Resolve produced unexpected values");
933 					}
934 
935 					if (inconsistentComponents)
936 					{
937 						m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different components of attachment were resolved to different values." << tcu::TestLog::EndMessage;
938 						m_resultCollector.fail("Different components of attachment were resolved to different values.");
939 					}
940 
941 					if (inconsistentAttachments)
942 					{
943 						m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different attachments were resolved to different values." << tcu::TestLog::EndMessage;
944 						m_resultCollector.fail("Different attachments were resolved to different values.");
945 					}
946 				}
947 			}
948 			break;
949 		}
950 
951 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
952 		{
953 			const int		componentCount			(tcu::getNumUsedChannels(format.order));
954 			const IVec4		bitDepth				(tcu::getTextureFormatBitDepth(format));
955 			const IVec4		renderValue				(tcu::select((IVec4(1) << (tcu::min(IVec4(8), bitDepth) - IVec4(1))) - IVec4(1),
956 																  IVec4(0, 0, 0, 1),
957 																  tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount))));
958 			const IVec4		clearValue				(tcu::select(-(IVec4(1) << (tcu::min(IVec4(8), bitDepth) - IVec4(1))),
959 																 IVec4(0, 0, 0, 1),
960 																 tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount))));
961 			bool			unexpectedValues		= false;
962 			bool			inconsistentComponents	= false;
963 			bool			inconsistentAttachments	= false;
964 
965 			for (deUint32 z = 0; z < m_layerCount; z++)
966 			for (deUint32 y = 0; y < m_height; y++)
967 			for (deUint32 x = 0; x < m_width; x++)
968 			{
969 				// Color has to be all zeros if no samples were covered, all 255 if all samples were covered or consistent across all attachments
970 				const IVec4 refColor	(m_sampleMask == 0x0u
971 										? clearValue
972 										: m_sampleMask == ((0x1u << m_sampleCount) - 1u)
973 										? renderValue
974 										: accesses[0].getPixelInt(x, y, z));
975 				bool		isOk		= true;
976 
977 				// If reference value was taken from first attachment, check that it is valid value i.e. clear or render value
978 				if (m_sampleMask != 0x0u && m_sampleMask != ((0x1u << m_sampleCount) - 1u))
979 				{
980 					// Each component must be resolved same way
981 					const BVec4		isRenderValue			(refColor == renderValue);
982 					const BVec4		isClearValue			(refColor == clearValue);
983 					const bool		unexpectedValue			(tcu::anyNotEqual(tcu::logicalOr(isRenderValue, isClearValue), BVec4(true)));
984 					const bool		inconsistentComponent	(!(tcu::allEqual(isRenderValue, BVec4(true)) || tcu::allEqual(isClearValue, BVec4(true))));
985 
986 					unexpectedValues		|= unexpectedValue;
987 					inconsistentComponents	|= inconsistentComponent;
988 
989 					if (unexpectedValue || inconsistentComponent)
990 						isOk = false;
991 				}
992 
993 				for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
994 				{
995 					const IVec4 color (accesses[attachmentNdx].getPixelInt(x, y, z));
996 
997 					if (refColor != color)
998 					{
999 						isOk = false;
1000 						inconsistentAttachments = true;
1001 						break;
1002 					}
1003 				}
1004 
1005 				errorMask.getAccess().setPixel((isOk ? okColor : errorColor), x, y, z);
1006 			}
1007 
1008 			if (unexpectedValues || inconsistentComponents || inconsistentAttachments)
1009 			{
1010 				const std::string			sectionName	("ResolveVerifyWithMask" + de::toString(m_sampleMask));
1011 				const tcu::ScopedLogSection	section		(log, sectionName, sectionName);
1012 
1013 				for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
1014 					logImage(std::string("Attachment") + de::toString(attachmentNdx), accesses[attachmentNdx]);
1015 
1016 				logImage("ErrorMask", errorMask.getAccess());
1017 
1018 				if (m_sampleMask == 0x0u)
1019 				{
1020 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage;
1021 					m_resultCollector.fail("Empty sample mask didn't produce correct pixels");
1022 				}
1023 				else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u))
1024 				{
1025 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage;
1026 					m_resultCollector.fail("Full sample mask didn't produce correct pixels");
1027 				}
1028 				else
1029 				{
1030 					if (unexpectedValues)
1031 					{
1032 						m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve produced unexpected values i.e. not " << clearValue << " or " << renderValue << tcu::TestLog::EndMessage;
1033 						m_resultCollector.fail("Resolve produced unexpected values");
1034 					}
1035 
1036 					if (inconsistentComponents)
1037 					{
1038 						m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different components of attachment were resolved to different values." << tcu::TestLog::EndMessage;
1039 						m_resultCollector.fail("Different components of attachment were resolved to different values.");
1040 					}
1041 
1042 					if (inconsistentAttachments)
1043 					{
1044 						m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different attachments were resolved to different values." << tcu::TestLog::EndMessage;
1045 						m_resultCollector.fail("Different attachments were resolved to different values.");
1046 					}
1047 				}
1048 			}
1049 			break;
1050 		}
1051 
1052 		default:
1053 			DE_FATAL("Unknown channel class");
1054 	}
1055 }
1056 
iterate(void)1057 tcu::TestStatus MultisampleRenderPassTestInstance::iterate (void)
1058 {
1059 	if (m_sampleMask == 0u)
1060 	{
1061 		const tcu::TextureFormat		format			(mapVkFormat(m_format));
1062 		const tcu::TextureChannelClass	channelClass	(tcu::getTextureChannelClass(format.type));
1063 		tcu::TestLog&					log				(m_context.getTestContext().getLog());
1064 
1065 		switch (channelClass)
1066 		{
1067 			case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1068 				log << TestLog::Message << "Clearing target to zero and rendering 255 pixels with every possible sample mask" << TestLog::EndMessage;
1069 				break;
1070 
1071 			case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1072 				log << TestLog::Message << "Clearing target to -128 and rendering 127 pixels with every possible sample mask" << TestLog::EndMessage;
1073 				break;
1074 
1075 			case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1076 			case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1077 			case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1078 				log << TestLog::Message << "Clearing target to black and rendering white pixels with every possible sample mask" << TestLog::EndMessage;
1079 				break;
1080 
1081 			default:
1082 				DE_FATAL("Unknown channel class");
1083 		}
1084 	}
1085 
1086 	submitSwitch(m_renderPassType);
1087 	verify();
1088 
1089 	if (m_sampleMask == ((0x1u << m_sampleCount) - 1u))
1090 	{
1091 		const tcu::TextureFormat		format			(mapVkFormat(m_format));
1092 		const tcu::TextureChannelClass	channelClass	(tcu::getTextureChannelClass(format.type));
1093 		const Vec4						threshold		(getFormatThreshold());
1094 		tcu::TestLog&					log				(m_context.getTestContext().getLog());
1095 
1096 		if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT
1097 				|| channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT
1098 				|| channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
1099 		{
1100 			const int			componentCount	(tcu::getNumUsedChannels(format.order));
1101 			const Vec4			errorColor		(1.0f, 0.0f, 0.0f, 1.0f);
1102 			const Vec4			okColor			(0.0f, 1.0f, 0.0f, 1.0f);
1103 			tcu::TextureLevel	errorMask		(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height, m_layerCount);
1104 			bool				isOk			= true;
1105 			Vec4				maxDiff			(0.0f);
1106 			Vec4				expectedAverage;
1107 
1108 			switch (channelClass)
1109 			{
1110 				case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1111 				{
1112 					expectedAverage = Vec4(0.5f, componentCount > 1 ? 0.5f : 0.0f, componentCount > 2 ? 0.5f : 0.0f, componentCount > 3 ? 0.5f : 1.0f);
1113 					break;
1114 				}
1115 
1116 				case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1117 				case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1118 				{
1119 					expectedAverage = Vec4(0.0f, 0.0f, 0.0f, componentCount > 3 ? 0.0f : 1.0f);
1120 					break;
1121 				}
1122 
1123 				default:
1124 					DE_FATAL("Unknown channel class");
1125 			}
1126 
1127 			for (deUint32 z = 0; z < m_layerCount; z++)
1128 			for (deUint32 y = 0; y < m_height; y++)
1129 			for (deUint32 x = 0; x < m_width; x++)
1130 			{
1131 				const Vec4	sum		(m_sum.getAccess().getPixel(x, y, z));
1132 				const Vec4	average	(sum / Vec4((float)(0x1u << m_sampleCount)));
1133 				const Vec4	diff	(tcu::abs(average - expectedAverage));
1134 
1135 				m_sum.getAccess().setPixel(average, x, y, z);
1136 				errorMask.getAccess().setPixel(okColor, x, y, z);
1137 
1138 				bool failThreshold;
1139 
1140 				if (!tcu::isSRGB(format))
1141 				{
1142 					failThreshold = (diff[0] > threshold.x()
1143 										|| diff[1] > threshold.y()
1144 										|| diff[2] > threshold.z()
1145 										|| diff[3] > threshold.w());
1146 				}
1147 				else
1148 				{
1149 					const Vec4	sumSrgb(m_sumSrgb.getAccess().getPixel(x, y, z));
1150 					const Vec4	averageSrgb(sumSrgb / Vec4((float)(0x1u << m_sampleCount)));
1151 					const Vec4	diffSrgb(tcu::abs(averageSrgb - expectedAverage));
1152 
1153 					m_sumSrgb.getAccess().setPixel(averageSrgb, x, y, z);
1154 
1155 					// Spec doesn't restrict implementation to downsample in linear color space. So, comparing both non linear and
1156 					// linear diff's in case of srgb formats.
1157 					failThreshold = ((diff[0] > threshold.x()
1158 										|| diff[1] > threshold.y()
1159 										|| diff[2] > threshold.z()
1160 										|| diff[3] > threshold.w()) &&
1161 									(diffSrgb[0] > threshold.x()
1162 										|| diffSrgb[1] > threshold.y()
1163 										|| diffSrgb[2] > threshold.z()
1164 										|| diffSrgb[3] > threshold.w()));
1165 
1166 				}
1167 
1168 				if (failThreshold)
1169 				{
1170 					isOk	= false;
1171 					maxDiff	= tcu::max(maxDiff, diff);
1172 					errorMask.getAccess().setPixel(errorColor, x, y, z);
1173 				}
1174 			}
1175 
1176 			log << TestLog::Image("Average resolved values in attachment 0", "Average resolved values in attachment 0", m_sum);
1177 
1178 			if (!isOk)
1179 			{
1180 				std::stringstream	message;
1181 
1182 				m_context.getTestContext().getLog() << tcu::LogImage("ErrorMask", "ErrorMask", errorMask.getAccess());
1183 
1184 				message << "Average resolved values differ from expected average values by more than ";
1185 
1186 				switch (componentCount)
1187 				{
1188 					case 1:
1189 						message << threshold.x();
1190 						break;
1191 					case 2:
1192 						message << "vec2" << Vec2(threshold.x(), threshold.y());
1193 						break;
1194 					case 3:
1195 						message << "vec3" << Vec3(threshold.x(), threshold.y(), threshold.z());
1196 						break;
1197 					default:
1198 						message << "vec4" << threshold;
1199 				}
1200 
1201 				message << ". Max diff " << maxDiff;
1202 				log << TestLog::Message << message.str() << TestLog::EndMessage;
1203 
1204 				m_resultCollector.fail("Average resolved values differ from expected average values");
1205 			}
1206 		}
1207 
1208 		return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1209 	}
1210 	else
1211 	{
1212 		m_sampleMask++;
1213 		return tcu::TestStatus::incomplete();
1214 	}
1215 }
1216 
1217 template<typename RenderPassTrait>
createRenderPass(bool usedResolveAttachment)1218 Move<VkRenderPass> MultisampleRenderPassTestInstance::createRenderPass (bool usedResolveAttachment)
1219 {
1220 	// make name for RenderPass1Trait or RenderPass2Trait shorter
1221 	typedef RenderPassTrait RPT;
1222 	typedef typename RPT::AttDesc				AttDesc;
1223 	typedef typename RPT::AttRef				AttRef;
1224 	typedef typename RPT::SubpassDesc			SubpassDesc;
1225 	typedef typename RPT::RenderPassCreateInfo	RenderPassCreateInfo;
1226 
1227 	const DeviceInterface&	vkd						= m_context.getDeviceInterface();
1228 	VkDevice				device					= m_context.getDevice();
1229 	std::vector<AttDesc>	attachments;
1230 	std::vector<AttRef>		colorAttachmentRefs;
1231 	std::vector<AttRef>		resolveAttachmentRefs;
1232 
1233 	for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
1234 	{
1235 		{
1236 			const AttDesc multisampleAttachment
1237 			(
1238 															// sType
1239 				DE_NULL,									// pNext
1240 				0u,											// flags
1241 				m_format,									// format
1242 				m_sampleCount,								// samples
1243 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// loadOp
1244 				VK_ATTACHMENT_STORE_OP_DONT_CARE,			// storeOp
1245 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// stencilLoadOp
1246 				VK_ATTACHMENT_STORE_OP_DONT_CARE,			// stencilStoreOp
1247 				VK_IMAGE_LAYOUT_UNDEFINED,					// initialLayout
1248 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// finalLayout
1249 			);
1250 			const AttRef attachmentRef
1251 			(
1252 															// sType
1253 				DE_NULL,									// pNext
1254 				(deUint32)attachments.size(),				// attachment
1255 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// layout
1256 				0u											// aspectMask
1257 			);
1258 			colorAttachmentRefs.push_back(attachmentRef);
1259 			attachments.push_back(multisampleAttachment);
1260 		}
1261 		{
1262 			const AttDesc singlesampleAttachment
1263 			(
1264 															// sType
1265 				DE_NULL,									// pNext
1266 				0u,											// flags
1267 				m_format,									// format
1268 				VK_SAMPLE_COUNT_1_BIT,						// samples
1269 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// loadOp
1270 				VK_ATTACHMENT_STORE_OP_STORE,				// storeOp
1271 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// stencilLoadOp
1272 				VK_ATTACHMENT_STORE_OP_DONT_CARE,			// stencilStoreOp
1273 				VK_IMAGE_LAYOUT_UNDEFINED,					// initialLayout
1274 				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL		// finalLayout
1275 			);
1276 			const auto attachmentId = (usedResolveAttachment ? static_cast<deUint32>(attachments.size()) : VK_ATTACHMENT_UNUSED);
1277 			const AttRef attachmentRef
1278 			(
1279 															// sType
1280 				DE_NULL,									// pNext
1281 				attachmentId,								// attachment
1282 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// layout
1283 				0u											// aspectMask
1284 			);
1285 			resolveAttachmentRefs.push_back(attachmentRef);
1286 			attachments.push_back(singlesampleAttachment);
1287 		}
1288 	}
1289 
1290 	DE_ASSERT(colorAttachmentRefs.size() == resolveAttachmentRefs.size());
1291 	DE_ASSERT(attachments.size() == colorAttachmentRefs.size() + resolveAttachmentRefs.size());
1292 
1293 	const SubpassDesc subpass
1294 	(
1295 														// sType
1296 		DE_NULL,										// pNext
1297 		(VkSubpassDescriptionFlags)0,					// flags
1298 		VK_PIPELINE_BIND_POINT_GRAPHICS,				// pipelineBindPoint
1299 		0u,												// viewMask
1300 		0u,												// inputAttachmentCount
1301 		DE_NULL,										// pInputAttachments
1302 		(deUint32)colorAttachmentRefs.size(),			// colorAttachmentCount
1303 		&colorAttachmentRefs[0],						// pColorAttachments
1304 		&resolveAttachmentRefs[0],						// pResolveAttachments
1305 		DE_NULL,										// pDepthStencilAttachment
1306 		0u,												// preserveAttachmentCount
1307 		DE_NULL											// pPreserveAttachments
1308 	);
1309 	const RenderPassCreateInfo renderPassCreator
1310 	(
1311 														// sType
1312 		DE_NULL,										// pNext
1313 		(VkRenderPassCreateFlags)0u,					// flags
1314 		(deUint32)attachments.size(),					// attachmentCount
1315 		&attachments[0],								// pAttachments
1316 		1u,												// subpassCount
1317 		&subpass,										// pSubpasses
1318 		0u,												// dependencyCount
1319 		DE_NULL,										// pDependencies
1320 		0u,												// correlatedViewMaskCount
1321 		DE_NULL											// pCorrelatedViewMasks
1322 	);
1323 
1324 	return renderPassCreator.createRenderPass(vkd, device);
1325 }
1326 
createRenderPassSwitch(bool usedResolveAttachment)1327 Move<VkRenderPass> MultisampleRenderPassTestInstance::createRenderPassSwitch (bool usedResolveAttachment)
1328 {
1329 	switch (m_renderPassType)
1330 	{
1331 		case RENDERPASS_TYPE_LEGACY:
1332 			return createRenderPass<RenderPass1Trait>(usedResolveAttachment);
1333 		case RENDERPASS_TYPE_RENDERPASS2:
1334 			return createRenderPass<RenderPass2Trait>(usedResolveAttachment);
1335 		default:
1336 			TCU_THROW(InternalError, "Impossible");
1337 	}
1338 }
1339 
createRenderPassCompatible(void)1340 Move<VkRenderPass> MultisampleRenderPassTestInstance::createRenderPassCompatible (void)
1341 {
1342 	if (m_testCompatibility)
1343 	{
1344 		// The compatible render pass is always created with a used resolve attachment.
1345 		return createRenderPassSwitch(true);
1346 	}
1347 	else
1348 	{
1349 		return {};
1350 	}
1351 }
1352 
createRenderPipelineLayout(void)1353 Move<VkPipelineLayout> MultisampleRenderPassTestInstance::createRenderPipelineLayout (void)
1354 {
1355 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
1356 	VkDevice				device	= m_context.getDevice();
1357 
1358 	const VkPushConstantRange pushConstant =
1359 	{
1360 		VK_SHADER_STAGE_FRAGMENT_BIT,
1361 		0u,
1362 		4u
1363 	};
1364 	const VkPipelineLayoutCreateInfo createInfo =
1365 	{
1366 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1367 		DE_NULL,
1368 		(vk::VkPipelineLayoutCreateFlags)0,
1369 
1370 		0u,
1371 		DE_NULL,
1372 
1373 		1u,
1374 		&pushConstant
1375 	};
1376 
1377 	return createPipelineLayout(vkd, device, &createInfo);
1378 }
1379 
createRenderPipeline(void)1380 Move<VkPipeline> MultisampleRenderPassTestInstance::createRenderPipeline (void)
1381 {
1382 	const DeviceInterface&			vkd						= m_context.getDeviceInterface();
1383 	VkDevice						device					= m_context.getDevice();
1384 	const vk::BinaryCollection&		binaryCollection		= m_context.getBinaryCollection();
1385 	const Unique<VkShaderModule>	vertexShaderModule		(createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u));
1386 	const Unique<VkShaderModule>	fragmentShaderModule	(createShaderModule(vkd, device, binaryCollection.get("quad-frag"), 0u));
1387 	const Move<VkShaderModule>		geometryShaderModule	(m_layerCount == 1 ? Move<VkShaderModule>() : createShaderModule(vkd, device, binaryCollection.get("geom"), 0u));
1388 	// Disable blending
1389 	const VkPipelineColorBlendAttachmentState attachmentBlendState =
1390 	{
1391 		VK_FALSE,
1392 		VK_BLEND_FACTOR_SRC_ALPHA,
1393 		VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
1394 		VK_BLEND_OP_ADD,
1395 		VK_BLEND_FACTOR_ONE,
1396 		VK_BLEND_FACTOR_ONE,
1397 		VK_BLEND_OP_ADD,
1398 		VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
1399 	};
1400 	std::vector<VkPipelineColorBlendAttachmentState>	attachmentBlendStates(m_attachmentsCount, attachmentBlendState);
1401 	const VkPipelineVertexInputStateCreateInfo			vertexInputState =
1402 	{
1403 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1404 		DE_NULL,
1405 		(VkPipelineVertexInputStateCreateFlags)0u,
1406 
1407 		0u,
1408 		DE_NULL,
1409 
1410 		0u,
1411 		DE_NULL
1412 	};
1413 	const tcu::UVec2				renderArea	(m_width, m_height);
1414 	const std::vector<VkViewport>	viewports	(1, makeViewport(renderArea));
1415 	const std::vector<VkRect2D>		scissors	(1, makeRect2D(renderArea));
1416 
1417 	const VkPipelineMultisampleStateCreateInfo multisampleState =
1418 	{
1419 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1420 		DE_NULL,
1421 		(VkPipelineMultisampleStateCreateFlags)0u,
1422 
1423 		sampleCountBitFromSampleCount(m_sampleCount),
1424 		VK_FALSE,
1425 		0.0f,
1426 		DE_NULL,
1427 		VK_FALSE,
1428 		VK_FALSE,
1429 	};
1430 	const VkPipelineDepthStencilStateCreateInfo depthStencilState =
1431 	{
1432 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
1433 		DE_NULL,
1434 		(VkPipelineDepthStencilStateCreateFlags)0u,
1435 
1436 		VK_FALSE,
1437 		VK_TRUE,
1438 		VK_COMPARE_OP_ALWAYS,
1439 		VK_FALSE,
1440 		VK_TRUE,
1441 		{
1442 			VK_STENCIL_OP_KEEP,
1443 			VK_STENCIL_OP_INCREMENT_AND_WRAP,
1444 			VK_STENCIL_OP_KEEP,
1445 			VK_COMPARE_OP_ALWAYS,
1446 			~0u,
1447 			~0u,
1448 			0xFFu / (m_sampleCount + 1)
1449 		},
1450 		{
1451 			VK_STENCIL_OP_KEEP,
1452 			VK_STENCIL_OP_INCREMENT_AND_WRAP,
1453 			VK_STENCIL_OP_KEEP,
1454 			VK_COMPARE_OP_ALWAYS,
1455 			~0u,
1456 			~0u,
1457 			0xFFu / (m_sampleCount + 1)
1458 		},
1459 
1460 		0.0f,
1461 		1.0f
1462 	};
1463 	const VkPipelineColorBlendStateCreateInfo blendState =
1464 	{
1465 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1466 		DE_NULL,
1467 		(VkPipelineColorBlendStateCreateFlags)0u,
1468 
1469 		VK_FALSE,
1470 		VK_LOGIC_OP_COPY,
1471 		deUint32(attachmentBlendStates.size()),
1472 		&attachmentBlendStates[0],
1473 		{ 0.0f, 0.0f, 0.0f, 0.0f }
1474 	};
1475 
1476 	return makeGraphicsPipeline(vkd,												// const DeviceInterface&                        vk
1477 								device,												// const VkDevice                                device
1478 								*m_renderPipelineLayout,							// const VkPipelineLayout                        pipelineLayout
1479 								*vertexShaderModule,								// const VkShaderModule                          vertexShaderModule
1480 								DE_NULL,											// const VkShaderModule                          tessellationControlShaderModule
1481 								DE_NULL,											// const VkShaderModule                          tessellationEvalShaderModule
1482 								m_layerCount != 1 ? *geometryShaderModule : DE_NULL,// const VkShaderModule                          geometryShaderModule
1483 								*fragmentShaderModule,								// const VkShaderModule                          fragmentShaderModule
1484 								*m_renderPass,										// const VkRenderPass                            renderPass
1485 								viewports,											// const std::vector<VkViewport>&                viewports
1486 								scissors,											// const std::vector<VkRect2D>&                  scissors
1487 								VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,				// const VkPrimitiveTopology                     topology
1488 								0u,													// const deUint32                                subpass
1489 								0u,													// const deUint32                                patchControlPoints
1490 								&vertexInputState,									// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
1491 								DE_NULL,											// const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
1492 								&multisampleState,									// const VkPipelineMultisampleStateCreateInfo*   multisampleStateCreateInfo
1493 								&depthStencilState,									// const VkPipelineDepthStencilStateCreateInfo*  depthStencilStateCreateInfo
1494 								&blendState);										// const VkPipelineColorBlendStateCreateInfo*    colorBlendStateCreateInfo
1495 }
1496 
1497 class MaxAttachmenstsRenderPassTestInstance : public MultisampleRenderPassTestBase
1498 {
1499 public:
1500 	MaxAttachmenstsRenderPassTestInstance	(Context& context, TestConfig config);
1501 	~MaxAttachmenstsRenderPassTestInstance	(void);
1502 
1503 	tcu::TestStatus			iterate			(void);
1504 
1505 private:
1506 
1507 	template<typename RenderpassSubpass>
1508 	void					submit						(void);
1509 	void					submitSwitch				(RenderPassType renderPassType);
1510 	void					verify						(void);
1511 
1512 	Move<VkDescriptorSetLayout>	createDescriptorSetLayout	(void);
1513 	Move<VkDescriptorPool>		createDescriptorPool		(void);
1514 	Move<VkDescriptorSet>		createDescriptorSet			(void);
1515 
1516 	template<typename RenderPassTrait>
1517 	Move<VkRenderPass>		createRenderPass			(void);
1518 	Move<VkRenderPass>		createRenderPassSwitch		(const RenderPassType renderPassType);
1519 	Move<VkPipelineLayout>	createRenderPipelineLayout	(bool secondSubpass);
1520 	Move<VkPipeline>		createRenderPipeline		(bool secondSubpass);
1521 
1522 private:
1523 
1524 	const std::vector<VkImageSp>			m_multisampleImages;
1525 	const std::vector<AllocationSp>			m_multisampleImageMemory;
1526 	const std::vector<VkImageViewSp>		m_multisampleImageViews;
1527 
1528 	const std::vector<VkImageSp>			m_singlesampleImages;
1529 	const std::vector<AllocationSp>			m_singlesampleImageMemory;
1530 	const std::vector<VkImageViewSp>		m_singlesampleImageViews;
1531 
1532 	const Unique<VkDescriptorSetLayout>		m_descriptorSetLayout;
1533 	const Unique<VkDescriptorPool>			m_descriptorPool;
1534 	const Unique<VkDescriptorSet>			m_descriptorSet;
1535 
1536 	const Unique<VkRenderPass>				m_renderPass;
1537 	const Unique<VkFramebuffer>				m_framebuffer;
1538 
1539 	const Unique<VkPipelineLayout>			m_pipelineLayoutPass0;
1540 	const Unique<VkPipeline>				m_pipelinePass0;
1541 	const Unique<VkPipelineLayout>			m_pipelineLayoutPass1;
1542 	const Unique<VkPipeline>				m_pipelinePass1;
1543 
1544 	const std::vector<VkBufferSp>			m_buffers;
1545 	const std::vector<AllocationSp>			m_bufferMemory;
1546 
1547 	const Unique<VkCommandPool>				m_commandPool;
1548 	tcu::ResultCollector					m_resultCollector;
1549 };
1550 
MaxAttachmenstsRenderPassTestInstance(Context & context,TestConfig config)1551 MaxAttachmenstsRenderPassTestInstance::MaxAttachmenstsRenderPassTestInstance (Context& context, TestConfig config)
1552 	: MultisampleRenderPassTestBase(context, config)
1553 
1554 	, m_multisampleImages		(createImages(m_sampleCount, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
1555 	, m_multisampleImageMemory	(createImageMemory(m_multisampleImages))
1556 	, m_multisampleImageViews	(createImageViews(m_multisampleImages))
1557 
1558 	, m_singlesampleImages		(createImages(VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT))
1559 	, m_singlesampleImageMemory	(createImageMemory(m_singlesampleImages))
1560 	, m_singlesampleImageViews	(createImageViews(m_singlesampleImages))
1561 
1562 	, m_descriptorSetLayout		(createDescriptorSetLayout())
1563 	, m_descriptorPool			(createDescriptorPool())
1564 	, m_descriptorSet			(createDescriptorSet())
1565 
1566 	, m_renderPass				(createRenderPassSwitch(config.renderPassType))
1567 	, m_framebuffer				(createFramebuffer(m_multisampleImageViews, m_singlesampleImageViews, *m_renderPass))
1568 
1569 	, m_pipelineLayoutPass0		(createRenderPipelineLayout(0))
1570 	, m_pipelinePass0			(createRenderPipeline(0))
1571 	, m_pipelineLayoutPass1		(createRenderPipelineLayout(1))
1572 	, m_pipelinePass1			(createRenderPipeline(1))
1573 
1574 	, m_buffers					(createBuffers())
1575 	, m_bufferMemory			(createBufferMemory(m_buffers))
1576 
1577 	, m_commandPool				(createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex()))
1578 {
1579 }
1580 
~MaxAttachmenstsRenderPassTestInstance(void)1581 MaxAttachmenstsRenderPassTestInstance::~MaxAttachmenstsRenderPassTestInstance (void)
1582 {
1583 }
1584 
1585 template<typename RenderpassSubpass>
submit(void)1586 void MaxAttachmenstsRenderPassTestInstance::submit (void)
1587 {
1588 	const DeviceInterface&								vkd					(m_context.getDeviceInterface());
1589 	const VkDevice										device				(m_context.getDevice());
1590 	const Unique<VkCommandBuffer>						commandBuffer		(allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1591 	const typename RenderpassSubpass::SubpassBeginInfo	subpassBeginInfo	(DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
1592 	const typename RenderpassSubpass::SubpassEndInfo	subpassEndInfo		(DE_NULL);
1593 
1594 	beginCommandBuffer(vkd, *commandBuffer);
1595 
1596 	// Memory barriers between previous copies and rendering
1597 	{
1598 		std::vector<VkImageMemoryBarrier> barriers;
1599 
1600 		for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++)
1601 		{
1602 			const VkImageMemoryBarrier barrier =
1603 			{
1604 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1605 				DE_NULL,
1606 
1607 				VK_ACCESS_TRANSFER_READ_BIT,
1608 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1609 
1610 				VK_IMAGE_LAYOUT_UNDEFINED,
1611 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1612 
1613 				VK_QUEUE_FAMILY_IGNORED,
1614 				VK_QUEUE_FAMILY_IGNORED,
1615 
1616 				**m_singlesampleImages[dstNdx],
1617 				{
1618 					VK_IMAGE_ASPECT_COLOR_BIT,
1619 					0u,
1620 					1u,
1621 					0u,
1622 					m_layerCount
1623 				}
1624 			};
1625 
1626 			barriers.push_back(barrier);
1627 		}
1628 
1629 		vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]);
1630 	}
1631 
1632 	{
1633 		const VkRenderPassBeginInfo beginInfo =
1634 		{
1635 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1636 			DE_NULL,
1637 
1638 			*m_renderPass,
1639 			*m_framebuffer,
1640 
1641 			{
1642 				{ 0u, 0u },
1643 				{ m_width, m_height }
1644 			},
1645 
1646 			0u,
1647 			DE_NULL
1648 		};
1649 		RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
1650 	}
1651 
1652 	// Clear everything to black
1653 	clearAttachments(*commandBuffer);
1654 
1655 	// First subpass - render black samples
1656 	{
1657 		vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelinePass0);
1658 		vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
1659 	}
1660 
1661 	// Second subpasss - merge attachments
1662 	{
1663 		RenderpassSubpass::cmdNextSubpass(vkd, *commandBuffer, &subpassBeginInfo, &subpassEndInfo);
1664 		vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelinePass1);
1665 		vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayoutPass1, 0, 1u, &*m_descriptorSet, 0, NULL);
1666 		vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
1667 	}
1668 
1669 	RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
1670 
1671 	// Memory barriers between rendering and copies
1672 	{
1673 		std::vector<VkImageMemoryBarrier> barriers;
1674 
1675 		for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++)
1676 		{
1677 			const VkImageMemoryBarrier barrier =
1678 			{
1679 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1680 				DE_NULL,
1681 
1682 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1683 				VK_ACCESS_TRANSFER_READ_BIT,
1684 
1685 				VK_IMAGE_LAYOUT_GENERAL,
1686 				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1687 
1688 				VK_QUEUE_FAMILY_IGNORED,
1689 				VK_QUEUE_FAMILY_IGNORED,
1690 
1691 				**m_singlesampleImages[dstNdx],
1692 				{
1693 					VK_IMAGE_ASPECT_COLOR_BIT,
1694 					0u,
1695 					1u,
1696 					0u,
1697 					m_layerCount
1698 				}
1699 			};
1700 
1701 			barriers.push_back(barrier);
1702 		}
1703 
1704 		vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]);
1705 	}
1706 
1707 	// Copy image memory to buffers
1708 	for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++)
1709 	{
1710 		const VkBufferImageCopy region =
1711 		{
1712 			0u,
1713 			0u,
1714 			0u,
1715 			{
1716 				VK_IMAGE_ASPECT_COLOR_BIT,
1717 				0u,
1718 				0u,
1719 				m_layerCount,
1720 			},
1721 			{ 0u, 0u, 0u },
1722 			{ m_width, m_height, 1u }
1723 		};
1724 
1725 		vkd.cmdCopyImageToBuffer(*commandBuffer, **m_singlesampleImages[dstNdx], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_buffers[dstNdx], 1u, &region);
1726 	}
1727 
1728 	// Memory barriers between copies and host access
1729 	{
1730 		std::vector<VkBufferMemoryBarrier> barriers;
1731 
1732 		for (size_t dstNdx = 0; dstNdx < m_buffers.size(); dstNdx++)
1733 		{
1734 			const VkBufferMemoryBarrier barrier =
1735 			{
1736 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
1737 				DE_NULL,
1738 
1739 				VK_ACCESS_TRANSFER_WRITE_BIT,
1740 				VK_ACCESS_HOST_READ_BIT,
1741 
1742 				VK_QUEUE_FAMILY_IGNORED,
1743 				VK_QUEUE_FAMILY_IGNORED,
1744 
1745 				**m_buffers[dstNdx],
1746 				0u,
1747 				VK_WHOLE_SIZE
1748 			};
1749 
1750 			barriers.push_back(barrier);
1751 		}
1752 
1753 		vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0], 0u, DE_NULL);
1754 	}
1755 
1756 	endCommandBuffer(vkd, *commandBuffer);
1757 
1758 	submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), *commandBuffer);
1759 
1760 	for (size_t memoryBufferNdx = 0; memoryBufferNdx < m_bufferMemory.size(); memoryBufferNdx++)
1761 		invalidateMappedMemoryRange(vkd, device, m_bufferMemory[memoryBufferNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
1762 }
1763 
submitSwitch(RenderPassType renderPassType)1764 void MaxAttachmenstsRenderPassTestInstance::submitSwitch (RenderPassType renderPassType)
1765 {
1766 	switch (renderPassType)
1767 	{
1768 		case RENDERPASS_TYPE_LEGACY:
1769 			submit<RenderpassSubpass1>();
1770 			break;
1771 		case RENDERPASS_TYPE_RENDERPASS2:
1772 			submit<RenderpassSubpass2>();
1773 			break;
1774 		default:
1775 			TCU_THROW(InternalError, "Impossible");
1776 	}
1777 }
1778 
1779 template <typename VecType>
isValueAboveThreshold1(const VecType & vale,const VecType & threshold)1780 bool isValueAboveThreshold1 (const VecType& vale, const VecType& threshold)
1781 {
1782 	return (vale[0] > threshold[0]);
1783 }
1784 
1785 template <typename VecType>
isValueAboveThreshold2(const VecType & vale,const VecType & threshold)1786 bool isValueAboveThreshold2 (const VecType& vale, const VecType& threshold)
1787 {
1788 	return (vale[0] > threshold[0]) || (vale[1] > threshold[1]);
1789 }
1790 
1791 template <typename VecType>
isValueAboveThreshold3(const VecType & vale,const VecType & threshold)1792 bool isValueAboveThreshold3 (const VecType& vale, const VecType& threshold)
1793 {
1794 	return (vale[0] > threshold[0]) || (vale[1] > threshold[1]) || (vale[2] > threshold[2]);
1795 }
1796 
1797 template <typename VecType>
isValueAboveThreshold4(const VecType & vale,const VecType & threshold)1798 bool isValueAboveThreshold4 (const VecType& vale, const VecType& threshold)
1799 {
1800 	return (vale[0] > threshold[0]) || (vale[1] > threshold[1]) || (vale[2] > threshold[2]) || (vale[3] > threshold[3]);
1801 }
1802 
verify(void)1803 void MaxAttachmenstsRenderPassTestInstance::verify (void)
1804 {
1805 	const Vec4							errorColor		(1.0f, 0.0f, 0.0f, 1.0f);
1806 	const Vec4							okColor			(0.0f, 1.0f, 0.0f, 1.0f);
1807 	const tcu::TextureFormat			format			(mapVkFormat(m_format));
1808 	const tcu::TextureChannelClass		channelClass	(tcu::getTextureChannelClass(format.type));
1809 	const int							componentCount	(tcu::getNumUsedChannels(format.order));
1810 	const int							outputsCount	= m_attachmentsCount / 2;
1811 
1812 	DE_ASSERT((componentCount >= 0) && (componentCount < 5));
1813 
1814 	std::vector<tcu::ConstPixelBufferAccess> accesses;
1815 	for (int outputNdx = 0; outputNdx < outputsCount; ++outputNdx)
1816 	{
1817 		void* const ptr = m_bufferMemory[outputNdx]->getHostPtr();
1818 		accesses.push_back(tcu::ConstPixelBufferAccess(format, m_width, m_height, 1, ptr));
1819 	}
1820 
1821 	tcu::TextureLevel	errorMask	(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height, outputsCount);
1822 	tcu::TestLog&		log			(m_context.getTestContext().getLog());
1823 	bool				isOk		= true;
1824 
1825 	switch (channelClass)
1826 	{
1827 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1828 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
1829 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1830 		{
1831 			const Vec4 refColor(0.0f, 0.3f, 0.6f, 0.75f);
1832 			const Vec4 threshold(getFormatThreshold());
1833 
1834 			typedef bool(*ValueAboveThresholdFn)(const Vec4&, const Vec4&);
1835 			ValueAboveThresholdFn componentToFnMap[4] =
1836 			{
1837 				isValueAboveThreshold1<Vec4>,
1838 				isValueAboveThreshold2<Vec4>,
1839 				isValueAboveThreshold3<Vec4>,
1840 				isValueAboveThreshold4<Vec4>
1841 			};
1842 			ValueAboveThresholdFn	isValueAboveThreshold	= componentToFnMap[componentCount - 1];
1843 			bool					isSRGBFormat			= tcu::isSRGB(format);
1844 
1845 			for (int outputNdx = 0; outputNdx < outputsCount; outputNdx++)
1846 			for (int y = 0; y < (int)m_height; y++)
1847 			for (int x = 0; x < (int)m_width; x++)
1848 			{
1849 				Vec4 color = accesses[outputNdx].getPixel(x, y);
1850 				if (isSRGBFormat)
1851 					color = tcu::sRGBToLinear(color);
1852 
1853 				const Vec4 diff(tcu::abs(color - refColor));
1854 
1855 				if (isValueAboveThreshold(diff, threshold))
1856 				{
1857 					isOk = false;
1858 					errorMask.getAccess().setPixel(errorColor, x, y, outputNdx);
1859 					break;
1860 				}
1861 				else
1862 					errorMask.getAccess().setPixel(okColor, x, y, outputNdx);
1863 			}
1864 			break;
1865 		}
1866 
1867 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1868 		{
1869 			const UVec4	refColor(0, 48, 144, 189);
1870 			UVec4		threshold(1, 1, 1, 1);
1871 
1872 			if (m_format == VK_FORMAT_A2B10G10R10_UINT_PACK32)
1873 				threshold[3] = 200;
1874 
1875 			typedef bool(*ValueAboveThresholdFn)(const UVec4&, const UVec4&);
1876 			ValueAboveThresholdFn componentToFnMap[4] =
1877 			{
1878 				isValueAboveThreshold1<UVec4>,
1879 				isValueAboveThreshold2<UVec4>,
1880 				isValueAboveThreshold3<UVec4>,
1881 				isValueAboveThreshold4<UVec4>
1882 			};
1883 			ValueAboveThresholdFn isValueAboveThreshold = componentToFnMap[componentCount - 1];
1884 
1885 			for (int outputNdx = 0; outputNdx < outputsCount; outputNdx++)
1886 			for (int y = 0; y < (int)m_height; y++)
1887 			for (int x = 0; x < (int)m_width; x++)
1888 			{
1889 				const UVec4 color	(accesses[outputNdx].getPixelUint(x, y));
1890 				const UVec4 diff	(std::abs(int(color.x()) - int(refColor.x())),
1891 									 std::abs(int(color.y()) - int(refColor.y())),
1892 									 std::abs(int(color.z()) - int(refColor.z())),
1893 									 std::abs(int(color.w()) - int(refColor.w())));
1894 
1895 				if (isValueAboveThreshold(diff, threshold))
1896 				{
1897 					isOk = false;
1898 					errorMask.getAccess().setPixel(errorColor, x, y, outputNdx);
1899 					break;
1900 				}
1901 				else
1902 					errorMask.getAccess().setPixel(okColor, x, y, outputNdx);
1903 			}
1904 			break;
1905 		}
1906 
1907 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1908 		{
1909 			const IVec4 refColor	(0, 24, 75, 93);
1910 			const IVec4 threshold	(1, 1, 1, 1);
1911 
1912 			typedef bool(*ValueAboveThresholdFn)(const IVec4&, const IVec4&);
1913 			ValueAboveThresholdFn componentToFnMap[4] =
1914 			{
1915 				isValueAboveThreshold1<IVec4>,
1916 				isValueAboveThreshold2<IVec4>,
1917 				isValueAboveThreshold3<IVec4>,
1918 				isValueAboveThreshold4<IVec4>
1919 			};
1920 			ValueAboveThresholdFn isValueAboveThreshold = componentToFnMap[componentCount - 1];
1921 
1922 			for (int outputNdx = 0; outputNdx < outputsCount; outputNdx++)
1923 			for (int y = 0; y < (int)m_height; y++)
1924 			for (int x = 0; x < (int)m_width; x++)
1925 			{
1926 				const IVec4 color	(accesses[outputNdx].getPixelInt(x, y));
1927 				const IVec4 diff	(std::abs(color.x() - refColor.x()),
1928 									 std::abs(color.y() - refColor.y()),
1929 									 std::abs(color.z() - refColor.z()),
1930 									 std::abs(color.w() - refColor.w()));
1931 
1932 				if (isValueAboveThreshold(diff, threshold))
1933 				{
1934 					isOk = false;
1935 					errorMask.getAccess().setPixel(errorColor, x, y, outputNdx);
1936 					break;
1937 				}
1938 				else
1939 					errorMask.getAccess().setPixel(okColor, x, y, outputNdx);
1940 			}
1941 			break;
1942 		}
1943 
1944 		default:
1945 			DE_FATAL("Unknown channel class");
1946 	}
1947 
1948 	if (!isOk)
1949 	{
1950 		const std::string			sectionName	("MaxAttachmentsVerify");
1951 		const tcu::ScopedLogSection	section		(log, sectionName, sectionName);
1952 
1953 		logImage("ErrorMask", errorMask.getAccess());
1954 		m_resultCollector.fail("Fail");
1955 	}
1956 }
1957 
iterate(void)1958 tcu::TestStatus MaxAttachmenstsRenderPassTestInstance::iterate(void)
1959 {
1960 	submitSwitch(m_renderPassType);
1961 	verify();
1962 
1963 	return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1964 }
1965 
createDescriptorSetLayout()1966 Move<VkDescriptorSetLayout> MaxAttachmenstsRenderPassTestInstance::createDescriptorSetLayout()
1967 {
1968 	const VkDescriptorSetLayoutBinding bindingTemplate =
1969 	{
1970 		0,														// binding
1971 		VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,					// descriptorType
1972 		1u,														// descriptorCount
1973 		VK_SHADER_STAGE_FRAGMENT_BIT,							// stageFlags
1974 		DE_NULL													// pImmutableSamplers
1975 	};
1976 
1977 	std::vector<VkDescriptorSetLayoutBinding> bindings(m_attachmentsCount, bindingTemplate);
1978 	for (deUint32 idx = 0; idx < m_attachmentsCount; ++idx)
1979 		bindings[idx].binding = idx;
1980 
1981 	const VkDescriptorSetLayoutCreateInfo createInfo =
1982 	{
1983 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,	// sType
1984 		DE_NULL,												// pNext
1985 		0u,														// flags
1986 		m_attachmentsCount,										// bindingCount
1987 		&bindings[0]											// pBindings
1988 	};
1989 
1990 	return ::createDescriptorSetLayout(m_context.getDeviceInterface(), m_context.getDevice(), &createInfo);
1991 }
1992 
createDescriptorPool()1993 Move<VkDescriptorPool> MaxAttachmenstsRenderPassTestInstance::createDescriptorPool()
1994 {
1995 	const VkDescriptorPoolSize size =
1996 	{
1997 		VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,					// type
1998 		m_attachmentsCount										// descriptorCount
1999 	};
2000 
2001 	const VkDescriptorPoolCreateInfo createInfo =
2002 	{
2003 		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,			// sType
2004 		DE_NULL,												// pNext
2005 		VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,		// flags
2006 		1u,														// maxSets
2007 		1u,														// poolSizeCount
2008 		&size													// pPoolSizes
2009 	};
2010 
2011 	return ::createDescriptorPool(m_context.getDeviceInterface(), m_context.getDevice(), &createInfo);
2012 }
2013 
createDescriptorSet()2014 Move<VkDescriptorSet> MaxAttachmenstsRenderPassTestInstance::createDescriptorSet()
2015 {
2016 	const VkDescriptorSetAllocateInfo allocateInfo =
2017 	{
2018 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,			// sType
2019 		DE_NULL,												// pNext
2020 		*m_descriptorPool,										// descriptorPool
2021 		1u,														// descriptorSetCount
2022 		&*m_descriptorSetLayout									// pSetLayouts
2023 	};
2024 
2025 	const vk::DeviceInterface&		vkd					= m_context.getDeviceInterface();
2026 	vk::VkDevice					device				= m_context.getDevice();
2027 	Move<VkDescriptorSet>			descriptorSet		= allocateDescriptorSet(vkd, device, &allocateInfo);
2028 	vector<VkDescriptorImageInfo>	descriptorImageInfo	(m_attachmentsCount);
2029 	vector<VkWriteDescriptorSet>	descriptorWrites	(m_attachmentsCount);
2030 
2031 	for (deUint32 idx = 0; idx < m_attachmentsCount; ++idx)
2032 	{
2033 		const VkDescriptorImageInfo imageInfo =
2034 		{
2035 			DE_NULL,									// VkSampler		sampler
2036 			**m_singlesampleImageViews[idx],			// VkImageView		imageView
2037 			VK_IMAGE_LAYOUT_GENERAL						// VkImageLayout	imageLayout
2038 		};
2039 		descriptorImageInfo[idx] = imageInfo;
2040 
2041 		const VkWriteDescriptorSet	write =
2042 		{
2043 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,		// VkStructureType					sType
2044 			DE_NULL,									// const void*						pNext
2045 			*descriptorSet,								// VkDescriptorSet					dstSet
2046 			(deUint32)idx,								// uint32_t							dstBinding
2047 			0u,											// uint32_t							dstArrayElement
2048 			1u,											// uint32_t							descriptorCount
2049 			VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,		// VkDescriptorType					descriptorType
2050 			&descriptorImageInfo[idx],					// const VkDescriptorImageInfo*		pImageInfo
2051 			DE_NULL,									// const VkDescriptorBufferInfo*	pBufferInfo
2052 			DE_NULL										// const VkBufferView*				pTexelBufferView
2053 		};
2054 
2055 		descriptorWrites[idx] = write;
2056 	}
2057 
2058 	vkd.updateDescriptorSets(device, (deUint32)descriptorWrites.size(), &descriptorWrites[0], 0u, DE_NULL);
2059 	return descriptorSet;
2060 }
2061 
2062 template<typename RenderPassTrait>
createRenderPass(void)2063 Move<VkRenderPass> MaxAttachmenstsRenderPassTestInstance::createRenderPass(void)
2064 {
2065 	// make name for RenderPass1Trait or RenderPass2Trait shorter
2066 	typedef RenderPassTrait RPT;
2067 
2068 	typedef RenderPassTrait RPT;
2069 	typedef typename RPT::AttDesc				AttDesc;
2070 	typedef typename RPT::AttRef				AttRef;
2071 	typedef typename RPT::SubpassDep			SubpassDep;
2072 	typedef typename RPT::SubpassDesc			SubpassDesc;
2073 	typedef typename RPT::RenderPassCreateInfo	RenderPassCreateInfo;
2074 
2075 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
2076 	VkDevice				device	= m_context.getDevice();
2077 	std::vector<AttDesc>	attachments;
2078 	std::vector<AttRef>		sp0colorAttachmentRefs;
2079 	std::vector<AttRef>		sp0resolveAttachmentRefs;
2080 	std::vector<AttRef>		sp1inAttachmentRefs;
2081 	std::vector<AttRef>		sp1colorAttachmentRefs;
2082 
2083 	for (size_t attachmentNdx = 0; attachmentNdx < m_attachmentsCount; attachmentNdx++)
2084 	{
2085 		// define first subpass outputs
2086 		{
2087 			const AttDesc multisampleAttachment
2088 			(
2089 				DE_NULL,									// pNext
2090 				0u,											// flags
2091 				m_format,									// format
2092 				m_sampleCount,								// samples
2093 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// loadOp
2094 				VK_ATTACHMENT_STORE_OP_STORE,				// storeOp
2095 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// stencilLoadOp
2096 				VK_ATTACHMENT_STORE_OP_DONT_CARE,			// stencilStoreOp
2097 				VK_IMAGE_LAYOUT_UNDEFINED,					// initialLayout
2098 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// finalLayout
2099 			);
2100 			const AttRef attachmentRef
2101 			(
2102 				DE_NULL,
2103 				(deUint32)attachments.size(),				// attachment
2104 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// layout
2105 				0u											// aspectMask
2106 			);
2107 			sp0colorAttachmentRefs.push_back(attachmentRef);
2108 			attachments.push_back(multisampleAttachment);
2109 		}
2110 		// define first subpass resolve attachments
2111 		{
2112 			const AttDesc singlesampleAttachment
2113 			(
2114 				DE_NULL,									// pNext
2115 				0u,											// flags
2116 				m_format,									// format
2117 				VK_SAMPLE_COUNT_1_BIT,						// samples
2118 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// loadOp
2119 				VK_ATTACHMENT_STORE_OP_STORE,				// storeOp
2120 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// stencilLoadOp
2121 				VK_ATTACHMENT_STORE_OP_DONT_CARE,			// stencilStoreOp
2122 				VK_IMAGE_LAYOUT_UNDEFINED,					// initialLayout
2123 				VK_IMAGE_LAYOUT_GENERAL						// finalLayout
2124 			);
2125 			const AttRef attachmentRef
2126 			(
2127 				DE_NULL,									// pNext
2128 				(deUint32)attachments.size(),				// attachment
2129 				VK_IMAGE_LAYOUT_GENERAL,					// layout
2130 				0u											// aspectMask
2131 			);
2132 			sp0resolveAttachmentRefs.push_back(attachmentRef);
2133 			attachments.push_back(singlesampleAttachment);
2134 		}
2135 		// define second subpass inputs
2136 		{
2137 			const AttRef attachmentRef
2138 			(
2139 				DE_NULL,									// pNext
2140 				(deUint32)attachments.size() - 1,			// attachment
2141 				VK_IMAGE_LAYOUT_GENERAL,					// layout
2142 				VK_IMAGE_ASPECT_COLOR_BIT					// aspectMask
2143 			);
2144 			sp1inAttachmentRefs.push_back(attachmentRef);
2145 		}
2146 		// define second subpass outputs - it merges pairs of
2147 		// results that were produced by the first subpass
2148 		if (attachmentNdx < (m_attachmentsCount / 2))
2149 		{
2150 			const AttRef colorAttachmentRef
2151 			(
2152 				DE_NULL,									// pNext
2153 				(deUint32)attachments.size() - 1,			// attachment
2154 				VK_IMAGE_LAYOUT_GENERAL,					// layout
2155 				0u											// aspectMask
2156 			);
2157 			sp1colorAttachmentRefs.push_back(colorAttachmentRef);
2158 		}
2159 	}
2160 
2161 	DE_ASSERT(sp0colorAttachmentRefs.size() == sp0resolveAttachmentRefs.size());
2162 	DE_ASSERT(attachments.size() == sp0colorAttachmentRefs.size() + sp0resolveAttachmentRefs.size());
2163 
2164 	{
2165 		const SubpassDesc subpass0
2166 		(
2167 															// sType
2168 			DE_NULL,										// pNext
2169 			(VkSubpassDescriptionFlags)0,					// flags
2170 			VK_PIPELINE_BIND_POINT_GRAPHICS,				// pipelineBindPoint
2171 			0u,												// viewMask
2172 			0u,												// inputAttachmentCount
2173 			DE_NULL,										// pInputAttachments
2174 			(deUint32)sp0colorAttachmentRefs.size(),		// colorAttachmentCount
2175 			&sp0colorAttachmentRefs[0],						// pColorAttachments
2176 			&sp0resolveAttachmentRefs[0],					// pResolveAttachments
2177 			DE_NULL,										// pDepthStencilAttachment
2178 			0u,												// preserveAttachmentCount
2179 			DE_NULL											// pPreserveAttachments
2180 		);
2181 		const SubpassDesc subpass1
2182 		(
2183 															// sType
2184 			DE_NULL,										// pNext
2185 			(VkSubpassDescriptionFlags)0,					// flags
2186 			VK_PIPELINE_BIND_POINT_GRAPHICS,				// pipelineBindPoint
2187 			0u,												// viewMask
2188 			(deUint32)sp1inAttachmentRefs.size(),			// inputAttachmentCount
2189 			&sp1inAttachmentRefs[0],						// pInputAttachments
2190 			(deUint32)sp1colorAttachmentRefs.size(),		// colorAttachmentCount
2191 			&sp1colorAttachmentRefs[0],						// pColorAttachments
2192 			DE_NULL,										// pResolveAttachments
2193 			DE_NULL,										// pDepthStencilAttachment
2194 			0u,												// preserveAttachmentCount
2195 			DE_NULL											// pPreserveAttachments
2196 		);
2197 		SubpassDesc subpasses[] =
2198 		{
2199 			subpass0,
2200 			subpass1
2201 		};
2202 		const SubpassDep subpassDependency
2203 		(
2204 			DE_NULL,										// pNext
2205 			0u,												// srcSubpass
2206 			1u,												// dstSubpass
2207 			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	// srcStageMask
2208 			VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,			// dstStageMask
2209 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// srcAccessMask
2210 			VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,			// dstAccessMask
2211 			0u,												// dependencyFlags
2212 			0u												// viewOffset
2213 		);
2214 		const RenderPassCreateInfo renderPassCreator
2215 		(
2216 															// sType
2217 			DE_NULL,										// pNext
2218 			(VkRenderPassCreateFlags)0u,					// flags
2219 			(deUint32)attachments.size(),					// attachmentCount
2220 			&attachments[0],								// pAttachments
2221 			2u,												// subpassCount
2222 			subpasses,										// pSubpasses
2223 			1u,												// dependencyCount
2224 			&subpassDependency,								// pDependencies
2225 			0u,												// correlatedViewMaskCount
2226 			DE_NULL											// pCorrelatedViewMasks
2227 		);
2228 
2229 		return renderPassCreator.createRenderPass(vkd, device);
2230 	}
2231 }
2232 
createRenderPassSwitch(const RenderPassType renderPassType)2233 Move<VkRenderPass> MaxAttachmenstsRenderPassTestInstance::createRenderPassSwitch(const RenderPassType renderPassType)
2234 {
2235 	switch (renderPassType)
2236 	{
2237 		case RENDERPASS_TYPE_LEGACY:
2238 			return createRenderPass<RenderPass1Trait>();
2239 		case RENDERPASS_TYPE_RENDERPASS2:
2240 			return createRenderPass<RenderPass2Trait>();
2241 		default:
2242 			TCU_THROW(InternalError, "Impossible");
2243 	}
2244 }
2245 
createRenderPipelineLayout(bool secondSubpass)2246 Move<VkPipelineLayout> MaxAttachmenstsRenderPassTestInstance::createRenderPipelineLayout(bool secondSubpass)
2247 {
2248 	const DeviceInterface&	vkd		= m_context.getDeviceInterface();
2249 	VkDevice				device	= m_context.getDevice();
2250 
2251 	const VkPipelineLayoutCreateInfo createInfo =
2252 	{
2253 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2254 		DE_NULL,
2255 		(vk::VkPipelineLayoutCreateFlags)0,
2256 
2257 		secondSubpass ? 1u : 0u,
2258 		secondSubpass ? &*m_descriptorSetLayout : DE_NULL,
2259 
2260 		0u,
2261 		DE_NULL
2262 	};
2263 
2264 	return createPipelineLayout(vkd, device, &createInfo);
2265 }
2266 
createRenderPipeline(bool secondSubpass)2267 Move<VkPipeline> MaxAttachmenstsRenderPassTestInstance::createRenderPipeline(bool secondSubpass)
2268 {
2269 	const DeviceInterface&			vkd						= m_context.getDeviceInterface();
2270 	VkDevice						device					= m_context.getDevice();
2271 	const vk::BinaryCollection&		binaryCollection		= m_context.getBinaryCollection();
2272 	VkSampleCountFlagBits			sampleCount				= sampleCountBitFromSampleCount(m_sampleCount);
2273 	deUint32						blendStatesCount		= m_attachmentsCount;
2274 	std::string						fragShaderNameBase		= "quad-frag-sp0-";
2275 
2276 	if (secondSubpass)
2277 	{
2278 		sampleCount			= VK_SAMPLE_COUNT_1_BIT;
2279 		blendStatesCount	/= 2;
2280 		fragShaderNameBase	= "quad-frag-sp1-";
2281 	}
2282 
2283 	std::string						fragShaderName			= fragShaderNameBase + de::toString(m_attachmentsCount);
2284 	const Unique<VkShaderModule>	vertexShaderModule		(createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u));
2285 	const Unique<VkShaderModule>	fragmentShaderModule	(createShaderModule(vkd, device, binaryCollection.get(fragShaderName), 0u));
2286 	const Move<VkShaderModule>		geometryShaderModule	(m_layerCount == 1 ? Move<VkShaderModule>() : createShaderModule(vkd, device, binaryCollection.get("geom"), 0u));
2287 
2288 	// Disable blending
2289 	const VkPipelineColorBlendAttachmentState attachmentBlendState =
2290 	{
2291 		VK_FALSE,
2292 		VK_BLEND_FACTOR_SRC_ALPHA,
2293 		VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
2294 		VK_BLEND_OP_ADD,
2295 		VK_BLEND_FACTOR_ONE,
2296 		VK_BLEND_FACTOR_ONE,
2297 		VK_BLEND_OP_ADD,
2298 		VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
2299 	};
2300 	std::vector<VkPipelineColorBlendAttachmentState>	attachmentBlendStates(blendStatesCount, attachmentBlendState);
2301 	const VkPipelineVertexInputStateCreateInfo			vertexInputState =
2302 	{
2303 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
2304 		DE_NULL,
2305 		(VkPipelineVertexInputStateCreateFlags)0u,
2306 
2307 		0u,
2308 		DE_NULL,
2309 
2310 		0u,
2311 		DE_NULL
2312 	};
2313 	const tcu::UVec2				renderArea	(m_width, m_height);
2314 	const std::vector<VkViewport>	viewports	(1, makeViewport(renderArea));
2315 	const std::vector<VkRect2D>		scissors	(1, makeRect2D(renderArea));
2316 
2317 	const VkPipelineMultisampleStateCreateInfo multisampleState =
2318 	{
2319 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
2320 		DE_NULL,
2321 		(VkPipelineMultisampleStateCreateFlags)0u,
2322 
2323 		sampleCount,
2324 		VK_FALSE,
2325 		0.0f,
2326 		DE_NULL,
2327 		VK_FALSE,
2328 		VK_FALSE,
2329 	};
2330 	const VkPipelineDepthStencilStateCreateInfo depthStencilState =
2331 	{
2332 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
2333 		DE_NULL,
2334 		(VkPipelineDepthStencilStateCreateFlags)0u,
2335 
2336 		VK_FALSE,
2337 		VK_TRUE,
2338 		VK_COMPARE_OP_ALWAYS,
2339 		VK_FALSE,
2340 		VK_TRUE,
2341 		{
2342 			VK_STENCIL_OP_KEEP,
2343 			VK_STENCIL_OP_INCREMENT_AND_WRAP,
2344 			VK_STENCIL_OP_KEEP,
2345 			VK_COMPARE_OP_ALWAYS,
2346 			~0u,
2347 			~0u,
2348 			0xFFu / (m_sampleCount + 1)
2349 		},
2350 		{
2351 			VK_STENCIL_OP_KEEP,
2352 			VK_STENCIL_OP_INCREMENT_AND_WRAP,
2353 			VK_STENCIL_OP_KEEP,
2354 			VK_COMPARE_OP_ALWAYS,
2355 			~0u,
2356 			~0u,
2357 			0xFFu / (m_sampleCount + 1)
2358 		},
2359 
2360 		0.0f,
2361 		1.0f
2362 	};
2363 	const VkPipelineColorBlendStateCreateInfo blendState =
2364 	{
2365 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
2366 		DE_NULL,
2367 		(VkPipelineColorBlendStateCreateFlags)0u,
2368 
2369 		VK_FALSE,
2370 		VK_LOGIC_OP_COPY,
2371 		deUint32(attachmentBlendStates.size()),
2372 		&attachmentBlendStates[0],
2373 		{ 0.0f, 0.0f, 0.0f, 0.0f }
2374 	};
2375 
2376 	return makeGraphicsPipeline(vkd,																// vk
2377 								device,																// device
2378 								secondSubpass ? *m_pipelineLayoutPass1 : *m_pipelineLayoutPass0,	// pipelineLayout
2379 								*vertexShaderModule,												// vertexShaderModule
2380 								DE_NULL,															// tessellationControlShaderModule
2381 								DE_NULL,															// tessellationEvalShaderModule
2382 								m_layerCount != 1 ? *geometryShaderModule : DE_NULL,				// geometryShaderModule
2383 								*fragmentShaderModule,												// fragmentShaderModule
2384 								*m_renderPass,														// renderPass
2385 								viewports,															// viewports
2386 								scissors,															// scissors
2387 								VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,								// topology
2388 								secondSubpass,														// subpass
2389 								0u,																	// patchControlPoints
2390 								&vertexInputState,													// vertexInputStateCreateInfo
2391 								DE_NULL,															// rasterizationStateCreateInfo
2392 								&multisampleState,													// multisampleStateCreateInfo
2393 								&depthStencilState,													// depthStencilStateCreateInfo
2394 								&blendState);														// colorBlendStateCreateInfo
2395 }
2396 
2397 struct Programs
2398 {
initvkt::__anon156ab5910111::Programs2399 	void init(vk::SourceCollections& dst, TestConfig config) const
2400 	{
2401 		const tcu::TextureFormat		format			(mapVkFormat(config.format));
2402 		const tcu::TextureChannelClass	channelClass	(tcu::getTextureChannelClass(format.type));
2403 
2404 		dst.glslSources.add("quad-vert") << glu::VertexSource(
2405 			"#version 450\n"
2406 			"out gl_PerVertex {\n"
2407 			"\tvec4 gl_Position;\n"
2408 			"};\n"
2409 			"highp float;\n"
2410 			"void main (void) {\n"
2411 			"\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
2412 			"\t                   ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
2413 			"}\n");
2414 
2415 		if (config.layerCount > 1)
2416 		{
2417 			std::ostringstream src;
2418 
2419 			src << "#version 450\n"
2420 				<< "highp float;\n"
2421 				<< "\n"
2422 				<< "layout(triangles) in;\n"
2423 				<< "layout(triangle_strip, max_vertices = " << 3 * 2 * config.layerCount << ") out;\n"
2424 				<< "\n"
2425 				<< "in gl_PerVertex {\n"
2426 				<< "    vec4 gl_Position;\n"
2427 				<< "} gl_in[];\n"
2428 				<< "\n"
2429 				<< "out gl_PerVertex {\n"
2430 				<< "    vec4 gl_Position;\n"
2431 				<< "};\n"
2432 				<< "\n"
2433 				<< "void main (void) {\n"
2434 				<< "    for (int layerNdx = 0; layerNdx < " << config.layerCount << "; ++layerNdx) {\n"
2435 				<< "        for(int vertexNdx = 0; vertexNdx < gl_in.length(); vertexNdx++) {\n"
2436 				<< "            gl_Position = gl_in[vertexNdx].gl_Position;\n"
2437 				<< "            gl_Layer    = layerNdx;\n"
2438 				<< "            EmitVertex();\n"
2439 				<< "        };\n"
2440 				<< "        EndPrimitive();\n"
2441 				<< "    };\n"
2442 				<< "}\n";
2443 
2444 			dst.glslSources.add("geom") << glu::GeometrySource(src.str());
2445 		}
2446 
2447 		const tcu::StringTemplate genericLayoutTemplate("layout(location = ${INDEX}) out ${TYPE_PREFIX}vec4 o_color${INDEX};\n");
2448 		const tcu::StringTemplate genericBodyTemplate("\to_color${INDEX} = ${TYPE_PREFIX}vec4(${COLOR_VAL});\n");
2449 
2450 		if (config.testType == RESOLVE || config.testType == COMPATIBILITY)
2451 		{
2452 			const tcu::StringTemplate fragTemplate("#version 450\n"
2453 												   "layout(push_constant) uniform PushConstant {\n"
2454 												   "\thighp uint sampleMask;\n"
2455 												   "} pushConstants;\n"
2456 												   "${LAYOUT}"
2457 												   "void main (void)\n"
2458 												   "{\n"
2459 												   "${BODY}"
2460 												   "}\n");
2461 
2462 			std::map<std::string, std::string> parameters;
2463 			switch (channelClass)
2464 			{
2465 				case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
2466 					parameters["TYPE_PREFIX"] = "u";
2467 					parameters["COLOR_VAL"] = "255";
2468 					break;
2469 
2470 				case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
2471 					parameters["TYPE_PREFIX"] = "i";
2472 					parameters["COLOR_VAL"] = "127";
2473 					break;
2474 
2475 				case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
2476 				case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
2477 				case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
2478 					parameters["TYPE_PREFIX"] = "";
2479 					parameters["COLOR_VAL"] = "1.0";
2480 					break;
2481 
2482 				default:
2483 					DE_FATAL("Unknown channel class");
2484 			}
2485 
2486 			std::string layoutDefinitions = "";
2487 			std::string shaderBody = "\tgl_SampleMask[0] = int(pushConstants.sampleMask);\n";
2488 
2489 			for (deUint32 attIdx = 0; attIdx < config.attachmentCount; ++attIdx)
2490 			{
2491 				parameters["INDEX"]	= de::toString(attIdx);
2492 				layoutDefinitions	+= genericLayoutTemplate.specialize(parameters);
2493 				shaderBody			+= genericBodyTemplate.specialize(parameters);
2494 			}
2495 
2496 			parameters["LAYOUT"]	= layoutDefinitions;
2497 			parameters["BODY"]		= shaderBody;
2498 			dst.glslSources.add("quad-frag") << glu::FragmentSource(fragTemplate.specialize(parameters));
2499 		}
2500 		else	// MAX_ATTACMENTS
2501 		{
2502 			const tcu::StringTemplate fragTemplate("#version 450\n"
2503 												   "${LAYOUT}"
2504 												   "void main (void)\n"
2505 												   "{\n"
2506 												   "${BODY}"
2507 												   "}\n");
2508 
2509 			std::map<std::string, std::string> parameters;
2510 			switch (channelClass)
2511 			{
2512 				case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
2513 					parameters["TYPE_PREFIX"] = "u";
2514 					parameters["COLOR_VAL"] = "0, 64, 192, 252";
2515 					break;
2516 
2517 				case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
2518 					parameters["TYPE_PREFIX"] = "i";
2519 					parameters["COLOR_VAL"] = "0, 32, 100, 124";
2520 					break;
2521 
2522 				case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
2523 				case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
2524 				case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
2525 					parameters["TYPE_PREFIX"] = "";
2526 					parameters["COLOR_VAL"] = "0.0, 0.4, 0.8, 1.0";
2527 					break;
2528 
2529 				default:
2530 					DE_FATAL("Unknown channel class");
2531 			}
2532 
2533 			// parts of fragment shader for second subpass - Vulkan introduced a new uniform type and syntax to glsl for input attachments
2534 			const tcu::StringTemplate subpassLayoutTemplate("layout (input_attachment_index = ${INDEX}, set = 0, binding = ${INDEX}) uniform ${TYPE_PREFIX}subpassInput i_color${INDEX};\n");
2535 			const tcu::StringTemplate subpassFBodyTemplate("\to_color${INDEX} = subpassLoad(i_color${INDEX})*0.5 + subpassLoad(i_color${MIX_INDEX})*0.25;\n");
2536 			const tcu::StringTemplate subpassIBodyTemplate("\to_color${INDEX} = subpassLoad(i_color${INDEX}) / 2 + subpassLoad(i_color${MIX_INDEX}) / 4;\n");
2537 
2538 			bool selectIBody = isIntFormat(config.format) || isUintFormat(config.format);
2539 			const tcu::StringTemplate& subpassBodyTemplate = selectIBody ? subpassIBodyTemplate : subpassFBodyTemplate;
2540 
2541 			std::string sp0layoutDefinitions	= "";
2542 			std::string sp0shaderBody			= "";
2543 			std::string sp1inLayoutDefinitions	= "";
2544 			std::string sp1outLayoutDefinitions	= "";
2545 			std::string sp1shaderBody			= "";
2546 
2547 			deUint32 halfAttachments = config.attachmentCount / 2;
2548 			for (deUint32 attIdx = 0; attIdx < config.attachmentCount; ++attIdx)
2549 			{
2550 				parameters["INDEX"] = de::toString(attIdx);
2551 
2552 				sp0layoutDefinitions	+= genericLayoutTemplate.specialize(parameters);
2553 				sp0shaderBody			+= genericBodyTemplate.specialize(parameters);
2554 
2555 				sp1inLayoutDefinitions += subpassLayoutTemplate.specialize(parameters);
2556 				if (attIdx < halfAttachments)
2557 				{
2558 					// we are combining pairs of input attachments to produce half the number of outputs
2559 					parameters["MIX_INDEX"]	= de::toString(halfAttachments + attIdx);
2560 					sp1outLayoutDefinitions	+= genericLayoutTemplate.specialize(parameters);
2561 					sp1shaderBody			+= subpassBodyTemplate.specialize(parameters);
2562 				}
2563 			}
2564 
2565 			// construct fragment shaders for subpass1 and subpass2; note that there
2566 			// is different shader definition depending on number of attachments
2567 			std::string nameBase	= "quad-frag-sp";
2568 			std::string namePostfix	= de::toString(config.attachmentCount);
2569 			parameters["LAYOUT"]	= sp0layoutDefinitions;
2570 			parameters["BODY"]		= sp0shaderBody;
2571 			dst.glslSources.add(nameBase + "0-" + namePostfix) << glu::FragmentSource(fragTemplate.specialize(parameters));
2572 			parameters["LAYOUT"]	= sp1inLayoutDefinitions + sp1outLayoutDefinitions;
2573 			parameters["BODY"]		= sp1shaderBody;
2574 			dst.glslSources.add(nameBase + "1-" + namePostfix) << glu::FragmentSource(fragTemplate.specialize(parameters));
2575 		}
2576 	}
2577 };
2578 
checkSupport(Context & context,TestConfig config)2579 void checkSupport(Context& context, TestConfig config)
2580 {
2581 	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
2582 		!context.getPortabilitySubsetFeatures().multisampleArrayImage &&
2583 		(config.sampleCount != VK_SAMPLE_COUNT_1_BIT) && (config.layerCount != 1))
2584 	{
2585 		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Implementation does not support image array with multiple samples per texel");
2586 	}
2587 }
2588 
formatToName(VkFormat format)2589 std::string formatToName (VkFormat format)
2590 {
2591 	const std::string	formatStr	= de::toString(format);
2592 	const std::string	prefix		= "VK_FORMAT_";
2593 
2594 	DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix);
2595 
2596 	return de::toLower(formatStr.substr(prefix.length()));
2597 }
2598 
initTests(tcu::TestCaseGroup * group,RenderPassType renderPassType)2599 void initTests (tcu::TestCaseGroup* group, RenderPassType renderPassType)
2600 {
2601 	static const VkFormat	formats[] =
2602 	{
2603 		VK_FORMAT_R5G6B5_UNORM_PACK16,
2604 		VK_FORMAT_R8_UNORM,
2605 		VK_FORMAT_R8_SNORM,
2606 		VK_FORMAT_R8_UINT,
2607 		VK_FORMAT_R8_SINT,
2608 		VK_FORMAT_R8G8_UNORM,
2609 		VK_FORMAT_R8G8_SNORM,
2610 		VK_FORMAT_R8G8_UINT,
2611 		VK_FORMAT_R8G8_SINT,
2612 		VK_FORMAT_R8G8B8A8_UNORM,
2613 		VK_FORMAT_R8G8B8A8_SNORM,
2614 		VK_FORMAT_R8G8B8A8_UINT,
2615 		VK_FORMAT_R8G8B8A8_SINT,
2616 		VK_FORMAT_R8G8B8A8_SRGB,
2617 		VK_FORMAT_A8B8G8R8_UNORM_PACK32,
2618 		VK_FORMAT_A8B8G8R8_SNORM_PACK32,
2619 		VK_FORMAT_A8B8G8R8_UINT_PACK32,
2620 		VK_FORMAT_A8B8G8R8_SINT_PACK32,
2621 		VK_FORMAT_A8B8G8R8_SRGB_PACK32,
2622 		VK_FORMAT_B8G8R8A8_UNORM,
2623 		VK_FORMAT_B8G8R8A8_SRGB,
2624 		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
2625 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
2626 		VK_FORMAT_A2B10G10R10_UINT_PACK32,
2627 		VK_FORMAT_R16_UNORM,
2628 		VK_FORMAT_R16_SNORM,
2629 		VK_FORMAT_R16_UINT,
2630 		VK_FORMAT_R16_SINT,
2631 		VK_FORMAT_R16_SFLOAT,
2632 		VK_FORMAT_R16G16_UNORM,
2633 		VK_FORMAT_R16G16_SNORM,
2634 		VK_FORMAT_R16G16_UINT,
2635 		VK_FORMAT_R16G16_SINT,
2636 		VK_FORMAT_R16G16_SFLOAT,
2637 		VK_FORMAT_R16G16B16A16_UNORM,
2638 		VK_FORMAT_R16G16B16A16_SNORM,
2639 		VK_FORMAT_R16G16B16A16_UINT,
2640 		VK_FORMAT_R16G16B16A16_SINT,
2641 		VK_FORMAT_R16G16B16A16_SFLOAT,
2642 		VK_FORMAT_R32_UINT,
2643 		VK_FORMAT_R32_SINT,
2644 		VK_FORMAT_R32_SFLOAT,
2645 		VK_FORMAT_R32G32_UINT,
2646 		VK_FORMAT_R32G32_SINT,
2647 		VK_FORMAT_R32G32_SFLOAT,
2648 		VK_FORMAT_R32G32B32A32_UINT,
2649 		VK_FORMAT_R32G32B32A32_SINT,
2650 		VK_FORMAT_R32G32B32A32_SFLOAT,
2651 	};
2652 	const deUint32			sampleCounts[] =
2653 	{
2654 		2u, 4u, 8u
2655 	};
2656 	const deUint32			layerCounts[] =
2657 	{
2658 		1u, 3u, 6u
2659 	};
2660 	tcu::TestContext&		testCtx	(group->getTestContext());
2661 
2662 	for (size_t layerCountNdx = 0; layerCountNdx < DE_LENGTH_OF_ARRAY(layerCounts); layerCountNdx++)
2663 	{
2664 		const deUint32					layerCount		(layerCounts[layerCountNdx]);
2665 		const std::string				layerGroupName	("layers_" + de::toString(layerCount));
2666 		de::MovePtr<tcu::TestCaseGroup>	layerGroup		(new tcu::TestCaseGroup(testCtx, layerGroupName.c_str(), layerGroupName.c_str()));
2667 
2668 		for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
2669 		{
2670 			const VkFormat					format		(formats[formatNdx]);
2671 			const std::string				formatName	(formatToName(format));
2672 			de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatName.c_str(), formatName.c_str()));
2673 
2674 			for (size_t sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCountNdx++)
2675 			{
2676 				const deUint32	sampleCount(sampleCounts[sampleCountNdx]);
2677 
2678 				// Skip this test as it is rather slow
2679 				if (layerCount == 6 && sampleCount == 8)
2680 					continue;
2681 
2682 				std::string			testName	("samples_" + de::toString(sampleCount));
2683 				const TestConfig	testConfig =
2684 				{
2685 					RESOLVE,
2686 					format,
2687 					sampleCount,
2688 					layerCount,
2689 					4u,
2690 					32u,
2691 					32u,
2692 					renderPassType
2693 				};
2694 
2695 				formatGroup->addChild(new InstanceFactory1WithSupport<MultisampleRenderPassTestInstance, TestConfig, FunctionSupport1<TestConfig>, Programs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName.c_str(), testName.c_str(), testConfig, typename FunctionSupport1<TestConfig>::Args(checkSupport, testConfig)));
2696 
2697 				// MaxAttachmenstsRenderPassTest is ment to test extreme cases where applications might consume all available on-chip
2698 				// memory. This is achieved by using maxColorAttachments attachments and two subpasses, but during test creation we
2699 				// dont know what is the maximal number of attachments (spirv tools are not available on all platforms) so we cant
2700 				// construct shaders during test execution. To be able to test this we need to execute tests for all available
2701 				// numbers of attachments despite the fact that we are only interested in the maximal number; test construction code
2702 				// assumes that the number of attachments is power of two
2703 				if (layerCount == 1)
2704 				{
2705 					for (deUint32 power = 2; power < 5; ++power)
2706 					{
2707 						deUint32	attachmentCount					= 1 << power;
2708 						std::string	maxAttName						= "max_attachments_" + de::toString(attachmentCount) + "_" + testName;
2709 
2710 						TestConfig	maxAttachmentsTestConfig		= testConfig;
2711 						maxAttachmentsTestConfig.testType			= MAX_ATTACHMENTS;
2712 						maxAttachmentsTestConfig.attachmentCount	= attachmentCount;
2713 
2714 						formatGroup->addChild(new InstanceFactory1<MaxAttachmenstsRenderPassTestInstance, TestConfig, Programs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, maxAttName.c_str(), maxAttName.c_str(), maxAttachmentsTestConfig));
2715 					}
2716 
2717 					{
2718 						std::string	compatibilityTestName			= "compatibility_" + testName;
2719 
2720 						TestConfig	compatibilityTestConfig			= testConfig;
2721 						compatibilityTestConfig.testType			= COMPATIBILITY;
2722 						compatibilityTestConfig.attachmentCount		= 1;
2723 
2724 						formatGroup->addChild(new InstanceFactory1<MultisampleRenderPassTestInstance, TestConfig, Programs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, compatibilityTestName.c_str(), compatibilityTestName.c_str(), compatibilityTestConfig));
2725 					}
2726 				}
2727 			}
2728 
2729 			if (layerCount == 1)
2730 				group->addChild(formatGroup.release());
2731 			else
2732 				layerGroup->addChild(formatGroup.release());
2733 		}
2734 
2735 		if (layerCount != 1)
2736 			group->addChild(layerGroup.release());
2737 	}
2738 }
2739 
2740 } // anonymous
2741 
createRenderPassMultisampleResolveTests(tcu::TestContext & testCtx)2742 tcu::TestCaseGroup* createRenderPassMultisampleResolveTests (tcu::TestContext& testCtx)
2743 {
2744 	return createTestGroup(testCtx, "multisample_resolve", "Multisample render pass resolve tests", initTests, RENDERPASS_TYPE_LEGACY);
2745 }
2746 
createRenderPass2MultisampleResolveTests(tcu::TestContext & testCtx)2747 tcu::TestCaseGroup* createRenderPass2MultisampleResolveTests (tcu::TestContext& testCtx)
2748 {
2749 	return createTestGroup(testCtx, "multisample_resolve", "Multisample render pass resolve tests", initTests, RENDERPASS_TYPE_RENDERPASS2);
2750 }
2751 
2752 } // vkt
2753