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