• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tests for multiple interpolation decorations in a shader stage
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawMultipleInterpolationTests.hpp"
26 
27 #include "tcuStringTemplate.hpp"
28 #include "vkCmdUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vktDrawBaseClass.hpp"
33 #include "vktTestGroupUtil.hpp"
34 #include "tcuVectorUtil.hpp"
35 
36 namespace vkt
37 {
38 namespace Draw
39 {
40 namespace
41 {
42 
43 enum Interpolation
44 {
45 	SMOOTH			= 0,
46 	FLAT			= 1,
47 	NOPERSPECTIVE	= 2,
48 	CENTROID		= 3,
49 	SAMPLE			= 4,
50 	COUNT			= 5,
51 };
52 
53 struct DrawParams
54 {
55 	vk::VkFormat				format;
56 	tcu::UVec2					size;
57 	vk::VkSampleCountFlagBits	samples;
58 	// From the SPIR-V point of view, structured test variants will allow us to test interpolation decorations on struct members
59 	// instead of plain ids.
60 	bool						useStructure;
61 	bool						includeSampleDecoration;
62 	const SharedGroupParams		groupParams;
63 };
64 
65 template<typename T>
makeSharedPtr(vk::Move<T> move)66 inline de::SharedPtr<vk::Move<T> > makeSharedPtr(vk::Move<T> move)
67 {
68 	return de::SharedPtr<vk::Move<T> >(new vk::Move<T>(move));
69 }
70 
interpolationToString(Interpolation interpolation)71 const char* interpolationToString (Interpolation interpolation)
72 {
73 	switch (interpolation)
74 	{
75 		case SMOOTH:
76 			return "smooth";
77 		case FLAT:
78 			return "flat";
79 		case NOPERSPECTIVE:
80 			return "noperspective";
81 		case CENTROID:
82 			return "centroid";
83 		case SAMPLE:
84 			return "sample";
85 		default:
86 			DE_FATAL("Invalid interpolation enum");
87 	}
88 
89 	return "";
90 }
91 
92 class DrawTestInstance : public TestInstance
93 {
94 public:
95 					DrawTestInstance	(Context& context, DrawParams params);
96 	void			render				(de::SharedPtr<Image>& colorTargetImage,
97 										 tcu::ConstPixelBufferAccess* frame,
98 										 const char* vsName,
99 										 const char* fsName,
100 										 Interpolation interpolation,
101 										 bool sampleRateShading);
102 	bool			compare				(const tcu::ConstPixelBufferAccess& result,
103 										 const tcu::ConstPixelBufferAccess& reference);
104 	tcu::TestStatus	iterate				(void);
105 
106 protected:
107 	void		preRenderCommands		(vk::VkCommandBuffer cmdBuffer, vk::VkImage colorTargetImage) const;
108 	void		drawCommands			(vk::VkCommandBuffer cmdBuffer, vk::VkPipeline pipeline, vk::VkPipelineLayout pipelineLayout,
109 										 vk::VkBuffer vertexBuffer, deUint32 pcData) const;
110 
111 #ifndef CTS_USES_VULKANSC
112 	void		beginSecondaryCmdBuffer	(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags = 0u) const;
113 	void		beginDynamicRender		(vk::VkCommandBuffer cmdBuffer, vk::VkRect2D renderArea,
114 										 vk::VkClearValue clearValue, vk::VkRenderingFlagsKHR renderingFlags = 0u) const;
115 #endif // CTS_USES_VULKANSC
116 
117 private:
118 
119 	DrawParams												m_params;
120 	de::SharedPtr<Image>									m_multisampleImage;
121 	std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > >	m_colorTargetViews;
122 	std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > >	m_multisampleViews;
123 	de::SharedPtr<Buffer>									m_vertexBuffer;
124 	vk::Move<vk::VkRenderPass>								m_renderPass;
125 	vk::Move<vk::VkFramebuffer>								m_framebuffer;
126 	vk::Move<vk::VkPipelineLayout>							m_pipelineLayout;
127 	vk::Move<vk::VkPipeline>								m_pipeline;
128 };
129 
DrawTestInstance(Context & context,DrawParams params)130 DrawTestInstance::DrawTestInstance (Context& context, DrawParams params)
131 	: TestInstance	(context)
132 	, m_params		(params)
133 {
134 }
135 
136 class DrawTestCase : public TestCase
137 {
138 public:
139 							DrawTestCase	(tcu::TestContext&	testCtx,
140 											 const std::string&	name,
141 											 const std::string&	description,
142 											 const DrawParams	params);
143 							~DrawTestCase	(void);
144 	virtual void			initPrograms	(vk::SourceCollections& programCollection) const;
145 	virtual void			checkSupport	(Context& context) const;
146 	virtual TestInstance*	createInstance	(Context& context) const;
147 private:
148 	const DrawParams		m_params;
149 };
150 
DrawTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const DrawParams params)151 DrawTestCase::DrawTestCase (tcu::TestContext& testCtx,
152 							const std::string& name,
153 							const std::string& description,
154 							const DrawParams params)
155 	: TestCase	(testCtx, name, description)
156 	, m_params	(params)
157 {
158 }
159 
~DrawTestCase(void)160 DrawTestCase::~DrawTestCase (void)
161 {
162 }
163 
initPrograms(vk::SourceCollections & programCollection) const164 void DrawTestCase::initPrograms (vk::SourceCollections& programCollection) const
165 {
166 	const std::string							blockName		= "ifb";
167 	const std::map<std::string, std::string>	replacements	=
168 	{
169 		std::pair<std::string, std::string>{"blockOpeningOut"	, (m_params.useStructure ? "layout(location = 0) out InterfaceBlock {\n" : "")},
170 		std::pair<std::string, std::string>{"blockOpeningIn"	, (m_params.useStructure ? "layout(location = 0) in InterfaceBlock {\n" : "")},
171 		std::pair<std::string, std::string>{"blockClosure"		, (m_params.useStructure ? "} " + blockName + ";\n" : "")},
172 		std::pair<std::string, std::string>{"extensions"		, (m_params.useStructure ? "#extension GL_ARB_enhanced_layouts : require\n" : "")},
173 		std::pair<std::string, std::string>{"accessPrefix"		, (m_params.useStructure ? blockName + "." : "")},
174 		std::pair<std::string, std::string>{"outQual"			, (m_params.useStructure ? "" : "out ")},
175 		std::pair<std::string, std::string>{"inQual"			, (m_params.useStructure ? "" : "in ")},
176 		std::pair<std::string, std::string>{"indent"			, (m_params.useStructure ? "    " : "")},
177 	};
178 
179 	std::ostringstream vertShaderMultiStream;
180 	vertShaderMultiStream
181 		<< "#version 430\n"
182 		<< "${extensions}"
183 		<< "\n"
184 		<< "layout(location = 0) in vec4 in_position;\n"
185 		<< "layout(location = 1) in vec4 in_color;\n"
186 		<< "\n"
187 		<< "${blockOpeningOut}"
188 		<< "${indent}layout(location = 0) ${outQual}vec4 out_color_smooth;\n"
189 		<< "${indent}layout(location = 1) ${outQual}flat vec4 out_color_flat;\n"
190 		<< "${indent}layout(location = 2) ${outQual}noperspective vec4 out_color_noperspective;\n"
191 		<< "${indent}layout(location = 3) ${outQual}centroid vec4 out_color_centroid;\n"
192 		<< (m_params.includeSampleDecoration ? "${indent}layout(location = 4) ${outQual}sample vec4 out_color_sample;\n" : "")
193 		<< "${blockClosure}"
194 		<< "\n"
195 		<< "void main()\n"
196 		<< "{\n"
197 		<< "    ${accessPrefix}out_color_smooth = in_color;\n"
198 		<< "    ${accessPrefix}out_color_flat = in_color;\n"
199 		<< "    ${accessPrefix}out_color_noperspective = in_color;\n"
200 		<< "    ${accessPrefix}out_color_centroid = in_color;\n"
201 		<< (m_params.includeSampleDecoration ? "    ${accessPrefix}out_color_sample = in_color;\n" : "")
202 		<< "    gl_Position = in_position;\n"
203 		<< "}\n"
204 		;
205 	const tcu::StringTemplate vertShaderMulti(vertShaderMultiStream.str());
206 
207 	const auto colorCount = (m_params.includeSampleDecoration ? COUNT : (COUNT - 1));
208 
209 	std::ostringstream fragShaderMultiStream;
210 	fragShaderMultiStream
211 		<< "#version 430\n"
212 		<< "${extensions}"
213 		<< "\n"
214 		<< "${blockOpeningIn}"
215 		<< "${indent}layout(location = 0) ${inQual}vec4 in_color_smooth;\n"
216 		<< "${indent}layout(location = 1) ${inQual}flat vec4 in_color_flat;\n"
217 		<< "${indent}layout(location = 2) ${inQual}noperspective vec4 in_color_noperspective;\n"
218 		<< "${indent}layout(location = 3) ${inQual}centroid vec4 in_color_centroid;\n"
219 		<< (m_params.includeSampleDecoration ? "${indent}layout(location = 4) ${inQual}sample vec4 in_color_sample;\n" : "")
220 		<< "${blockClosure}"
221 		<< "\n"
222 		<< "layout(push_constant, std430) uniform PushConstants {\n"
223 		<< "    uint interpolationIndex;\n"
224 		<< "} pc;\n"
225 		<< "\n"
226 		<< "layout(location=0) out vec4 out_color;\n"
227 		<< "\n"
228 		<< "void main()\n"
229 		<< "{\n"
230 		<< "    const vec4 in_colors[" + de::toString(colorCount) + "] = vec4[](\n"
231 		<< "        ${accessPrefix}in_color_smooth,\n"
232 		<< "        ${accessPrefix}in_color_flat,\n"
233 		<< "        ${accessPrefix}in_color_noperspective,\n"
234 		<< "        ${accessPrefix}in_color_centroid" << (m_params.includeSampleDecoration ? "," : "") << "\n"
235 		<< (m_params.includeSampleDecoration ? "        ${accessPrefix}in_color_sample\n" : "")
236 		<< "    );\n"
237 		<< "    out_color = in_colors[pc.interpolationIndex];\n"
238 		<< "}\n"
239 		;
240 	const tcu::StringTemplate fragShaderMulti(fragShaderMultiStream.str());
241 
242 	const tcu::StringTemplate vertShaderSingle
243 	{
244 		"#version 430\n"
245 		"${extensions}"
246 		"\n"
247 		"layout(location = 0) in vec4 in_position;\n"
248 		"layout(location = 1) in vec4 in_color;\n"
249 		"\n"
250 		"${blockOpeningOut}"
251 		"${indent}layout(location = 0) ${outQual}${qualifier:opt}vec4 out_color;\n"
252 		"${blockClosure}"
253 		"\n"
254 		"void main()\n"
255 		"{\n"
256 		"    ${accessPrefix}out_color = in_color;\n"
257 		"    gl_Position = in_position;\n"
258 		"}\n"
259 	};
260 
261 	const tcu::StringTemplate fragShaderSingle
262 	{
263 		"#version 430\n"
264 		"${extensions}"
265 		"\n"
266 		"${blockOpeningIn}"
267 		"${indent}layout(location = 0) ${inQual}${qualifier:opt}vec4 in_color;\n"
268 		"${blockClosure}"
269 		"\n"
270 		"layout(location = 0) out vec4 out_color;\n"
271 		"\n"
272 		"void main()\n"
273 		"{\n"
274 		"    out_color = ${accessPrefix}in_color;\n"
275 		"}\n"
276 	};
277 
278 	std::map<std::string, std::string>	smooth			= replacements;
279 	std::map<std::string, std::string>	flat			= replacements;
280 	std::map<std::string, std::string>	noperspective	= replacements;
281 	std::map<std::string, std::string>	centroid		= replacements;
282 	std::map<std::string, std::string>	sample			= replacements;
283 
284 	flat["qualifier"]			= "flat ";
285 	noperspective["qualifier"]	= "noperspective ";
286 	centroid["qualifier"]		= "centroid ";
287 	sample["qualifier"]			= "sample ";
288 
289 	programCollection.glslSources.add("vert_multi")			<< glu::VertexSource(vertShaderMulti.specialize(replacements));
290 	programCollection.glslSources.add("frag_multi")			<< glu::FragmentSource(fragShaderMulti.specialize(replacements));
291 	programCollection.glslSources.add("vert_smooth")		<< glu::VertexSource(vertShaderSingle.specialize(smooth));
292 	programCollection.glslSources.add("frag_smooth")		<< glu::FragmentSource(fragShaderSingle.specialize(smooth));
293 	programCollection.glslSources.add("vert_flat")			<< glu::VertexSource(vertShaderSingle.specialize(flat));
294 	programCollection.glslSources.add("frag_flat")			<< glu::FragmentSource(fragShaderSingle.specialize(flat));
295 	programCollection.glslSources.add("vert_noperspective")	<< glu::VertexSource(vertShaderSingle.specialize(noperspective));
296 	programCollection.glslSources.add("frag_noperspective")	<< glu::FragmentSource(fragShaderSingle.specialize(noperspective));
297 	programCollection.glslSources.add("vert_centroid")		<< glu::VertexSource(vertShaderSingle.specialize(centroid));
298 	programCollection.glslSources.add("frag_centroid")		<< glu::FragmentSource(fragShaderSingle.specialize(centroid));
299 
300 	if (m_params.includeSampleDecoration)
301 	{
302 		programCollection.glslSources.add("vert_sample")		<< glu::VertexSource(vertShaderSingle.specialize(sample));
303 		programCollection.glslSources.add("frag_sample")		<< glu::FragmentSource(fragShaderSingle.specialize(sample));
304 	}
305 }
306 
checkSupport(Context & context) const307 void DrawTestCase::checkSupport (Context& context) const
308 {
309 	if (!(m_params.samples & context.getDeviceProperties().limits.framebufferColorSampleCounts))
310 		TCU_THROW(NotSupportedError, "Multisampling with " + de::toString(m_params.samples) + " samples not supported");
311 
312 	if (m_params.includeSampleDecoration && !context.getDeviceFeatures().sampleRateShading)
313 		TCU_THROW(NotSupportedError, "Sample rate shading not supported");
314 
315 	if (m_params.groupParams->useDynamicRendering)
316 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
317 }
318 
createInstance(Context & context) const319 TestInstance* DrawTestCase::createInstance (Context& context) const
320 {
321 	return new DrawTestInstance(context, m_params);
322 }
323 
render(de::SharedPtr<Image> & colorTargetImage,tcu::ConstPixelBufferAccess * frame,const char * vsName,const char * fsName,Interpolation interpolation,bool sampleRateShading)324 void DrawTestInstance::render (de::SharedPtr<Image>& colorTargetImage,
325 							   tcu::ConstPixelBufferAccess* frame,
326 							   const char* vsName,
327 							   const char* fsName,
328 							   Interpolation interpolation,
329 							   bool sampleRateShading)
330 {
331 	const deUint32							pcData				= static_cast<deUint32>(interpolation);
332 	const deUint32							pcDataSize			= static_cast<deUint32>(sizeof(pcData));
333 	const bool								useMultisampling	= (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
334 	const vk::VkBool32						sampleShadingEnable	= (sampleRateShading ? VK_TRUE : VK_FALSE);
335 	const vk::DeviceInterface&				vk					= m_context.getDeviceInterface();
336 	const vk::VkDevice						device				= m_context.getDevice();
337 	const vk::Unique<vk::VkShaderModule>	vs					(createShaderModule(vk, device, m_context.getBinaryCollection().get(vsName), 0));
338 	const vk::Unique<vk::VkShaderModule>	fs					(createShaderModule(vk, device, m_context.getBinaryCollection().get(fsName), 0));
339 	const CmdPoolCreateInfo					cmdPoolCreateInfo	= m_context.getUniversalQueueFamilyIndex();
340 	vk::Move<vk::VkCommandPool>				cmdPool				= createCommandPool(vk, device, &cmdPoolCreateInfo);
341 	vk::Move<vk::VkCommandBuffer>			cmdBuffer			= vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
342 	vk::Move<vk::VkCommandBuffer>			secCmdBuffer;
343 
344 	m_colorTargetViews.clear();
345 	m_multisampleViews.clear();
346 
347 	// Create color buffer images
348 	{
349 		const vk::VkExtent3D		targetImageExtent		= { m_params.size.x(), m_params.size.y(), 1 };
350 		const vk::VkImageUsageFlags	usage					= vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT;
351 		const ImageCreateInfo		targetImageCreateInfo	(vk::VK_IMAGE_TYPE_2D,
352 															 m_params.format,
353 															 targetImageExtent,
354 															 1,
355 															 1,
356 															 vk::VK_SAMPLE_COUNT_1_BIT,
357 															 vk::VK_IMAGE_TILING_OPTIMAL,
358 															 usage);
359 
360 		colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo,
361 												 m_context.getDefaultAllocator(),
362 												 m_context.getUniversalQueueFamilyIndex());
363 
364 		if (useMultisampling)
365 		{
366 			const ImageCreateInfo multisampleImageCreateInfo (vk::VK_IMAGE_TYPE_2D,
367 															  m_params.format,
368 															  targetImageExtent,
369 															  1,
370 															  1,
371 															  m_params.samples,
372 															  vk::VK_IMAGE_TILING_OPTIMAL,
373 															  usage);
374 
375 			m_multisampleImage = Image::createAndAlloc(vk, device, multisampleImageCreateInfo,
376 													 m_context.getDefaultAllocator(),
377 													 m_context.getUniversalQueueFamilyIndex());
378 		}
379 	}
380 
381 	{
382 		const ImageViewCreateInfo colorTargetViewInfo(colorTargetImage->object(),
383 													  vk::VK_IMAGE_VIEW_TYPE_2D,
384 													  m_params.format);
385 
386 		m_colorTargetViews.push_back(makeSharedPtr(createImageView(vk, device, &colorTargetViewInfo)));
387 
388 		if (useMultisampling)
389 		{
390 			const ImageViewCreateInfo multisamplingTargetViewInfo(m_multisampleImage->object(),
391 																  vk::VK_IMAGE_VIEW_TYPE_2D,
392 																  m_params.format);
393 
394 			m_multisampleViews.push_back(makeSharedPtr(createImageView(vk, device, &multisamplingTargetViewInfo)));
395 		}
396 	}
397 
398 	// Create render pass and framebuffer
399 	if (!m_params.groupParams->useDynamicRendering)
400 	{
401 		RenderPassCreateInfo					renderPassCreateInfo;
402 		std::vector<vk::VkImageView>			attachments;
403 		std::vector<vk::VkAttachmentReference>	colorAttachmentRefs;
404 		std::vector<vk::VkAttachmentReference>	multisampleAttachmentRefs;
405 		deUint32								attachmentNdx				= 0;
406 
407 		{
408 			const vk::VkAttachmentReference	colorAttachmentReference	=
409 			{
410 				attachmentNdx++,
411 				vk::VK_IMAGE_LAYOUT_GENERAL
412 			};
413 
414 			colorAttachmentRefs.push_back(colorAttachmentReference);
415 
416 			renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
417 																	 vk::VK_SAMPLE_COUNT_1_BIT,
418 																	 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
419 																	 vk::VK_ATTACHMENT_STORE_OP_STORE,
420 																	 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
421 																	 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
422 																	 vk::VK_IMAGE_LAYOUT_UNDEFINED,
423 																	 vk::VK_IMAGE_LAYOUT_GENERAL));
424 
425 			if (useMultisampling)
426 			{
427 				const vk::VkAttachmentReference	multiSampleAttachmentReference	=
428 				{
429 					attachmentNdx++,
430 					vk::VK_IMAGE_LAYOUT_GENERAL
431 				};
432 
433 				multisampleAttachmentRefs.push_back(multiSampleAttachmentReference);
434 
435 				renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
436 																		 m_params.samples,
437 																		 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
438 																		 vk::VK_ATTACHMENT_STORE_OP_STORE,
439 																		 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
440 																		 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
441 																		 vk::VK_IMAGE_LAYOUT_UNDEFINED,
442 																		 vk::VK_IMAGE_LAYOUT_GENERAL));
443 			}
444 		}
445 
446 		renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
447 														   0,
448 														   0,
449 														   DE_NULL,
450 														   (deUint32)colorAttachmentRefs.size(),
451 														   useMultisampling ? &multisampleAttachmentRefs[0] : &colorAttachmentRefs[0],
452 														   useMultisampling ? &colorAttachmentRefs[0] : DE_NULL,
453 														   AttachmentReference(),
454 														   0,
455 														   DE_NULL));
456 
457 		m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
458 
459 		for (deUint32 frameNdx = 0; frameNdx < m_colorTargetViews.size(); frameNdx++)
460 		{
461 			attachments.push_back(**m_colorTargetViews[frameNdx]);
462 
463 			if (useMultisampling)
464 				attachments.push_back(**m_multisampleViews[frameNdx]);
465 		}
466 
467 		const vk::VkFramebufferCreateInfo framebufferCreateInfo =
468 		{
469 			vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
470 			DE_NULL,
471 			0u,
472 			*m_renderPass,
473 			(deUint32)attachments.size(),
474 			&attachments[0],
475 			m_params.size.x(),
476 			m_params.size.y(),
477 			1
478 		};
479 
480 		m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
481 	}
482 
483 	// Create vertex buffer.
484 	{
485 		const PositionColorVertex	vertices[]		=
486 		{
487 			PositionColorVertex(
488 				tcu::Vec4(-1.5f, -0.4f, 1.0f, 2.0f),	// Coord
489 				tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)),		// Color
490 
491 			PositionColorVertex(
492 				tcu::Vec4(0.4f, -0.4f, 0.5f, 0.5f),		// Coord
493 				tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)),		// Color
494 
495 			PositionColorVertex(
496 				tcu::Vec4(0.3f, 0.8f, 0.0f, 1.0f),		// Coord
497 				tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f))		// Color
498 		};
499 
500 		const vk::VkDeviceSize		dataSize		= DE_LENGTH_OF_ARRAY(vertices) * sizeof(PositionColorVertex);
501 									m_vertexBuffer	= Buffer::createAndAlloc(vk,
502 																			 device,
503 																			 BufferCreateInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
504 																			 m_context.getDefaultAllocator(),
505 																			 vk::MemoryRequirement::HostVisible);
506 		deUint8*					ptr				= reinterpret_cast<deUint8*>(m_vertexBuffer->getBoundMemory().getHostPtr());
507 
508 		deMemcpy(ptr, vertices, static_cast<size_t>(dataSize));
509 		flushMappedMemoryRange(vk,
510 							   device,
511 							   m_vertexBuffer->getBoundMemory().getMemory(),
512 							   m_vertexBuffer->getBoundMemory().getOffset(),
513 							   VK_WHOLE_SIZE);
514 	}
515 
516 	// Create pipeline
517 	{
518 		const vk::VkViewport							viewport							= vk::makeViewport(m_params.size.x(), m_params.size.y());
519 		const vk::VkRect2D								scissor								= vk::makeRect2D(m_params.size.x(), m_params.size.y());
520 		const auto										pcRange								= vk::makePushConstantRange(vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize);
521 		const std::vector<vk::VkPushConstantRange>		pcRanges							(1u, pcRange);
522 		const PipelineLayoutCreateInfo					pipelineLayoutCreateInfo			(0u, nullptr, static_cast<deUint32>(pcRanges.size()), pcRanges.data());
523 
524 		m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
525 
526 		PipelineCreateInfo								pipelineCreateInfo					(*m_pipelineLayout, *m_renderPass, 0, 0);
527 
528 		const vk::VkVertexInputBindingDescription		vertexInputBindingDescription		=
529 		{
530 			0,
531 			(deUint32)sizeof(tcu::Vec4) * 2,
532 			vk::VK_VERTEX_INPUT_RATE_VERTEX
533 		};
534 
535 		const vk::VkVertexInputAttributeDescription						vertexInputAttributeDescriptions[2]	=
536 		{
537 			{ 0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
538 			{ 1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
539 		};
540 
541 		std::vector<PipelineCreateInfo::ColorBlendState::Attachment>	vkCbAttachmentStates				(1u);
542 		PipelineCreateInfo::VertexInputState							vertexInputState					= PipelineCreateInfo::VertexInputState(1,
543 																																				   &vertexInputBindingDescription,
544 																																				   2,
545 																																				   vertexInputAttributeDescriptions);
546 
547 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
548 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
549 		pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
550 		pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
551 		pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState((deUint32)vkCbAttachmentStates.size(), &vkCbAttachmentStates[0]));
552 		pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
553 		pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
554 		pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
555 		pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState(m_params.samples, sampleShadingEnable, 1.0f));
556 
557 #ifndef CTS_USES_VULKANSC
558 		std::vector<vk::VkFormat> colorAttachmentFormats(m_colorTargetViews.size(), m_params.format);
559 		vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
560 		{
561 			vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
562 			DE_NULL,
563 			0u,
564 			static_cast<deUint32>(colorAttachmentFormats.size()),
565 			colorAttachmentFormats.data(),
566 			vk::VK_FORMAT_UNDEFINED,
567 			vk::VK_FORMAT_UNDEFINED
568 		};
569 
570 		if (m_params.groupParams->useDynamicRendering)
571 			pipelineCreateInfo.pNext = &renderingCreateInfo;
572 #endif // CTS_USES_VULKANSC
573 
574 		m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
575 	}
576 
577 	// Queue draw and read results.
578 	{
579 		const vk::VkQueue				queue				= m_context.getUniversalQueue();
580 		const vk::VkRect2D				renderArea			= vk::makeRect2D(m_params.size.x(), m_params.size.y());
581 		const vk::VkBuffer				buffer				= m_vertexBuffer->object();
582 		const vk::VkOffset3D			zeroOffset			= { 0, 0, 0 };
583 		const auto						clearValueColor		= vk::makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
584 
585 #ifndef CTS_USES_VULKANSC
586 		if (m_params.groupParams->useSecondaryCmdBuffer)
587 		{
588 			secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
589 
590 			// record secondary command buffer
591 			if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
592 			{
593 				beginSecondaryCmdBuffer(*secCmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
594 				beginDynamicRender(*secCmdBuffer, renderArea, clearValueColor);
595 			}
596 			else
597 				beginSecondaryCmdBuffer(*secCmdBuffer);
598 
599 			drawCommands(*secCmdBuffer, *m_pipeline, *m_pipelineLayout, buffer, pcData);
600 
601 			if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
602 				endRendering(vk, *secCmdBuffer);
603 
604 			endCommandBuffer(vk, *secCmdBuffer);
605 
606 			// record primary command buffer
607 			beginCommandBuffer(vk, *cmdBuffer, 0u);
608 			preRenderCommands(*cmdBuffer, colorTargetImage->object());
609 
610 			if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
611 				beginDynamicRender(*cmdBuffer, renderArea, clearValueColor, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
612 
613 			vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
614 
615 			if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
616 				endRendering(vk, *cmdBuffer);
617 
618 			endCommandBuffer(vk, *cmdBuffer);
619 		}
620 		else if (m_params.groupParams->useDynamicRendering)
621 		{
622 			beginCommandBuffer(vk, *cmdBuffer);
623 
624 			preRenderCommands(*cmdBuffer, colorTargetImage->object());
625 			beginDynamicRender(*cmdBuffer, renderArea, clearValueColor);
626 			drawCommands(*cmdBuffer, *m_pipeline, *m_pipelineLayout, buffer, pcData);
627 			endRendering(vk, *cmdBuffer);
628 
629 			endCommandBuffer(vk, *cmdBuffer);
630 		}
631 #endif // CTS_USES_VULKANSC
632 
633 		if (!m_params.groupParams->useDynamicRendering)
634 		{
635 			const deUint32					imagesCount	= static_cast<deUint32>(m_colorTargetViews.size() + m_multisampleViews.size());
636 			std::vector<vk::VkClearValue>	clearValues	(2, clearValueColor);
637 
638 			beginCommandBuffer(vk, *cmdBuffer);
639 
640 			preRenderCommands(*cmdBuffer, colorTargetImage->object());
641 			beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, imagesCount, &clearValues[0]);
642 			drawCommands(*cmdBuffer, *m_pipeline, *m_pipelineLayout, buffer, pcData);
643 			endRenderPass(vk, *cmdBuffer);
644 
645 			endCommandBuffer(vk, *cmdBuffer);
646 		}
647 
648 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
649 
650 		*frame = colorTargetImage->readSurface(queue,
651 											   m_context.getDefaultAllocator(),
652 											   vk::VK_IMAGE_LAYOUT_GENERAL,
653 											   zeroOffset,
654 											   (int)m_params.size.x(),
655 											   (int)m_params.size.y(),
656 											   vk::VK_IMAGE_ASPECT_COLOR_BIT);
657 	}
658 }
659 
preRenderCommands(vk::VkCommandBuffer cmdBuffer,vk::VkImage colorTargetImage) const660 void DrawTestInstance::preRenderCommands(vk::VkCommandBuffer cmdBuffer, vk::VkImage colorTargetImage) const
661 {
662 	if (!m_params.groupParams->useDynamicRendering)
663 		return;
664 
665 	const vk::DeviceInterface& vk = m_context.getDeviceInterface();
666 	initialTransitionColor2DImage(vk, cmdBuffer, colorTargetImage, vk::VK_IMAGE_LAYOUT_GENERAL,
667 		vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
668 
669 	if (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT)
670 	{
671 		initialTransitionColor2DImage(vk, cmdBuffer, m_multisampleImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
672 			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
673 	}
674 }
675 
drawCommands(vk::VkCommandBuffer cmdBuffer,vk::VkPipeline pipeline,vk::VkPipelineLayout pipelineLayout,vk::VkBuffer vertexBuffer,deUint32 pcData) const676 void DrawTestInstance::drawCommands(vk::VkCommandBuffer cmdBuffer, vk::VkPipeline pipeline, vk::VkPipelineLayout pipelineLayout,
677 									vk::VkBuffer vertexBuffer, deUint32 pcData) const
678 {
679 	const vk::DeviceInterface&	vk					= m_context.getDeviceInterface();
680 	const vk::VkDeviceSize		vertexBufferOffset	= 0;
681 	const deUint32				pcDataSize			= static_cast<deUint32>(sizeof(pcData));
682 
683 	vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
684 	vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
685 	vk.cmdPushConstants(cmdBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize, &pcData);
686 	vk.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
687 }
688 
compare(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference)689 bool DrawTestInstance::compare (const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& reference)
690 {
691 	DE_ASSERT(result.getSize() == reference.getSize());
692 
693 	const tcu::IVec4	threshold	(1u, 1u, 1u, 1u);
694 
695 	for (int y = 0; y < result.getHeight(); y++)
696 	{
697 		for (int x = 0; x < result.getWidth(); x++)
698 		{
699 			tcu::IVec4	refPix	= reference.getPixelInt(x, y);
700 			tcu::IVec4	cmpPix	= result.getPixelInt(x, y);
701 			tcu::IVec4	diff	= tcu::abs(refPix - cmpPix);
702 
703 			if (!tcu::boolAll(tcu::lessThanEqual(diff, threshold)))
704 				return false;
705 		}
706 	}
707 
708 	return true;
709 }
710 
711 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(vk::VkCommandBuffer cmdBuffer,vk::VkRenderingFlagsKHR renderingFlags) const712 void DrawTestInstance::beginSecondaryCmdBuffer(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags) const
713 {
714 	std::vector<vk::VkFormat> colorAttachmentFormats(m_colorTargetViews.size(), m_params.format);
715 	vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
716 	{
717 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR,	// VkStructureType					sType;
718 		DE_NULL,																// const void*						pNext;
719 		renderingFlags,															// VkRenderingFlagsKHR				flags;
720 		0u,																		// uint32_t							viewMask;
721 		(deUint32)colorAttachmentFormats.size(),								// uint32_t							colorAttachmentCount;
722 		colorAttachmentFormats.data(),											// const VkFormat*					pColorAttachmentFormats;
723 		vk::VK_FORMAT_UNDEFINED,												// VkFormat							depthAttachmentFormat;
724 		vk::VK_FORMAT_UNDEFINED,												// VkFormat							stencilAttachmentFormat;
725 		m_params.samples,														// VkSampleCountFlagBits			rasterizationSamples;
726 	};
727 	const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo = vk::initVulkanStructure(&inheritanceRenderingInfo);
728 
729 	vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
730 	if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
731 		usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
732 
733 	const vk::VkCommandBufferBeginInfo commandBufBeginParams
734 	{
735 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,						// VkStructureType					sType;
736 		DE_NULL,																// const void*						pNext;
737 		usageFlags,																// VkCommandBufferUsageFlags		flags;
738 		&bufferInheritanceInfo
739 	};
740 
741 	const vk::DeviceInterface& vk = m_context.getDeviceInterface();
742 	VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
743 }
744 
beginDynamicRender(vk::VkCommandBuffer cmdBuffer,vk::VkRect2D renderArea,vk::VkClearValue clearValue,vk::VkRenderingFlagsKHR renderingFlags) const745 void DrawTestInstance::beginDynamicRender(vk::VkCommandBuffer cmdBuffer, vk::VkRect2D renderArea, vk::VkClearValue clearValue, vk::VkRenderingFlagsKHR renderingFlags) const
746 {
747 	const vk::DeviceInterface& vk	= m_context.getDeviceInterface();
748 	const deUint32 imagesCount		= static_cast<deUint32>(m_colorTargetViews.size());
749 
750 	std::vector<vk::VkRenderingAttachmentInfoKHR> colorAttachments(imagesCount,
751 		{
752 			vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR,	// VkStructureType						sType;
753 			DE_NULL,												// const void*							pNext;
754 			DE_NULL,												// VkImageView							imageView;
755 			vk::VK_IMAGE_LAYOUT_GENERAL,							// VkImageLayout						imageLayout;
756 			vk::VK_RESOLVE_MODE_NONE,								// VkResolveModeFlagBits				resolveMode;
757 			DE_NULL,												// VkImageView							resolveImageView;
758 			vk::VK_IMAGE_LAYOUT_GENERAL,							// VkImageLayout						resolveImageLayout;
759 			vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp					loadOp;
760 			vk::VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp					storeOp;
761 			clearValue												// VkClearValue							clearValue;
762 		});
763 
764 	for (deUint32 i = 0; i < imagesCount; ++i)
765 	{
766 		if (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT)
767 		{
768 			colorAttachments[i].imageView = **m_multisampleViews[i];
769 			colorAttachments[i].resolveMode = vk::VK_RESOLVE_MODE_AVERAGE_BIT;
770 			colorAttachments[i].resolveImageView = **m_colorTargetViews[i];
771 		}
772 		else
773 			colorAttachments[i].imageView = **m_colorTargetViews[i];
774 	}
775 
776 	vk::VkRenderingInfoKHR renderingInfo
777 	{
778 		vk::VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
779 		DE_NULL,
780 		renderingFlags,											// VkRenderingFlagsKHR					flags;
781 		renderArea,												// VkRect2D								renderArea;
782 		1u,														// deUint32								layerCount;
783 		0u,														// deUint32								viewMask;
784 		imagesCount,											// deUint32								colorAttachmentCount;
785 		colorAttachments.data(),								// const VkRenderingAttachmentInfoKHR*	pColorAttachments;
786 		DE_NULL,												// const VkRenderingAttachmentInfoKHR*	pDepthAttachment;
787 		DE_NULL,												// const VkRenderingAttachmentInfoKHR*	pStencilAttachment;
788 	};
789 
790 	vk.cmdBeginRendering(cmdBuffer, &renderingInfo);
791 }
792 #endif // CTS_USES_VULKANSC
793 
iterate(void)794 tcu::TestStatus DrawTestInstance::iterate (void)
795 {
796 	tcu::TestLog&						log						= m_context.getTestContext().getLog();
797 	const bool							useMultisampling		= (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
798 	const deUint32						frameCount				= static_cast<deUint32>(COUNT);
799 	std::vector<de::SharedPtr<Image> >	resImages				(frameCount);
800 	de::SharedPtr<Image>				smoothImage[2];
801 	de::SharedPtr<Image>				flatImage[2];
802 	de::SharedPtr<Image>				noperspectiveImage[2];
803 	de::SharedPtr<Image>				centroidImage[2];
804 	de::SharedPtr<Image>				sampleImage[2];
805 	tcu::ConstPixelBufferAccess			resFrames[frameCount];
806 	tcu::ConstPixelBufferAccess			refFrames[frameCount];
807 	tcu::ConstPixelBufferAccess			refSRSFrames[frameCount]; // Using sample rate shading.
808 
809 	for (int interpolationType = 0; interpolationType < COUNT; ++interpolationType)
810 	{
811 		// Avoid generating a result image for the sample decoration if we're not using it.
812 		if (!m_params.includeSampleDecoration && interpolationType == Interpolation::SAMPLE)
813 			continue;
814 
815 		render(resImages[interpolationType], &resFrames[interpolationType], "vert_multi", "frag_multi", static_cast<Interpolation>(interpolationType), false);
816 	}
817 
818 	for (int i = 0; i < 2; ++i)
819 	{
820 		const bool useSampleRateShading = (i > 0);
821 
822 		// Sample rate shading is an alternative good result for cases using the sample decoration.
823 		if (useSampleRateShading && !m_params.includeSampleDecoration)
824 			continue;
825 
826 		tcu::ConstPixelBufferAccess *framesArray = (useSampleRateShading ? refSRSFrames : refFrames);
827 
828 		render(smoothImage[i],			&framesArray[SMOOTH],			"vert_smooth",			"frag_smooth",			SMOOTH,			useSampleRateShading);
829 		render(flatImage[i],			&framesArray[FLAT],				"vert_flat",			"frag_flat",			FLAT,			useSampleRateShading);
830 		render(noperspectiveImage[i],	&framesArray[NOPERSPECTIVE],	"vert_noperspective",	"frag_noperspective",	NOPERSPECTIVE,	useSampleRateShading);
831 		render(centroidImage[i],		&framesArray[CENTROID],			"vert_centroid",		"frag_centroid",		CENTROID,		useSampleRateShading);
832 
833 		// Avoid generating a reference image for the sample interpolation if we're not using it.
834 		if (m_params.includeSampleDecoration)
835 			render(sampleImage[i],		&framesArray[SAMPLE],			"vert_sample",			"frag_sample",			SAMPLE,			useSampleRateShading);
836 	}
837 
838 	for (deUint32 resNdx = 0; resNdx < frameCount; resNdx++)
839 	{
840 		if (!m_params.includeSampleDecoration && resNdx == SAMPLE)
841 			continue;
842 
843 		const std::string resName = interpolationToString((Interpolation)resNdx);
844 
845 		log	<< tcu::TestLog::ImageSet(resName, resName)
846 			<< tcu::TestLog::Image("Result", "Result", resFrames[resNdx])
847 			<< tcu::TestLog::Image("Reference", "Reference", refFrames[resNdx]);
848 		if (m_params.includeSampleDecoration)
849 			log << tcu::TestLog::Image("ReferenceSRS", "Reference with sample shading", refSRSFrames[resNdx]);
850 		log	<< tcu::TestLog::EndImageSet;
851 
852 		for (deUint32 refNdx = 0; refNdx < frameCount; refNdx++)
853 		{
854 			if (!m_params.includeSampleDecoration && refNdx == SAMPLE)
855 				continue;
856 
857 			const std::string refName = interpolationToString((Interpolation)refNdx);
858 
859 			if (resNdx == refNdx)
860 			{
861 				if (!compare(resFrames[resNdx], refFrames[refNdx]) && (!m_params.includeSampleDecoration || !compare(resFrames[resNdx], refSRSFrames[refNdx])))
862 					return tcu::TestStatus::fail(resName + " produced different results");
863 			}
864 			else if (!useMultisampling &&
865 				((resNdx == SMOOTH && refNdx == CENTROID) ||
866 				 (resNdx == CENTROID && refNdx == SMOOTH) ||
867 				 (resNdx == SMOOTH && refNdx == SAMPLE)   ||
868 				 (resNdx == SAMPLE && refNdx == SMOOTH)   ||
869 				 (resNdx == CENTROID && refNdx == SAMPLE) ||
870 				 (resNdx == SAMPLE && refNdx == CENTROID)))
871 			{
872 				if (!compare(resFrames[resNdx], refFrames[refNdx]))
873 					return tcu::TestStatus::fail(resName + " and " + refName + " produced different results without multisampling");
874 			}
875 			else
876 			{
877 				// "smooth" means lack of centroid and sample.
878 				// Spec does not specify exactly what "smooth" should be, so it can match centroid or sample.
879 				// "centroid" and "sample" may also produce the same results.
880 				if (!((resNdx == SMOOTH && refNdx == CENTROID)   ||
881 					  (resNdx == CENTROID && refNdx == SMOOTH)   ||
882 					  (resNdx == SMOOTH && refNdx == SAMPLE)     ||
883 					  (resNdx == SAMPLE && refNdx == SMOOTH)     ||
884 					  (resNdx == CENTROID && refNdx == SAMPLE)   ||
885 					  (resNdx == SAMPLE && refNdx == CENTROID)   ))
886 				{
887 					if (compare(resFrames[resNdx], refFrames[refNdx]))
888 						return tcu::TestStatus::fail(resName + " and " + refName + " produced same result");
889 				}
890 			}
891 		}
892 	}
893 
894 	return tcu::TestStatus::pass("Results differ and references match");
895 }
896 
createTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)897 void createTests (tcu::TestCaseGroup* testGroup, const SharedGroupParams groupParams)
898 {
899 	tcu::TestContext&	testCtx	= testGroup->getTestContext();
900 	const vk::VkFormat	format	= vk::VK_FORMAT_R8G8B8A8_UNORM;
901 	const tcu::UVec2	size	(128, 128);
902 
903 	struct TestVariant
904 	{
905 		const std::string				name;
906 		const std::string				desc;
907 		const vk::VkSampleCountFlagBits	samples;
908 	};
909 
910 	static const std::vector<TestVariant> testVariants
911 	{
912 		{ "1_sample",	"Without multisampling",	vk::VK_SAMPLE_COUNT_1_BIT	},
913 		{ "2_samples",	"2 samples",				vk::VK_SAMPLE_COUNT_2_BIT	},
914 		{ "4_samples",	"4 samples",				vk::VK_SAMPLE_COUNT_4_BIT	},
915 		{ "8_samples",	"8 samples",				vk::VK_SAMPLE_COUNT_8_BIT	},
916 		{ "16_samples",	"16 samples",				vk::VK_SAMPLE_COUNT_16_BIT	},
917 		{ "32_samples",	"32 samples",				vk::VK_SAMPLE_COUNT_32_BIT	},
918 		{ "64_samples",	"64 samples",				vk::VK_SAMPLE_COUNT_64_BIT	},
919 	};
920 
921 	struct GroupVariant
922 	{
923 		const bool			useStructure;
924 		const std::string	groupName;
925 	};
926 
927 	static const std::vector<GroupVariant> groupVariants
928 	{
929 		{ false,	"separate"		},
930 		{ true,		"structured"	},
931 	};
932 
933 	const struct
934 	{
935 		const bool			includeSampleDecoration;
936 		const std::string	groupName;
937 	} sampleVariants[]
938 	{
939 		{ false,	"no_sample_decoration"		},
940 		{ true,		"with_sample_decoration"	},
941 	};
942 
943 	for (const auto& grpVariant : groupVariants)
944 	{
945 		de::MovePtr<tcu::TestCaseGroup> group {new tcu::TestCaseGroup{testCtx, grpVariant.groupName.c_str(), ""}};
946 
947 		for (const auto& sampleVariant : sampleVariants)
948 		{
949 			de::MovePtr<tcu::TestCaseGroup> sampleGroup {new tcu::TestCaseGroup{testCtx, sampleVariant.groupName.c_str(), ""}};
950 
951 			for (const auto& testVariant : testVariants)
952 			{
953 				const DrawParams params {format, size, testVariant.samples, grpVariant.useStructure, sampleVariant.includeSampleDecoration, groupParams };
954 				sampleGroup->addChild(new DrawTestCase(testCtx, testVariant.name, testVariant.desc, params));
955 			}
956 
957 			group->addChild(sampleGroup.release());
958 		}
959 
960 		testGroup->addChild(group.release());
961 	}
962 }
963 
964 }	// anonymous
965 
createMultipleInterpolationTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)966 tcu::TestCaseGroup* createMultipleInterpolationTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
967 {
968 	return createTestGroup(testCtx,
969 						   "multiple_interpolation",
970 						   "Tests for multiple interpolation decorations in a shader stage.",
971 						   createTests,
972 						   groupParams);
973 }
974 
975 }	// Draw
976 }	// vkt
977