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 "vktDrawBaseClass.hpp"
32 #include "vktTestGroupUtil.hpp"
33 
34 namespace vkt
35 {
36 namespace Draw
37 {
38 namespace
39 {
40 
41 enum Interpolation
42 {
43 	SMOOTH			= 0,
44 	FLAT			= 1,
45 	NOPERSPECTIVE	= 2,
46 	CENTROID		= 3
47 };
48 
49 struct DrawParams
50 {
51 	vk::VkFormat				format;
52 	tcu::UVec2					size;
53 	vk::VkSampleCountFlagBits	samples;
54 	// From the SPIR-V point of view, structured test variants will allow us to test interpolation decorations on struct members
55 	// instead of plain ids.
56 	bool						useStructure;
57 };
58 
59 template<typename T>
makeSharedPtr(vk::Move<T> move)60 inline de::SharedPtr<vk::Move<T> > makeSharedPtr(vk::Move<T> move)
61 {
62 	return de::SharedPtr<vk::Move<T> >(new vk::Move<T>(move));
63 }
64 
interpolationToString(Interpolation interpolation)65 const char* interpolationToString (Interpolation interpolation)
66 {
67 	switch (interpolation)
68 	{
69 		case SMOOTH:
70 			return "smooth";
71 		case FLAT:
72 			return "flat";
73 		case NOPERSPECTIVE:
74 			return "noperspective";
75 		case CENTROID:
76 			return "centroid";
77 		default:
78 			DE_FATAL("Invalid interpolation enum");
79 	}
80 
81 	return "";
82 }
83 
84 class DrawTestInstance : public TestInstance
85 {
86 public:
87 					DrawTestInstance	(Context& context, DrawParams params);
88 	void			render				(std::vector<de::SharedPtr<Image> >& colorTargetImages,
89 										 tcu::ConstPixelBufferAccess* frames,
90 										 const char* vsName,
91 										 const char* fsName);
92 	bool			compare				(const tcu::ConstPixelBufferAccess& result,
93 										 const tcu::ConstPixelBufferAccess& reference);
94 	tcu::TestStatus	iterate				(void);
95 private:
96 	DrawParams		m_params;
97 };
98 
DrawTestInstance(Context & context,DrawParams params)99 DrawTestInstance::DrawTestInstance (Context& context, DrawParams params)
100 	: TestInstance	(context)
101 	, m_params		(params)
102 {
103 }
104 
105 class DrawTestCase : public TestCase
106 {
107 public:
108 							DrawTestCase	(tcu::TestContext&	testCtx,
109 											 const std::string&	name,
110 											 const std::string&	description,
111 											 const DrawParams	params);
112 							~DrawTestCase	(void);
113 	virtual void			initPrograms	(vk::SourceCollections& programCollection) const;
114 	virtual void			checkSupport	(Context& context) const;
115 	virtual TestInstance*	createInstance	(Context& context) const;
116 private:
117 	const DrawParams		m_params;
118 };
119 
DrawTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const DrawParams params)120 DrawTestCase::DrawTestCase (tcu::TestContext& testCtx,
121 							const std::string& name,
122 							const std::string& description,
123 							const DrawParams params)
124 	: TestCase	(testCtx, name, description)
125 	, m_params	(params)
126 {
127 }
128 
~DrawTestCase(void)129 DrawTestCase::~DrawTestCase (void)
130 {
131 }
132 
initPrograms(vk::SourceCollections & programCollection) const133 void DrawTestCase::initPrograms (vk::SourceCollections& programCollection) const
134 {
135 	const std::string							blockName		= "ifb";
136 	const std::map<std::string, std::string>	replacements	=
137 	{
138 		std::pair<std::string, std::string>{"blockOpeningOut"	, (m_params.useStructure ? "layout(location = 0) out InterfaceBlock {\n" : "")},
139 		std::pair<std::string, std::string>{"blockOpeningIn"	, (m_params.useStructure ? "layout(location = 0) in InterfaceBlock {\n" : "")},
140 		std::pair<std::string, std::string>{"blockClosure"		, (m_params.useStructure ? "} " + blockName + ";\n" : "")},
141 		std::pair<std::string, std::string>{"extensions"		, (m_params.useStructure ? "#extension GL_ARB_enhanced_layouts : require\n" : "")},
142 		std::pair<std::string, std::string>{"accessPrefix"		, (m_params.useStructure ? blockName + "." : "")},
143 		std::pair<std::string, std::string>{"outQual"			, (m_params.useStructure ? "" : "out ")},
144 		std::pair<std::string, std::string>{"inQual"			, (m_params.useStructure ? "" : "in ")},
145 		std::pair<std::string, std::string>{"indent"			, (m_params.useStructure ? "    " : "")},
146 	};
147 
148 	const tcu::StringTemplate vertShaderMulti
149 	{
150 		"#version 430\n"
151 		"${extensions}"
152 		"\n"
153 		"layout(location = 0) in vec4 in_position;\n"
154 		"layout(location = 1) in vec4 in_color;\n"
155 		"\n"
156 		"${blockOpeningOut}"
157 		"${indent}layout(location = 0) ${outQual}vec4 out_color_smooth;\n"
158 		"${indent}layout(location = 1) ${outQual}flat vec4 out_color_flat;\n"
159 		"${indent}layout(location = 2) ${outQual}noperspective vec4 out_color_noperspective;\n"
160 		"${indent}layout(location = 3) ${outQual}centroid vec4 out_color_centroid;\n"
161 		"${blockClosure}"
162 		"\n"
163 		"void main()\n"
164 		"{\n"
165 		"    ${accessPrefix}out_color_smooth = in_color;\n"
166 		"    ${accessPrefix}out_color_flat = in_color;\n"
167 		"    ${accessPrefix}out_color_noperspective = in_color;\n"
168 		"    ${accessPrefix}out_color_centroid = in_color;\n"
169 		"    gl_Position = in_position;\n"
170 		"}\n"
171 	};
172 
173 	const tcu::StringTemplate fragShaderMulti
174 	{
175 		"#version 430\n"
176 		"${extensions}"
177 		"\n"
178 		"${blockOpeningIn}"
179 		"${indent}layout(location = 0) ${inQual}vec4 in_color_smooth;\n"
180 		"${indent}layout(location = 1) ${inQual}flat vec4 in_color_flat;\n"
181 		"${indent}layout(location = 2) ${inQual}noperspective vec4 in_color_noperspective;\n"
182 		"${indent}layout(location = 3) ${inQual}centroid vec4 in_color_centroid;\n"
183 		"${blockClosure}"
184 		"\n"
185 		"layout(location = " + de::toString(SMOOTH) + ") out vec4 out_color_smooth;\n"
186 		"layout(location = " + de::toString(FLAT) + ") out vec4 out_color_flat;\n"
187 		"layout(location = " + de::toString(NOPERSPECTIVE) + ") out vec4 out_color_noperspective;\n"
188 		"layout(location = " + de::toString(CENTROID) + ") out vec4 out_color_centroid;\n"
189 		"\n"
190 		"void main()\n"
191 		"{\n"
192 		"    out_color_smooth = ${accessPrefix}in_color_smooth;\n"
193 		"    out_color_flat = ${accessPrefix}in_color_flat;\n"
194 		"    out_color_noperspective = ${accessPrefix}in_color_noperspective;\n"
195 		"    out_color_centroid = ${accessPrefix}in_color_centroid;\n"
196 		"}\n"
197 	};
198 
199 	const tcu::StringTemplate vertShaderSingle
200 	{
201 		"#version 430\n"
202 		"${extensions}"
203 		"\n"
204 		"layout(location = 0) in vec4 in_position;\n"
205 		"layout(location = 1) in vec4 in_color;\n"
206 		"\n"
207 		"${blockOpeningOut}"
208 		"${indent}layout(location = 0) ${outQual}${qualifier:opt}vec4 out_color;\n"
209 		"${blockClosure}"
210 		"\n"
211 		"void main()\n"
212 		"{\n"
213 		"    ${accessPrefix}out_color = in_color;\n"
214 		"    gl_Position = in_position;\n"
215 		"}\n"
216 	};
217 
218 	const tcu::StringTemplate fragShaderSingle
219 	{
220 		"#version 430\n"
221 		"${extensions}"
222 		"\n"
223 		"${blockOpeningIn}"
224 		"${indent}layout(location = 0) ${inQual}${qualifier:opt}vec4 in_color;\n"
225 		"${blockClosure}"
226 		"\n"
227 		"layout(location = 0) out vec4 out_color;\n"
228 		"\n"
229 		"void main()\n"
230 		"{\n"
231 		"    out_color = ${accessPrefix}in_color;\n"
232 		"}\n"
233 	};
234 
235 	std::map<std::string, std::string>	smooth			= replacements;
236 	std::map<std::string, std::string>	flat			= replacements;
237 	std::map<std::string, std::string>	noperspective	= replacements;
238 	std::map<std::string, std::string>	centroid		= replacements;
239 
240 	flat["qualifier"]			= "flat ";
241 	noperspective["qualifier"]	= "noperspective ";
242 	centroid["qualifier"]		= "centroid ";
243 
244 	programCollection.glslSources.add("vert_multi")			<< glu::VertexSource(vertShaderMulti.specialize(replacements));
245 	programCollection.glslSources.add("frag_multi")			<< glu::FragmentSource(fragShaderMulti.specialize(replacements));
246 	programCollection.glslSources.add("vert_smooth")		<< glu::VertexSource(vertShaderSingle.specialize(smooth));
247 	programCollection.glslSources.add("frag_smooth")		<< glu::FragmentSource(fragShaderSingle.specialize(smooth));
248 	programCollection.glslSources.add("vert_flat")			<< glu::VertexSource(vertShaderSingle.specialize(flat));
249 	programCollection.glslSources.add("frag_flat")			<< glu::FragmentSource(fragShaderSingle.specialize(flat));
250 	programCollection.glslSources.add("vert_noperspective")	<< glu::VertexSource(vertShaderSingle.specialize(noperspective));
251 	programCollection.glslSources.add("frag_noperspective")	<< glu::FragmentSource(fragShaderSingle.specialize(noperspective));
252 	programCollection.glslSources.add("vert_centroid")		<< glu::VertexSource(vertShaderSingle.specialize(centroid));
253 	programCollection.glslSources.add("frag_centroid")		<< glu::FragmentSource(fragShaderSingle.specialize(centroid));
254 }
255 
checkSupport(Context & context) const256 void DrawTestCase::checkSupport (Context& context) const
257 {
258 	if (!(m_params.samples & context.getDeviceProperties().limits.framebufferColorSampleCounts))
259 		throw tcu::NotSupportedError("Multisampling with " + de::toString(m_params.samples) + " samples not supported");
260 }
261 
createInstance(Context & context) const262 TestInstance* DrawTestCase::createInstance (Context& context) const
263 {
264 	return new DrawTestInstance(context, m_params);
265 }
266 
render(std::vector<de::SharedPtr<Image>> & colorTargetImages,tcu::ConstPixelBufferAccess * frames,const char * vsName,const char * fsName)267 void DrawTestInstance::render (std::vector<de::SharedPtr<Image> >& colorTargetImages,
268 							   tcu::ConstPixelBufferAccess* frames,
269 							   const char* vsName,
270 							   const char* fsName)
271 {
272 	const bool												useMultisampling	= (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
273 	const vk::DeviceInterface&								vk					= m_context.getDeviceInterface();
274 	const vk::VkDevice										device				= m_context.getDevice();
275 	const vk::Unique<vk::VkShaderModule>					vs					(createShaderModule(vk, device, m_context.getBinaryCollection().get(vsName), 0));
276 	const vk::Unique<vk::VkShaderModule>					fs					(createShaderModule(vk, device, m_context.getBinaryCollection().get(fsName), 0));
277 	const CmdPoolCreateInfo									cmdPoolCreateInfo	= m_context.getUniversalQueueFamilyIndex();
278 	vk::Move<vk::VkCommandPool>								cmdPool				= createCommandPool(vk, device, &cmdPoolCreateInfo);
279 	vk::Move<vk::VkCommandBuffer>							cmdBuffer			= vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
280 	std::vector<de::SharedPtr<Image> >						multisampleImages;
281 	std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > >	colorTargetViews;
282 	std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > >	multisampleViews;
283 	de::SharedPtr<Buffer>									vertexBuffer;
284 	vk::Move<vk::VkRenderPass>								renderPass;
285 	vk::Move<vk::VkFramebuffer>								framebuffer;
286 	vk::Move<vk::VkPipeline>								pipeline;
287 
288 	// Create color buffer images
289 	for (deUint32 frameNdx = 0; frameNdx < colorTargetImages.size(); frameNdx++)
290 	{
291 		const vk::VkExtent3D		targetImageExtent		= { m_params.size.x(), m_params.size.y(), 1 };
292 		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;
293 		const ImageCreateInfo		targetImageCreateInfo	(vk::VK_IMAGE_TYPE_2D,
294 															 m_params.format,
295 															 targetImageExtent,
296 															 1,
297 															 1,
298 															 vk::VK_SAMPLE_COUNT_1_BIT,
299 															 vk::VK_IMAGE_TILING_OPTIMAL,
300 															 usage);
301 
302 		colorTargetImages[frameNdx] = Image::createAndAlloc(vk, device, targetImageCreateInfo,
303 															m_context.getDefaultAllocator(),
304 															m_context.getUniversalQueueFamilyIndex());
305 
306 		if (useMultisampling)
307 		{
308 			const ImageCreateInfo multisampleImageCreateInfo (vk::VK_IMAGE_TYPE_2D,
309 															  m_params.format,
310 															  targetImageExtent,
311 															  1,
312 															  1,
313 															  m_params.samples,
314 															  vk::VK_IMAGE_TILING_OPTIMAL,
315 															  usage);
316 
317 			multisampleImages.push_back(Image::createAndAlloc(vk, device, multisampleImageCreateInfo,
318 															  m_context.getDefaultAllocator(),
319 															  m_context.getUniversalQueueFamilyIndex()));
320 		}
321 	}
322 
323 	// Create render pass and framebuffer
324 	{
325 		RenderPassCreateInfo					renderPassCreateInfo;
326 		std::vector<vk::VkImageView>			attachments;
327 		std::vector<vk::VkAttachmentReference>	colorAttachmentRefs;
328 		std::vector<vk::VkAttachmentReference>	multisampleAttachmentRefs;
329 		deUint32								attachmentNdx				= 0;
330 
331 		for (deUint32 frameNdx = 0; frameNdx < colorTargetImages.size(); frameNdx++)
332 		{
333 			const ImageViewCreateInfo		colorTargetViewInfo			(colorTargetImages[frameNdx]->object(),
334 																		 vk::VK_IMAGE_VIEW_TYPE_2D,
335 																		 m_params.format);
336 
337 			const vk::VkAttachmentReference	colorAttachmentReference	=
338 			{
339 				attachmentNdx++,
340 				vk::VK_IMAGE_LAYOUT_GENERAL
341 			};
342 
343 			colorTargetViews.push_back(makeSharedPtr(createImageView(vk, device, &colorTargetViewInfo)));
344 			colorAttachmentRefs.push_back(colorAttachmentReference);
345 
346 			renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
347 																	 vk::VK_SAMPLE_COUNT_1_BIT,
348 																	 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
349 																	 vk::VK_ATTACHMENT_STORE_OP_STORE,
350 																	 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
351 																	 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
352 																	 vk::VK_IMAGE_LAYOUT_UNDEFINED,
353 																	 vk::VK_IMAGE_LAYOUT_GENERAL));
354 
355 			if (useMultisampling)
356 			{
357 				const ImageViewCreateInfo		multisamplingTargetViewInfo		(multisampleImages[frameNdx]->object(),
358 																				 vk::VK_IMAGE_VIEW_TYPE_2D,
359 																				 m_params.format);
360 
361 				const vk::VkAttachmentReference	multiSampleAttachmentReference	=
362 				{
363 					attachmentNdx++,
364 					vk::VK_IMAGE_LAYOUT_GENERAL
365 				};
366 
367 				multisampleViews.push_back(makeSharedPtr(createImageView(vk, device, &multisamplingTargetViewInfo)));
368 				multisampleAttachmentRefs.push_back(multiSampleAttachmentReference);
369 
370 				renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
371 																		 m_params.samples,
372 																		 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
373 																		 vk::VK_ATTACHMENT_STORE_OP_STORE,
374 																		 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
375 																		 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
376 																		 vk::VK_IMAGE_LAYOUT_UNDEFINED,
377 																		 vk::VK_IMAGE_LAYOUT_GENERAL));
378 			}
379 		}
380 
381 		renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
382 														   0,
383 														   0,
384 														   DE_NULL,
385 														   (deUint32)colorAttachmentRefs.size(),
386 														   useMultisampling ? &multisampleAttachmentRefs[0] : &colorAttachmentRefs[0],
387 														   useMultisampling ? &colorAttachmentRefs[0] : DE_NULL,
388 														   AttachmentReference(),
389 														   0,
390 														   DE_NULL));
391 
392 		renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
393 
394 		for (deUint32 frameNdx = 0; frameNdx < colorTargetViews.size(); frameNdx++)
395 		{
396 			attachments.push_back(**colorTargetViews[frameNdx]);
397 
398 			if (useMultisampling)
399 				attachments.push_back(**multisampleViews[frameNdx]);
400 		}
401 
402 		const vk::VkFramebufferCreateInfo framebufferCreateInfo =
403 		{
404 			vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
405 			DE_NULL,
406 			0u,
407 			*renderPass,
408 			(deUint32)attachments.size(),
409 			&attachments[0],
410 			m_params.size.x(),
411 			m_params.size.y(),
412 			1
413 		};
414 
415 		framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
416 	}
417 
418 	// Create vertex buffer.
419 	{
420 		const PositionColorVertex	vertices[]		=
421 		{
422 			PositionColorVertex(
423 				tcu::Vec4(-1.5f, -0.4f, 1.0f, 2.0f),	// Coord
424 				tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)),		// Color
425 
426 			PositionColorVertex(
427 				tcu::Vec4(0.4f, -0.4f, 0.5f, 0.5f),		// Coord
428 				tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)),		// Color
429 
430 			PositionColorVertex(
431 				tcu::Vec4(0.3f, 0.8f, 0.0f, 1.0f),		// Coord
432 				tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f))		// Color
433 		};
434 
435 		const vk::VkDeviceSize		dataSize		= DE_LENGTH_OF_ARRAY(vertices) * sizeof(PositionColorVertex);
436 									vertexBuffer	= Buffer::createAndAlloc(vk,
437 																			 device,
438 																			 BufferCreateInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
439 																			 m_context.getDefaultAllocator(),
440 																			 vk::MemoryRequirement::HostVisible);
441 		deUint8*					ptr				= reinterpret_cast<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
442 
443 		deMemcpy(ptr, vertices, static_cast<size_t>(dataSize));
444 		flushMappedMemoryRange(vk,
445 							   device,
446 							   vertexBuffer->getBoundMemory().getMemory(),
447 							   vertexBuffer->getBoundMemory().getOffset(),
448 							   VK_WHOLE_SIZE);
449 	}
450 
451 	// Create pipeline
452 	{
453 		const vk::VkViewport											viewport							= vk::makeViewport(m_params.size.x(), m_params.size.y());
454 		const vk::VkRect2D												scissor								= vk::makeRect2D(m_params.size.x(), m_params.size.y());
455 		const PipelineLayoutCreateInfo									pipelineLayoutCreateInfo;
456 		const vk::Move<vk::VkPipelineLayout>							pipelineLayout						= createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
457 		PipelineCreateInfo												pipelineCreateInfo					(*pipelineLayout, *renderPass, 0, 0);
458 
459 		const vk::VkVertexInputBindingDescription						vertexInputBindingDescription		=
460 		{
461 			0,
462 			(deUint32)sizeof(tcu::Vec4) * 2,
463 			vk::VK_VERTEX_INPUT_RATE_VERTEX
464 		};
465 
466 		const vk::VkVertexInputAttributeDescription						vertexInputAttributeDescriptions[2]	=
467 		{
468 			{ 0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
469 			{ 1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
470 		};
471 
472 		std::vector<PipelineCreateInfo::ColorBlendState::Attachment>	vkCbAttachmentStates				(colorTargetImages.size());
473 		PipelineCreateInfo::VertexInputState							vertexInputState					= PipelineCreateInfo::VertexInputState(1,
474 																																				   &vertexInputBindingDescription,
475 																																				   2,
476 																																				   vertexInputAttributeDescriptions);
477 
478 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
479 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
480 		pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
481 		pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
482 		pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState((deUint32)vkCbAttachmentStates.size(), &vkCbAttachmentStates[0]));
483 		pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
484 		pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
485 		pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
486 		pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState(m_params.samples));
487 
488 		pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
489 	}
490 
491 	// Queue draw and read results.
492 	{
493 		const vk::VkQueue				queue				= m_context.getUniversalQueue();
494 		const vk::VkRect2D				renderArea			= vk::makeRect2D(m_params.size.x(), m_params.size.y());
495 		const vk::VkDeviceSize			vertexBufferOffset	= 0;
496 		const vk::VkBuffer				buffer				= vertexBuffer->object();
497 		const vk::VkOffset3D			zeroOffset			= { 0, 0, 0 };
498 		std::vector<vk::VkClearValue>	clearValues;
499 
500 		for (deUint32 i = 0; i < colorTargetImages.size() + multisampleImages.size(); i++)
501 			clearValues.push_back(vk::makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
502 
503 		beginCommandBuffer(vk, *cmdBuffer, 0u);
504 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, (deUint32)clearValues.size(), &clearValues[0]);
505 		vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &vertexBufferOffset);
506 		vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
507 		vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u);
508 		endRenderPass(vk, *cmdBuffer);
509 
510 		endCommandBuffer(vk, *cmdBuffer);
511 		submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
512 
513 		for (deUint32 frameNdx = 0; frameNdx < colorTargetImages.size(); frameNdx++)
514 		{
515 			frames[frameNdx] = colorTargetImages[frameNdx]->readSurface(queue,
516 																		m_context.getDefaultAllocator(),
517 																		vk::VK_IMAGE_LAYOUT_GENERAL,
518 																		zeroOffset,
519 																		(int)m_params.size.x(),
520 																		(int)m_params.size.y(),
521 																		vk::VK_IMAGE_ASPECT_COLOR_BIT);
522 		}
523 	}
524 }
525 
compare(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference)526 bool DrawTestInstance::compare (const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& reference)
527 {
528 	DE_ASSERT(result.getSize() == reference.getSize());
529 
530 	const size_t	size	= result.getWidth() * result.getHeight() * vk::mapVkFormat(m_params.format).getPixelSize();
531 	const int		res		= deMemCmp(result.getDataPtr(), reference.getDataPtr(), size);
532 
533 	return (res == 0);
534 }
535 
iterate(void)536 tcu::TestStatus DrawTestInstance::iterate (void)
537 {
538 	tcu::TestLog&						log						= m_context.getTestContext().getLog();
539 	const bool							useMultisampling		= (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
540 	const deUint32						frameCount				= 4;
541 	std::vector<de::SharedPtr<Image> >	resImages				(frameCount);
542 	std::vector<de::SharedPtr<Image> >	smoothImage				(1);
543 	std::vector<de::SharedPtr<Image> >	flatImage				(1);
544 	std::vector<de::SharedPtr<Image> >	noperspectiveImage		(1);
545 	std::vector<de::SharedPtr<Image> >	centroidImage			(1);
546 	tcu::ConstPixelBufferAccess			resFrames[frameCount];
547 	tcu::ConstPixelBufferAccess			refFrames[frameCount];
548 
549 	render(resImages,			resFrames,					"vert_multi",			"frag_multi");
550 	render(smoothImage,			&refFrames[SMOOTH],			"vert_smooth",			"frag_smooth");
551 	render(flatImage,			&refFrames[FLAT],			"vert_flat",			"frag_flat");
552 	render(noperspectiveImage,	&refFrames[NOPERSPECTIVE],	"vert_noperspective",	"frag_noperspective");
553 	render(centroidImage,		&refFrames[CENTROID],		"vert_centroid",		"frag_centroid");
554 
555 	for (deUint32 resNdx = 0; resNdx < frameCount; resNdx++)
556 	{
557 		const std::string resName = interpolationToString((Interpolation)resNdx);
558 
559 		log	<< tcu::TestLog::ImageSet(resName, resName)
560 			<< tcu::TestLog::Image("Result", "Result", resFrames[resNdx])
561 			<< tcu::TestLog::Image("Reference", "Reference", refFrames[resNdx])
562 			<< tcu::TestLog::EndImageSet;
563 
564 		for (deUint32 refNdx = 0; refNdx < frameCount; refNdx++)
565 		{
566 			const std::string refName = interpolationToString((Interpolation)refNdx);
567 
568 			if (resNdx == refNdx)
569 			{
570 				if (!compare(resFrames[resNdx], refFrames[refNdx]))
571 					return tcu::TestStatus::fail(resName + " produced different results");
572 			}
573 			else if (!useMultisampling && ((resNdx == SMOOTH && refNdx == CENTROID) || (resNdx == CENTROID && refNdx == SMOOTH)))
574 			{
575 				if (!compare(resFrames[resNdx], refFrames[refNdx]))
576 					return tcu::TestStatus::fail(resName + " and " + refName + " produced different results without multisampling");
577 			}
578 			else
579 			{
580 				if (compare(resFrames[resNdx], refFrames[refNdx]))
581 					return tcu::TestStatus::fail(resName + " and " + refName + " produced same result");
582 			}
583 		}
584 	}
585 
586 	return tcu::TestStatus::pass("Results differ and references match");
587 }
588 
createTests(tcu::TestCaseGroup * testGroup)589 void createTests (tcu::TestCaseGroup* testGroup)
590 {
591 	tcu::TestContext&	testCtx	= testGroup->getTestContext();
592 	const vk::VkFormat	format	= vk::VK_FORMAT_R8G8B8A8_UNORM;
593 	const tcu::UVec2	size	(128, 128);
594 
595 	struct TestVariant
596 	{
597 		const std::string				name;
598 		const std::string				desc;
599 		const vk::VkSampleCountFlagBits	samples;
600 	};
601 
602 	static const std::vector<TestVariant> testVariants =
603 	{
604 		{ "1_sample",	"Without multisampling",	vk::VK_SAMPLE_COUNT_1_BIT	},
605 		{ "2_samples",	"2 samples",				vk::VK_SAMPLE_COUNT_2_BIT	},
606 		{ "4_samples",	"4 samples",				vk::VK_SAMPLE_COUNT_4_BIT	},
607 		{ "8_samples",	"8 samples",				vk::VK_SAMPLE_COUNT_8_BIT	},
608 		{ "16_samples",	"16 samples",				vk::VK_SAMPLE_COUNT_16_BIT	},
609 		{ "32_samples",	"32 samples",				vk::VK_SAMPLE_COUNT_32_BIT	},
610 		{ "64_samples",	"64 samples",				vk::VK_SAMPLE_COUNT_64_BIT	},
611 	};
612 
613 	struct GroupVariant
614 	{
615 		const bool			useStructure;
616 		const std::string	groupName;
617 	};
618 
619 	static const std::vector<GroupVariant> groupVariants =
620 	{
621 		{ false,	"separate"		},
622 		{ true,		"structured"	},
623 	};
624 
625 	for (const auto& grpVariant : groupVariants)
626 	{
627 		de::MovePtr<tcu::TestCaseGroup> group {new tcu::TestCaseGroup{testCtx, grpVariant.groupName.c_str(), ""}};
628 
629 		for (const auto& testVariant : testVariants)
630 		{
631 			const DrawParams params {format, size, testVariant.samples, grpVariant.useStructure};
632 			group->addChild(new DrawTestCase(testCtx, testVariant.name, testVariant.desc, params));
633 		}
634 
635 		testGroup->addChild(group.release());
636 	}
637 }
638 
639 }	// anonymous
640 
createMultipleInterpolationTests(tcu::TestContext & testCtx)641 tcu::TestCaseGroup* createMultipleInterpolationTests (tcu::TestContext& testCtx)
642 {
643 	return createTestGroup(testCtx,
644 						   "multiple_interpolation",
645 						   "Tests for multiple interpolation decorations in a shader stage.",
646 						   createTests);
647 }
648 
649 }	// Draw
650 }	// vkt
651