• 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 "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 	SAMPLE			= 4,
48 	COUNT			= 5,
49 };
50 
51 struct DrawParams
52 {
53 	vk::VkFormat				format;
54 	tcu::UVec2					size;
55 	vk::VkSampleCountFlagBits	samples;
56 	// From the SPIR-V point of view, structured test variants will allow us to test interpolation decorations on struct members
57 	// instead of plain ids.
58 	bool						useStructure;
59 	bool						includeSampleDecoration;
60 	bool						useDynamicRendering;
61 };
62 
63 template<typename T>
makeSharedPtr(vk::Move<T> move)64 inline de::SharedPtr<vk::Move<T> > makeSharedPtr(vk::Move<T> move)
65 {
66 	return de::SharedPtr<vk::Move<T> >(new vk::Move<T>(move));
67 }
68 
interpolationToString(Interpolation interpolation)69 const char* interpolationToString (Interpolation interpolation)
70 {
71 	switch (interpolation)
72 	{
73 		case SMOOTH:
74 			return "smooth";
75 		case FLAT:
76 			return "flat";
77 		case NOPERSPECTIVE:
78 			return "noperspective";
79 		case CENTROID:
80 			return "centroid";
81 		case SAMPLE:
82 			return "sample";
83 		default:
84 			DE_FATAL("Invalid interpolation enum");
85 	}
86 
87 	return "";
88 }
89 
90 class DrawTestInstance : public TestInstance
91 {
92 public:
93 					DrawTestInstance	(Context& context, DrawParams params);
94 	void			render				(de::SharedPtr<Image>& colorTargetImage,
95 										 tcu::ConstPixelBufferAccess* frame,
96 										 const char* vsName,
97 										 const char* fsName,
98 										 Interpolation interpolation,
99 										 bool sampleRateShading);
100 	bool			compare				(const tcu::ConstPixelBufferAccess& result,
101 										 const tcu::ConstPixelBufferAccess& reference);
102 	tcu::TestStatus	iterate				(void);
103 private:
104 	DrawParams		m_params;
105 };
106 
DrawTestInstance(Context & context,DrawParams params)107 DrawTestInstance::DrawTestInstance (Context& context, DrawParams params)
108 	: TestInstance	(context)
109 	, m_params		(params)
110 {
111 }
112 
113 class DrawTestCase : public TestCase
114 {
115 public:
116 							DrawTestCase	(tcu::TestContext&	testCtx,
117 											 const std::string&	name,
118 											 const std::string&	description,
119 											 const DrawParams	params);
120 							~DrawTestCase	(void);
121 	virtual void			initPrograms	(vk::SourceCollections& programCollection) const;
122 	virtual void			checkSupport	(Context& context) const;
123 	virtual TestInstance*	createInstance	(Context& context) const;
124 private:
125 	const DrawParams		m_params;
126 };
127 
DrawTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const DrawParams params)128 DrawTestCase::DrawTestCase (tcu::TestContext& testCtx,
129 							const std::string& name,
130 							const std::string& description,
131 							const DrawParams params)
132 	: TestCase	(testCtx, name, description)
133 	, m_params	(params)
134 {
135 }
136 
~DrawTestCase(void)137 DrawTestCase::~DrawTestCase (void)
138 {
139 }
140 
initPrograms(vk::SourceCollections & programCollection) const141 void DrawTestCase::initPrograms (vk::SourceCollections& programCollection) const
142 {
143 	const std::string							blockName		= "ifb";
144 	const std::map<std::string, std::string>	replacements	=
145 	{
146 		std::pair<std::string, std::string>{"blockOpeningOut"	, (m_params.useStructure ? "layout(location = 0) out InterfaceBlock {\n" : "")},
147 		std::pair<std::string, std::string>{"blockOpeningIn"	, (m_params.useStructure ? "layout(location = 0) in InterfaceBlock {\n" : "")},
148 		std::pair<std::string, std::string>{"blockClosure"		, (m_params.useStructure ? "} " + blockName + ";\n" : "")},
149 		std::pair<std::string, std::string>{"extensions"		, (m_params.useStructure ? "#extension GL_ARB_enhanced_layouts : require\n" : "")},
150 		std::pair<std::string, std::string>{"accessPrefix"		, (m_params.useStructure ? blockName + "." : "")},
151 		std::pair<std::string, std::string>{"outQual"			, (m_params.useStructure ? "" : "out ")},
152 		std::pair<std::string, std::string>{"inQual"			, (m_params.useStructure ? "" : "in ")},
153 		std::pair<std::string, std::string>{"indent"			, (m_params.useStructure ? "    " : "")},
154 	};
155 
156 	std::ostringstream vertShaderMultiStream;
157 	vertShaderMultiStream
158 		<< "#version 430\n"
159 		<< "${extensions}"
160 		<< "\n"
161 		<< "layout(location = 0) in vec4 in_position;\n"
162 		<< "layout(location = 1) in vec4 in_color;\n"
163 		<< "\n"
164 		<< "${blockOpeningOut}"
165 		<< "${indent}layout(location = 0) ${outQual}vec4 out_color_smooth;\n"
166 		<< "${indent}layout(location = 1) ${outQual}flat vec4 out_color_flat;\n"
167 		<< "${indent}layout(location = 2) ${outQual}noperspective vec4 out_color_noperspective;\n"
168 		<< "${indent}layout(location = 3) ${outQual}centroid vec4 out_color_centroid;\n"
169 		<< (m_params.includeSampleDecoration ? "${indent}layout(location = 4) ${outQual}sample vec4 out_color_sample;\n" : "")
170 		<< "${blockClosure}"
171 		<< "\n"
172 		<< "void main()\n"
173 		<< "{\n"
174 		<< "    ${accessPrefix}out_color_smooth = in_color;\n"
175 		<< "    ${accessPrefix}out_color_flat = in_color;\n"
176 		<< "    ${accessPrefix}out_color_noperspective = in_color;\n"
177 		<< "    ${accessPrefix}out_color_centroid = in_color;\n"
178 		<< (m_params.includeSampleDecoration ? "    ${accessPrefix}out_color_sample = in_color;\n" : "")
179 		<< "    gl_Position = in_position;\n"
180 		<< "}\n"
181 		;
182 	const tcu::StringTemplate vertShaderMulti(vertShaderMultiStream.str());
183 
184 	const auto colorCount = (m_params.includeSampleDecoration ? COUNT : (COUNT - 1));
185 
186 	std::ostringstream fragShaderMultiStream;
187 	fragShaderMultiStream
188 		<< "#version 430\n"
189 		<< "${extensions}"
190 		<< "\n"
191 		<< "${blockOpeningIn}"
192 		<< "${indent}layout(location = 0) ${inQual}vec4 in_color_smooth;\n"
193 		<< "${indent}layout(location = 1) ${inQual}flat vec4 in_color_flat;\n"
194 		<< "${indent}layout(location = 2) ${inQual}noperspective vec4 in_color_noperspective;\n"
195 		<< "${indent}layout(location = 3) ${inQual}centroid vec4 in_color_centroid;\n"
196 		<< (m_params.includeSampleDecoration ? "${indent}layout(location = 4) ${inQual}sample vec4 in_color_sample;\n" : "")
197 		<< "${blockClosure}"
198 		<< "\n"
199 		<< "layout(push_constant, std430) uniform PushConstants {\n"
200 		<< "    uint interpolationIndex;\n"
201 		<< "} pc;\n"
202 		<< "\n"
203 		<< "layout(location=0) out vec4 out_color;\n"
204 		<< "\n"
205 		<< "void main()\n"
206 		<< "{\n"
207 		<< "    const vec4 in_colors[" + de::toString(colorCount) + "] = vec4[](\n"
208 		<< "        ${accessPrefix}in_color_smooth,\n"
209 		<< "        ${accessPrefix}in_color_flat,\n"
210 		<< "        ${accessPrefix}in_color_noperspective,\n"
211 		<< "        ${accessPrefix}in_color_centroid" << (m_params.includeSampleDecoration ? "," : "") << "\n"
212 		<< (m_params.includeSampleDecoration ? "        ${accessPrefix}in_color_sample\n" : "")
213 		<< "    );\n"
214 		<< "    out_color = in_colors[pc.interpolationIndex];\n"
215 		<< "}\n"
216 		;
217 	const tcu::StringTemplate fragShaderMulti(fragShaderMultiStream.str());
218 
219 	const tcu::StringTemplate vertShaderSingle
220 	{
221 		"#version 430\n"
222 		"${extensions}"
223 		"\n"
224 		"layout(location = 0) in vec4 in_position;\n"
225 		"layout(location = 1) in vec4 in_color;\n"
226 		"\n"
227 		"${blockOpeningOut}"
228 		"${indent}layout(location = 0) ${outQual}${qualifier:opt}vec4 out_color;\n"
229 		"${blockClosure}"
230 		"\n"
231 		"void main()\n"
232 		"{\n"
233 		"    ${accessPrefix}out_color = in_color;\n"
234 		"    gl_Position = in_position;\n"
235 		"}\n"
236 	};
237 
238 	const tcu::StringTemplate fragShaderSingle
239 	{
240 		"#version 430\n"
241 		"${extensions}"
242 		"\n"
243 		"${blockOpeningIn}"
244 		"${indent}layout(location = 0) ${inQual}${qualifier:opt}vec4 in_color;\n"
245 		"${blockClosure}"
246 		"\n"
247 		"layout(location = 0) out vec4 out_color;\n"
248 		"\n"
249 		"void main()\n"
250 		"{\n"
251 		"    out_color = ${accessPrefix}in_color;\n"
252 		"}\n"
253 	};
254 
255 	std::map<std::string, std::string>	smooth			= replacements;
256 	std::map<std::string, std::string>	flat			= replacements;
257 	std::map<std::string, std::string>	noperspective	= replacements;
258 	std::map<std::string, std::string>	centroid		= replacements;
259 	std::map<std::string, std::string>	sample			= replacements;
260 
261 	flat["qualifier"]			= "flat ";
262 	noperspective["qualifier"]	= "noperspective ";
263 	centroid["qualifier"]		= "centroid ";
264 	sample["qualifier"]			= "sample ";
265 
266 	programCollection.glslSources.add("vert_multi")			<< glu::VertexSource(vertShaderMulti.specialize(replacements));
267 	programCollection.glslSources.add("frag_multi")			<< glu::FragmentSource(fragShaderMulti.specialize(replacements));
268 	programCollection.glslSources.add("vert_smooth")		<< glu::VertexSource(vertShaderSingle.specialize(smooth));
269 	programCollection.glslSources.add("frag_smooth")		<< glu::FragmentSource(fragShaderSingle.specialize(smooth));
270 	programCollection.glslSources.add("vert_flat")			<< glu::VertexSource(vertShaderSingle.specialize(flat));
271 	programCollection.glslSources.add("frag_flat")			<< glu::FragmentSource(fragShaderSingle.specialize(flat));
272 	programCollection.glslSources.add("vert_noperspective")	<< glu::VertexSource(vertShaderSingle.specialize(noperspective));
273 	programCollection.glslSources.add("frag_noperspective")	<< glu::FragmentSource(fragShaderSingle.specialize(noperspective));
274 	programCollection.glslSources.add("vert_centroid")		<< glu::VertexSource(vertShaderSingle.specialize(centroid));
275 	programCollection.glslSources.add("frag_centroid")		<< glu::FragmentSource(fragShaderSingle.specialize(centroid));
276 
277 	if (m_params.includeSampleDecoration)
278 	{
279 		programCollection.glslSources.add("vert_sample")		<< glu::VertexSource(vertShaderSingle.specialize(sample));
280 		programCollection.glslSources.add("frag_sample")		<< glu::FragmentSource(fragShaderSingle.specialize(sample));
281 	}
282 }
283 
checkSupport(Context & context) const284 void DrawTestCase::checkSupport (Context& context) const
285 {
286 	if (!(m_params.samples & context.getDeviceProperties().limits.framebufferColorSampleCounts))
287 		TCU_THROW(NotSupportedError, "Multisampling with " + de::toString(m_params.samples) + " samples not supported");
288 
289 	if (m_params.includeSampleDecoration && !context.getDeviceFeatures().sampleRateShading)
290 		TCU_THROW(NotSupportedError, "Sample rate shading not supported");
291 
292 	if (m_params.useDynamicRendering)
293 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
294 }
295 
createInstance(Context & context) const296 TestInstance* DrawTestCase::createInstance (Context& context) const
297 {
298 	return new DrawTestInstance(context, m_params);
299 }
300 
render(de::SharedPtr<Image> & colorTargetImage,tcu::ConstPixelBufferAccess * frame,const char * vsName,const char * fsName,Interpolation interpolation,bool sampleRateShading)301 void DrawTestInstance::render (de::SharedPtr<Image>& colorTargetImage,
302 							   tcu::ConstPixelBufferAccess* frame,
303 							   const char* vsName,
304 							   const char* fsName,
305 							   Interpolation interpolation,
306 							   bool sampleRateShading)
307 {
308 	const deUint32											pcData				= static_cast<deUint32>(interpolation);
309 	const deUint32											pcDataSize			= static_cast<deUint32>(sizeof(pcData));
310 	const bool												useMultisampling	= (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
311 	const vk::VkBool32										sampleShadingEnable	= (sampleRateShading ? VK_TRUE : VK_FALSE);
312 	const vk::DeviceInterface&								vk					= m_context.getDeviceInterface();
313 	const vk::VkDevice										device				= m_context.getDevice();
314 	const vk::Unique<vk::VkShaderModule>					vs					(createShaderModule(vk, device, m_context.getBinaryCollection().get(vsName), 0));
315 	const vk::Unique<vk::VkShaderModule>					fs					(createShaderModule(vk, device, m_context.getBinaryCollection().get(fsName), 0));
316 	const CmdPoolCreateInfo									cmdPoolCreateInfo	= m_context.getUniversalQueueFamilyIndex();
317 	vk::Move<vk::VkCommandPool>								cmdPool				= createCommandPool(vk, device, &cmdPoolCreateInfo);
318 	vk::Move<vk::VkCommandBuffer>							cmdBuffer			= vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
319 	de::SharedPtr<Image>									multisampleImage;
320 	std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > >	colorTargetViews;
321 	std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > >	multisampleViews;
322 	de::SharedPtr<Buffer>									vertexBuffer;
323 	vk::Move<vk::VkRenderPass>								renderPass;
324 	vk::Move<vk::VkFramebuffer>								framebuffer;
325 	vk::Move<vk::VkPipelineLayout>							pipelineLayout;
326 	vk::Move<vk::VkPipeline>								pipeline;
327 
328 	// Create color buffer images
329 	{
330 		const vk::VkExtent3D		targetImageExtent		= { m_params.size.x(), m_params.size.y(), 1 };
331 		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;
332 		const ImageCreateInfo		targetImageCreateInfo	(vk::VK_IMAGE_TYPE_2D,
333 															 m_params.format,
334 															 targetImageExtent,
335 															 1,
336 															 1,
337 															 vk::VK_SAMPLE_COUNT_1_BIT,
338 															 vk::VK_IMAGE_TILING_OPTIMAL,
339 															 usage);
340 
341 		colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo,
342 												 m_context.getDefaultAllocator(),
343 												 m_context.getUniversalQueueFamilyIndex());
344 
345 		if (useMultisampling)
346 		{
347 			const ImageCreateInfo multisampleImageCreateInfo (vk::VK_IMAGE_TYPE_2D,
348 															  m_params.format,
349 															  targetImageExtent,
350 															  1,
351 															  1,
352 															  m_params.samples,
353 															  vk::VK_IMAGE_TILING_OPTIMAL,
354 															  usage);
355 
356 			multisampleImage = Image::createAndAlloc(vk, device, multisampleImageCreateInfo,
357 													 m_context.getDefaultAllocator(),
358 													 m_context.getUniversalQueueFamilyIndex());
359 		}
360 	}
361 
362 	{
363 		const ImageViewCreateInfo colorTargetViewInfo(colorTargetImage->object(),
364 													  vk::VK_IMAGE_VIEW_TYPE_2D,
365 													  m_params.format);
366 
367 		colorTargetViews.push_back(makeSharedPtr(createImageView(vk, device, &colorTargetViewInfo)));
368 
369 		if (useMultisampling)
370 		{
371 			const ImageViewCreateInfo multisamplingTargetViewInfo(multisampleImage->object(),
372 																  vk::VK_IMAGE_VIEW_TYPE_2D,
373 																  m_params.format);
374 
375 			multisampleViews.push_back(makeSharedPtr(createImageView(vk, device, &multisamplingTargetViewInfo)));
376 		}
377 	}
378 
379 	// Create render pass and framebuffer
380 	if (!m_params.useDynamicRendering)
381 	{
382 		RenderPassCreateInfo					renderPassCreateInfo;
383 		std::vector<vk::VkImageView>			attachments;
384 		std::vector<vk::VkAttachmentReference>	colorAttachmentRefs;
385 		std::vector<vk::VkAttachmentReference>	multisampleAttachmentRefs;
386 		deUint32								attachmentNdx				= 0;
387 
388 		{
389 			const vk::VkAttachmentReference	colorAttachmentReference	=
390 			{
391 				attachmentNdx++,
392 				vk::VK_IMAGE_LAYOUT_GENERAL
393 			};
394 
395 			colorAttachmentRefs.push_back(colorAttachmentReference);
396 
397 			renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
398 																	 vk::VK_SAMPLE_COUNT_1_BIT,
399 																	 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
400 																	 vk::VK_ATTACHMENT_STORE_OP_STORE,
401 																	 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
402 																	 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
403 																	 vk::VK_IMAGE_LAYOUT_UNDEFINED,
404 																	 vk::VK_IMAGE_LAYOUT_GENERAL));
405 
406 			if (useMultisampling)
407 			{
408 				const vk::VkAttachmentReference	multiSampleAttachmentReference	=
409 				{
410 					attachmentNdx++,
411 					vk::VK_IMAGE_LAYOUT_GENERAL
412 				};
413 
414 				multisampleAttachmentRefs.push_back(multiSampleAttachmentReference);
415 
416 				renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
417 																		 m_params.samples,
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 		}
426 
427 		renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
428 														   0,
429 														   0,
430 														   DE_NULL,
431 														   (deUint32)colorAttachmentRefs.size(),
432 														   useMultisampling ? &multisampleAttachmentRefs[0] : &colorAttachmentRefs[0],
433 														   useMultisampling ? &colorAttachmentRefs[0] : DE_NULL,
434 														   AttachmentReference(),
435 														   0,
436 														   DE_NULL));
437 
438 		renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
439 
440 		for (deUint32 frameNdx = 0; frameNdx < colorTargetViews.size(); frameNdx++)
441 		{
442 			attachments.push_back(**colorTargetViews[frameNdx]);
443 
444 			if (useMultisampling)
445 				attachments.push_back(**multisampleViews[frameNdx]);
446 		}
447 
448 		const vk::VkFramebufferCreateInfo framebufferCreateInfo =
449 		{
450 			vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
451 			DE_NULL,
452 			0u,
453 			*renderPass,
454 			(deUint32)attachments.size(),
455 			&attachments[0],
456 			m_params.size.x(),
457 			m_params.size.y(),
458 			1
459 		};
460 
461 		framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
462 	}
463 
464 	// Create vertex buffer.
465 	{
466 		const PositionColorVertex	vertices[]		=
467 		{
468 			PositionColorVertex(
469 				tcu::Vec4(-1.5f, -0.4f, 1.0f, 2.0f),	// Coord
470 				tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)),		// Color
471 
472 			PositionColorVertex(
473 				tcu::Vec4(0.4f, -0.4f, 0.5f, 0.5f),		// Coord
474 				tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)),		// Color
475 
476 			PositionColorVertex(
477 				tcu::Vec4(0.3f, 0.8f, 0.0f, 1.0f),		// Coord
478 				tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f))		// Color
479 		};
480 
481 		const vk::VkDeviceSize		dataSize		= DE_LENGTH_OF_ARRAY(vertices) * sizeof(PositionColorVertex);
482 									vertexBuffer	= Buffer::createAndAlloc(vk,
483 																			 device,
484 																			 BufferCreateInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
485 																			 m_context.getDefaultAllocator(),
486 																			 vk::MemoryRequirement::HostVisible);
487 		deUint8*					ptr				= reinterpret_cast<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
488 
489 		deMemcpy(ptr, vertices, static_cast<size_t>(dataSize));
490 		flushMappedMemoryRange(vk,
491 							   device,
492 							   vertexBuffer->getBoundMemory().getMemory(),
493 							   vertexBuffer->getBoundMemory().getOffset(),
494 							   VK_WHOLE_SIZE);
495 	}
496 
497 	// Create pipeline
498 	{
499 		const vk::VkViewport											viewport							= vk::makeViewport(m_params.size.x(), m_params.size.y());
500 		const vk::VkRect2D												scissor								= vk::makeRect2D(m_params.size.x(), m_params.size.y());
501 		const auto														pcRange								= vk::makePushConstantRange(vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize);
502 		const std::vector<vk::VkPushConstantRange>						pcRanges							(1u, pcRange);
503 		const PipelineLayoutCreateInfo									pipelineLayoutCreateInfo			(0u, nullptr, static_cast<deUint32>(pcRanges.size()), pcRanges.data());
504 
505 		pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
506 
507 		PipelineCreateInfo												pipelineCreateInfo					(*pipelineLayout, *renderPass, 0, 0);
508 
509 		const vk::VkVertexInputBindingDescription						vertexInputBindingDescription		=
510 		{
511 			0,
512 			(deUint32)sizeof(tcu::Vec4) * 2,
513 			vk::VK_VERTEX_INPUT_RATE_VERTEX
514 		};
515 
516 		const vk::VkVertexInputAttributeDescription						vertexInputAttributeDescriptions[2]	=
517 		{
518 			{ 0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
519 			{ 1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
520 		};
521 
522 		std::vector<PipelineCreateInfo::ColorBlendState::Attachment>	vkCbAttachmentStates				(1u);
523 		PipelineCreateInfo::VertexInputState							vertexInputState					= PipelineCreateInfo::VertexInputState(1,
524 																																				   &vertexInputBindingDescription,
525 																																				   2,
526 																																				   vertexInputAttributeDescriptions);
527 
528 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
529 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
530 		pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
531 		pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
532 		pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState((deUint32)vkCbAttachmentStates.size(), &vkCbAttachmentStates[0]));
533 		pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
534 		pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
535 		pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
536 		pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState(m_params.samples, sampleShadingEnable, 1.0f));
537 
538 		std::vector<vk::VkFormat> colorAttachmentFormats(colorTargetViews.size(), m_params.format);
539 		vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
540 		{
541 			vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
542 			DE_NULL,
543 			0u,
544 			static_cast<deUint32>(colorAttachmentFormats.size()),
545 			colorAttachmentFormats.data(),
546 			vk::VK_FORMAT_UNDEFINED,
547 			vk::VK_FORMAT_UNDEFINED
548 		};
549 
550 		if (m_params.useDynamicRendering)
551 			pipelineCreateInfo.pNext = &renderingCreateInfo;
552 
553 		pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
554 	}
555 
556 	// Queue draw and read results.
557 	{
558 		const vk::VkQueue				queue				= m_context.getUniversalQueue();
559 		const vk::VkRect2D				renderArea			= vk::makeRect2D(m_params.size.x(), m_params.size.y());
560 		const vk::VkDeviceSize			vertexBufferOffset	= 0;
561 		const vk::VkBuffer				buffer				= vertexBuffer->object();
562 		const vk::VkOffset3D			zeroOffset			= { 0, 0, 0 };
563 		const auto						clearValueColor		= vk::makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
564 		std::vector<vk::VkClearValue>	clearValues			(2, clearValueColor);
565 
566 		beginCommandBuffer(vk, *cmdBuffer, 0u);
567 
568 		if (m_params.useDynamicRendering)
569 		{
570 			const deUint32 imagesCount = static_cast<deUint32>(colorTargetViews.size());
571 			std::vector<vk::VkRenderingAttachmentInfoKHR> colorAttachments(imagesCount,
572 			{
573 				vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR,	// VkStructureType						sType;
574 				DE_NULL,												// const void*							pNext;
575 				DE_NULL,												// VkImageView							imageView;
576 				vk::VK_IMAGE_LAYOUT_GENERAL,							// VkImageLayout						imageLayout;
577 				vk::VK_RESOLVE_MODE_NONE,								// VkResolveModeFlagBits				resolveMode;
578 				DE_NULL,												// VkImageView							resolveImageView;
579 				vk::VK_IMAGE_LAYOUT_GENERAL,							// VkImageLayout						resolveImageLayout;
580 				vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp					loadOp;
581 				vk::VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp					storeOp;
582 				clearValueColor											// VkClearValue							clearValue;
583 			});
584 
585 			for (deUint32 i = 0; i < imagesCount; ++i)
586 			{
587 				if (useMultisampling)
588 				{
589 					colorAttachments[i].imageView			= **multisampleViews[i];
590 					colorAttachments[i].resolveMode			= vk::VK_RESOLVE_MODE_AVERAGE_BIT;
591 					colorAttachments[i].resolveImageView	= **colorTargetViews[i];
592 				}
593 				else
594 					colorAttachments[i].imageView = **colorTargetViews[i];
595 			}
596 
597 			vk::VkRenderingInfoKHR renderingInfo
598 			{
599 				vk::VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
600 				DE_NULL,
601 				0,														// VkRenderingFlagsKHR					flags;
602 				renderArea,												// VkRect2D								renderArea;
603 				1u,														// deUint32								layerCount;
604 				0u,														// deUint32								viewMask;
605 				imagesCount,											// deUint32								colorAttachmentCount;
606 				colorAttachments.data(),								// const VkRenderingAttachmentInfoKHR*	pColorAttachments;
607 				DE_NULL,												// const VkRenderingAttachmentInfoKHR*	pDepthAttachment;
608 				DE_NULL,												// const VkRenderingAttachmentInfoKHR*	pStencilAttachment;
609 			};
610 
611 			// Transition Images
612 			initialTransitionColor2DImage(vk, *cmdBuffer, colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
613 				vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
614 
615 			if (useMultisampling)
616 			{
617 				initialTransitionColor2DImage(vk, *cmdBuffer, multisampleImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
618 					vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
619 			}
620 
621 			vk.cmdBeginRenderingKHR(*cmdBuffer, &renderingInfo);
622 		}
623 		else
624 		{
625 			const deUint32 imagesCount = static_cast<deUint32>(colorTargetViews.size() + multisampleViews.size());
626 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, imagesCount, &clearValues[0]);
627 		}
628 
629 		vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &vertexBufferOffset);
630 		vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
631 		vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize, &pcData);
632 		vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u);
633 
634 		if (m_params.useDynamicRendering)
635 			endRendering(vk, *cmdBuffer);
636 		else
637 			endRenderPass(vk, *cmdBuffer);
638 
639 		endCommandBuffer(vk, *cmdBuffer);
640 		submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
641 
642 		*frame = colorTargetImage->readSurface(queue,
643 											   m_context.getDefaultAllocator(),
644 											   vk::VK_IMAGE_LAYOUT_GENERAL,
645 											   zeroOffset,
646 											   (int)m_params.size.x(),
647 											   (int)m_params.size.y(),
648 											   vk::VK_IMAGE_ASPECT_COLOR_BIT);
649 	}
650 }
651 
compare(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference)652 bool DrawTestInstance::compare (const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& reference)
653 {
654 	DE_ASSERT(result.getSize() == reference.getSize());
655 
656 	const size_t	size	= result.getWidth() * result.getHeight() * vk::mapVkFormat(m_params.format).getPixelSize();
657 	const int		res		= deMemCmp(result.getDataPtr(), reference.getDataPtr(), size);
658 
659 	return (res == 0);
660 }
661 
iterate(void)662 tcu::TestStatus DrawTestInstance::iterate (void)
663 {
664 	tcu::TestLog&						log						= m_context.getTestContext().getLog();
665 	const bool							useMultisampling		= (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
666 	const deUint32						frameCount				= static_cast<deUint32>(COUNT);
667 	std::vector<de::SharedPtr<Image> >	resImages				(frameCount);
668 	de::SharedPtr<Image>				smoothImage[2];
669 	de::SharedPtr<Image>				flatImage[2];
670 	de::SharedPtr<Image>				noperspectiveImage[2];
671 	de::SharedPtr<Image>				centroidImage[2];
672 	de::SharedPtr<Image>				sampleImage[2];
673 	tcu::ConstPixelBufferAccess			resFrames[frameCount];
674 	tcu::ConstPixelBufferAccess			refFrames[frameCount];
675 	tcu::ConstPixelBufferAccess			refSRSFrames[frameCount]; // Using sample rate shading.
676 
677 	for (int interpolationType = 0; interpolationType < COUNT; ++interpolationType)
678 	{
679 		// Avoid generating a result image for the sample decoration if we're not using it.
680 		if (!m_params.includeSampleDecoration && interpolationType == Interpolation::SAMPLE)
681 			continue;
682 
683 		render(resImages[interpolationType], &resFrames[interpolationType], "vert_multi", "frag_multi", static_cast<Interpolation>(interpolationType), false);
684 	}
685 
686 	for (int i = 0; i < 2; ++i)
687 	{
688 		const bool useSampleRateShading = (i > 0);
689 
690 		// Sample rate shading is an alternative good result for cases using the sample decoration.
691 		if (useSampleRateShading && !m_params.includeSampleDecoration)
692 			continue;
693 
694 		tcu::ConstPixelBufferAccess *framesArray = (useSampleRateShading ? refSRSFrames : refFrames);
695 
696 		render(smoothImage[i],			&framesArray[SMOOTH],			"vert_smooth",			"frag_smooth",			SMOOTH,			useSampleRateShading);
697 		render(flatImage[i],			&framesArray[FLAT],				"vert_flat",			"frag_flat",			FLAT,			useSampleRateShading);
698 		render(noperspectiveImage[i],	&framesArray[NOPERSPECTIVE],	"vert_noperspective",	"frag_noperspective",	NOPERSPECTIVE,	useSampleRateShading);
699 		render(centroidImage[i],		&framesArray[CENTROID],			"vert_centroid",		"frag_centroid",		CENTROID,		useSampleRateShading);
700 
701 		// Avoid generating a reference image for the sample interpolation if we're not using it.
702 		if (m_params.includeSampleDecoration)
703 			render(sampleImage[i],		&framesArray[SAMPLE],			"vert_sample",			"frag_sample",			SAMPLE,			useSampleRateShading);
704 	}
705 
706 	for (deUint32 resNdx = 0; resNdx < frameCount; resNdx++)
707 	{
708 		if (!m_params.includeSampleDecoration && resNdx == SAMPLE)
709 			continue;
710 
711 		const std::string resName = interpolationToString((Interpolation)resNdx);
712 
713 		log	<< tcu::TestLog::ImageSet(resName, resName)
714 			<< tcu::TestLog::Image("Result", "Result", resFrames[resNdx])
715 			<< tcu::TestLog::Image("Reference", "Reference", refFrames[resNdx]);
716 		if (m_params.includeSampleDecoration)
717 			log << tcu::TestLog::Image("ReferenceSRS", "Reference with sample shading", refSRSFrames[resNdx]);
718 		log	<< tcu::TestLog::EndImageSet;
719 
720 		for (deUint32 refNdx = 0; refNdx < frameCount; refNdx++)
721 		{
722 			if (!m_params.includeSampleDecoration && refNdx == SAMPLE)
723 				continue;
724 
725 			const std::string refName = interpolationToString((Interpolation)refNdx);
726 
727 			if (resNdx == refNdx)
728 			{
729 				if (!compare(resFrames[resNdx], refFrames[refNdx]) && (!m_params.includeSampleDecoration || !compare(resFrames[resNdx], refSRSFrames[refNdx])))
730 					return tcu::TestStatus::fail(resName + " produced different results");
731 			}
732 			else if (!useMultisampling &&
733 				((resNdx == SMOOTH && refNdx == CENTROID) ||
734 				 (resNdx == CENTROID && refNdx == SMOOTH) ||
735 				 (resNdx == SMOOTH && refNdx == SAMPLE)   ||
736 				 (resNdx == SAMPLE && refNdx == SMOOTH)   ||
737 				 (resNdx == CENTROID && refNdx == SAMPLE) ||
738 				 (resNdx == SAMPLE && refNdx == CENTROID)))
739 			{
740 				if (!compare(resFrames[resNdx], refFrames[refNdx]))
741 					return tcu::TestStatus::fail(resName + " and " + refName + " produced different results without multisampling");
742 			}
743 			else
744 			{
745 				// "smooth" means lack of centroid and sample.
746 				// Spec does not specify exactly what "smooth" should be, so it can match centroid or sample.
747 				// "centroid" and "sample" may also produce the same results.
748 				if (!((resNdx == SMOOTH && refNdx == CENTROID)   ||
749 					  (resNdx == CENTROID && refNdx == SMOOTH)   ||
750 					  (resNdx == SMOOTH && refNdx == SAMPLE)     ||
751 					  (resNdx == SAMPLE && refNdx == SMOOTH)     ||
752 					  (resNdx == CENTROID && refNdx == SAMPLE)   ||
753 					  (resNdx == SAMPLE && refNdx == CENTROID)   ))
754 				{
755 					if (compare(resFrames[resNdx], refFrames[refNdx]))
756 						return tcu::TestStatus::fail(resName + " and " + refName + " produced same result");
757 				}
758 			}
759 		}
760 	}
761 
762 	return tcu::TestStatus::pass("Results differ and references match");
763 }
764 
createTests(tcu::TestCaseGroup * testGroup,bool useDynamicRendering)765 void createTests (tcu::TestCaseGroup* testGroup, bool useDynamicRendering)
766 {
767 	tcu::TestContext&	testCtx	= testGroup->getTestContext();
768 	const vk::VkFormat	format	= vk::VK_FORMAT_R8G8B8A8_UNORM;
769 	const tcu::UVec2	size	(128, 128);
770 
771 	struct TestVariant
772 	{
773 		const std::string				name;
774 		const std::string				desc;
775 		const vk::VkSampleCountFlagBits	samples;
776 	};
777 
778 	static const std::vector<TestVariant> testVariants =
779 	{
780 		{ "1_sample",	"Without multisampling",	vk::VK_SAMPLE_COUNT_1_BIT	},
781 		{ "2_samples",	"2 samples",				vk::VK_SAMPLE_COUNT_2_BIT	},
782 		{ "4_samples",	"4 samples",				vk::VK_SAMPLE_COUNT_4_BIT	},
783 		{ "8_samples",	"8 samples",				vk::VK_SAMPLE_COUNT_8_BIT	},
784 		{ "16_samples",	"16 samples",				vk::VK_SAMPLE_COUNT_16_BIT	},
785 		{ "32_samples",	"32 samples",				vk::VK_SAMPLE_COUNT_32_BIT	},
786 		{ "64_samples",	"64 samples",				vk::VK_SAMPLE_COUNT_64_BIT	},
787 	};
788 
789 	struct GroupVariant
790 	{
791 		const bool			useStructure;
792 		const std::string	groupName;
793 	};
794 
795 	static const std::vector<GroupVariant> groupVariants =
796 	{
797 		{ false,	"separate"		},
798 		{ true,		"structured"	},
799 	};
800 
801 	const struct
802 	{
803 		const bool			includeSampleDecoration;
804 		const std::string	groupName;
805 	} sampleVariants[] =
806 	{
807 		{ false,	"no_sample_decoration"		},
808 		{ true,		"with_sample_decoration"	},
809 	};
810 
811 	for (const auto& grpVariant : groupVariants)
812 	{
813 		de::MovePtr<tcu::TestCaseGroup> group {new tcu::TestCaseGroup{testCtx, grpVariant.groupName.c_str(), ""}};
814 
815 		for (const auto& sampleVariant : sampleVariants)
816 		{
817 			de::MovePtr<tcu::TestCaseGroup> sampleGroup {new tcu::TestCaseGroup{testCtx, sampleVariant.groupName.c_str(), ""}};
818 
819 			for (const auto& testVariant : testVariants)
820 			{
821 				const DrawParams params {format, size, testVariant.samples, grpVariant.useStructure, sampleVariant.includeSampleDecoration, useDynamicRendering};
822 				sampleGroup->addChild(new DrawTestCase(testCtx, testVariant.name, testVariant.desc, params));
823 			}
824 
825 			group->addChild(sampleGroup.release());
826 		}
827 
828 		testGroup->addChild(group.release());
829 	}
830 }
831 
832 }	// anonymous
833 
createMultipleInterpolationTests(tcu::TestContext & testCtx,bool useDynamicRendering)834 tcu::TestCaseGroup* createMultipleInterpolationTests (tcu::TestContext& testCtx, bool useDynamicRendering)
835 {
836 	return createTestGroup(testCtx,
837 						   "multiple_interpolation",
838 						   "Tests for multiple interpolation decorations in a shader stage.",
839 						   createTests,
840 						   useDynamicRendering);
841 }
842 
843 }	// Draw
844 }	// vkt
845