1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2023 LunarG, Inc.
7 * Copyright (c) 2023 Nintendo
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file vktPipelineInterfaceMatchingTests.cpp
23 * \brief Interface matching tests
24 *//*--------------------------------------------------------------------*/
25
26#include "vktPipelineInterfaceMatchingTests.hpp"
27#include "vktPipelineImageUtil.hpp"
28
29#include "vkBuilderUtil.hpp"
30#include "vkBarrierUtil.hpp"
31#include "vkImageUtil.hpp"
32#include "vkMemUtil.hpp"
33#include "vkQueryUtil.hpp"
34#include "vkTypeUtil.hpp"
35#include "vkCmdUtil.hpp"
36#include "vkObjUtil.hpp"
37
38#include "tcuTestLog.hpp"
39#include "tcuTestCase.hpp"
40#include "tcuStringTemplate.hpp"
41
42#include <set>
43
44namespace vkt
45{
46namespace pipeline
47{
48
49using namespace vk;
50using namespace de;
51using namespace tcu;
52
53namespace
54{
55
56enum class TestType
57{
58	VECTOR_LENGTH			= 0,
59	DECORATION_MISMATCH,
60};
61
62enum class VecType
63{
64	VEC2 = 0,
65	VEC3,
66	VEC4,
67	IVEC2,
68	IVEC3,
69	IVEC4,
70	UVEC2,
71	UVEC3,
72	UVEC4,
73};
74
75enum class DecorationType
76{
77	NONE = 0,
78	FLAT,
79	NO_PERSPECTIVE,
80	COMPONENT0
81};
82
83enum class PipelineType
84{
85	// all combinations with vert and frag
86	VERT_OUT_FRAG_IN = 0,
87
88	// all combinations with vert, tesc, tese and frag
89	VERT_OUT_TESC_IN_TESE_FRAG,
90	VERT_TESC_TESE_OUT_FRAG_IN,
91	VERT_TESC_OUT_TESE_IN_FRAG,
92
93	// all combinations with vert, geom and frag
94	VERT_OUT_GEOM_IN_FRAG,
95	VERT_GEOM_OUT_FRAG_IN,
96
97	// all combinations with vert, tesc, tese, geom and frag
98	VERT_OUT_TESC_IN_TESE_GEOM_FRAG,		// this won't add coverage as it is similar to VERT_OUT_TESC_IN_TESE_FRAG
99	//VERT_TESC_OUT_TESE_IN_GEOM_FRAG,		// this won't add coverage as it is similar to VERT_TESC_OUT_TESE_IN_FRAG
100	VERT_TESC_TESE_OUT_GEOM_IN_FRAG,
101	VERT_TESC_TESE_GEOM_OUT_FRAG_IN,
102};
103
104enum class DefinitionType
105{
106	LOOSE_VARIABLE = 0,
107	MEMBER_OF_BLOCK,
108	MEMBER_OF_STRUCTURE,
109	MEMBER_OF_ARRAY_OF_STRUCTURES,
110	MEMBER_OF_STRUCTURE_IN_BLOCK,
111	MEMBER_OF_ARRAY_OF_STRUCTURES_IN_BLOCK,
112};
113
114struct TestParams
115{
116	PipelineConstructionType	pipelineConstructionType;
117	TestType					testType;
118
119	VecType						outVecType;
120	VecType						inVecType;
121
122	DecorationType				outDeclDecoration;
123	DecorationType				inDeclDecoration;
124
125	PipelineType				pipelineType;
126	DefinitionType				definitionType;
127};
128
129typedef de::SharedPtr<TestParams> TestParamsSp;
130
131// helper function that check if specified pipeline is in set of pipelines
132bool isPipelineOneOf(PipelineType pipelineType, std::set<PipelineType> pipelines)
133{
134	return !!pipelines.count(pipelineType);
135}
136
137class InterfaceMatchingTestInstance : public vkt::TestInstance
138{
139public:
140						InterfaceMatchingTestInstance	(Context&			context,
141														 const TestParamsSp	params);
142	virtual				~InterfaceMatchingTestInstance	(void) = default;
143
144	tcu::TestStatus		iterate(void) override;
145
146private:
147	TestParamsSp				m_params;
148	SimpleAllocator				m_alloc;
149
150	Move<VkBuffer>				m_vertexBuffer;
151	de::MovePtr<Allocation>		m_vertexBufferAlloc;
152	Move<VkBuffer>				m_resultBuffer;
153	de::MovePtr<Allocation>		m_resultBufferAlloc;
154
155	Move<VkImage>				m_colorImage;
156	de::MovePtr<Allocation>		m_colorImageAlloc;
157	Move<VkImageView>			m_colorAttachmentView;
158	RenderPassWrapper			m_renderPass;
159	Move<VkFramebuffer>			m_framebuffer;
160
161	ShaderWrapper				m_vertShaderModule;
162	ShaderWrapper				m_tescShaderModule;
163	ShaderWrapper				m_teseShaderModule;
164	ShaderWrapper				m_geomShaderModule;
165	ShaderWrapper				m_fragShaderModule;
166
167	PipelineLayoutWrapper		m_pipelineLayout;
168	GraphicsPipelineWrapper		m_graphicsPipeline;
169
170	Move<VkCommandPool>			m_cmdPool;
171	Move<VkCommandBuffer>		m_cmdBuffer;
172};
173
174InterfaceMatchingTestInstance::InterfaceMatchingTestInstance(Context& context, const TestParamsSp params)
175	: vkt::TestInstance(context)
176	, m_params(params)
177	, m_alloc(context.getDeviceInterface(), context.getDevice(),
178			  getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()))
179	, m_graphicsPipeline(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(), context.getDevice(), context.getDeviceExtensions(), params->pipelineConstructionType)
180{
181}
182
183tcu::TestStatus InterfaceMatchingTestInstance::iterate(void)
184{
185	const DeviceInterface&		vk						= m_context.getDeviceInterface();
186	const VkDevice				device					= m_context.getDevice();
187	const VkQueue				queue					= m_context.getUniversalQueue();
188	const deUint32				queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
189	const VkComponentMapping	componentMappingRGBA	= makeComponentMappingRGBA();
190	VkImageSubresourceRange		subresourceRange		{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u };
191	const VkFormat				colorFormat				(VK_FORMAT_R8G8B8A8_UNORM);
192	const tcu::UVec2			renderSize				(16, 16);
193	const tcu::TextureFormat	textureFormat			= mapVkFormat(colorFormat);
194	const VkDeviceSize			pixelDataSize			= renderSize.x() * renderSize.y() * textureFormat.getPixelSize();
195	const VkDeviceSize			vertexBufferOffset		= 0;
196
197	// create color image that is used as a color attachment
198	{
199		const VkImageCreateInfo colorImageParams
200		{
201			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType			sType;
202			DE_NULL,																	// const void*				pNext;
203			0u,																			// VkImageCreateFlags		flags;
204			VK_IMAGE_TYPE_2D,															// VkImageType				imageType;
205			colorFormat,																// VkFormat					format;
206			{ renderSize.x(), renderSize.y(), 1u },										// VkExtent3D				extent;
207			1u,																			// deUint32					mipLevels;
208			1u,																			// deUint32					arrayLayers;
209			VK_SAMPLE_COUNT_1_BIT,														// VkSampleCountFlagBits	samples;
210			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling			tiling;
211			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,		// VkImageUsageFlags		usage;
212			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode			sharingMode;
213			1u,																			// deUint32					queueFamilyIndexCount;
214			&queueFamilyIndex,															// const deUint32*			pQueueFamilyIndices;
215			VK_IMAGE_LAYOUT_UNDEFINED,													// VkImageLayout			initialLayout;
216		};
217
218		m_colorImage = createImage(vk, device, &colorImageParams);
219
220		// allocate and bind color image memory
221		m_colorImageAlloc = m_alloc.allocate(getImageMemoryRequirements(vk, device, *m_colorImage), MemoryRequirement::Any);
222		VK_CHECK(vk.bindImageMemory(device, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
223	}
224
225	// create color attachment view
226	{
227		const VkImageViewCreateInfo colorAttachmentViewParams
228		{
229			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,									// VkStructureType			sType;
230			DE_NULL,																	// const void*				pNext;
231			0u,																			// VkImageViewCreateFlags	flags;
232			*m_colorImage,																// VkImage					image;
233			VK_IMAGE_VIEW_TYPE_2D,														// VkImageViewType			viewType;
234			colorFormat,																// VkFormat					format;
235			componentMappingRGBA,														// VkComponentMapping		components;
236			subresourceRange															// VkImageSubresourceRange	subresourceRange;
237		};
238
239		m_colorAttachmentView = createImageView(vk, device, &colorAttachmentViewParams);
240	}
241
242	// create render pass
243	m_renderPass = RenderPassWrapper(m_params->pipelineConstructionType, vk, device, colorFormat);
244
245	// create framebuffer
246	{
247		const VkFramebufferCreateInfo framebufferParams
248		{
249			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,									// VkStructureType			sType;
250			DE_NULL,																	// const void*				pNext;
251			0u,																			// VkFramebufferCreateFlags	flags;
252			*m_renderPass,																// VkRenderPass				renderPass;
253			1u,																			// deUint32					attachmentCount;
254			&m_colorAttachmentView.get(),												// const VkImageView*		pAttachments;
255			(deUint32)renderSize.x(),													// deUint32					width;
256			(deUint32)renderSize.y(),													// deUint32					height;
257			1u																			// deUint32					layers;
258		};
259
260		m_renderPass.createFramebuffer(vk, device, &framebufferParams, *m_colorImage);
261	}
262
263	// create pipeline layout
264	{
265		const VkPipelineLayoutCreateInfo pipelineLayoutParams
266		{
267			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,								// VkStructureType					sType;
268			DE_NULL,																	// const void*						pNext;
269			0u,																			// VkPipelineLayoutCreateFlags		flags;
270			0u,																			// deUint32							setLayoutCount;
271			DE_NULL,																	// const VkDescriptorSetLayout*		pSetLayouts;
272			0u,																			// deUint32							pushConstantRangeCount;
273			DE_NULL																		// const VkPushConstantRange*		pPushConstantRanges;
274		};
275
276		m_pipelineLayout = PipelineLayoutWrapper(m_params->pipelineConstructionType, vk, device, &pipelineLayoutParams);
277	}
278
279	// create pipeline
280	bool useTess = isPipelineOneOf(m_params->pipelineType, {
281		PipelineType::VERT_OUT_TESC_IN_TESE_FRAG,
282		PipelineType::VERT_TESC_TESE_OUT_FRAG_IN,
283		PipelineType::VERT_TESC_OUT_TESE_IN_FRAG,
284		PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG,
285		PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG,
286		PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN });
287
288	m_vertShaderModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0);
289	m_fragShaderModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0);
290	if (useTess)
291	{
292		m_tescShaderModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("tesc"), 0);
293		m_teseShaderModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("tese"), 0);
294	}
295
296	if (isPipelineOneOf(m_params->pipelineType, {
297		PipelineType::VERT_OUT_GEOM_IN_FRAG,
298		PipelineType::VERT_GEOM_OUT_FRAG_IN,
299		PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG,
300		PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG,
301		PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN }))
302	{
303		m_geomShaderModule = ShaderWrapper(vk, device, m_context.getBinaryCollection().get("geom"), 0);
304	}
305
306	const std::vector<VkViewport>	viewports	{ makeViewport(renderSize) };
307	const std::vector<VkRect2D>		scissors	{ makeRect2D(renderSize) };
308
309	m_graphicsPipeline.setDefaultTopology(useTess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
310					  .setDefaultRasterizationState()
311					  .setDefaultDepthStencilState()
312					  .setDefaultMultisampleState()
313					  .setDefaultColorBlendState()
314					  .setupVertexInputState()
315					  .setupPreRasterizationShaderState(viewports,
316														scissors,
317														m_pipelineLayout,
318														*m_renderPass,
319														0u,
320														m_vertShaderModule,
321														DE_NULL,
322														m_tescShaderModule,
323														m_teseShaderModule,
324														m_geomShaderModule)
325					  .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, m_fragShaderModule)
326					  .setupFragmentOutputState(*m_renderPass)
327					  .setMonolithicPipelineLayout(m_pipelineLayout)
328					  .buildPipeline();
329
330	// create vertex buffer
331	{
332		std::vector<float> vertices
333		{
334			 1.0f, -1.0f, 0.0f, 1.0f,
335			-1.0f,  1.0f, 0.0f, 1.0f,
336			-1.0f, -1.0f, 0.0f, 1.0f,
337		};
338		const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(vertices.size() * sizeof(float), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
339
340		m_vertexBuffer		= createBuffer(vk, device, &bufferCreateInfo);
341		m_vertexBufferAlloc = m_alloc.allocate(getBufferMemoryRequirements(vk, device, *m_vertexBuffer), MemoryRequirement::HostVisible);
342		VK_CHECK(vk.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
343
344		deMemcpy(m_vertexBufferAlloc->getHostPtr(), vertices.data(), vertices.size() * sizeof(float));
345		flushAlloc(vk, device, *m_vertexBufferAlloc);
346	}
347
348	// create buffer to which we will grab rendered result
349	{
350		const VkBufferCreateInfo	bufferCreateInfo	= makeBufferCreateInfo(pixelDataSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
351
352		m_resultBuffer		= createBuffer(vk, device, &bufferCreateInfo);
353		m_resultBufferAlloc = m_alloc.allocate(getBufferMemoryRequirements(vk, device, *m_resultBuffer), MemoryRequirement::HostVisible);
354		VK_CHECK(vk.bindBufferMemory(device, *m_resultBuffer, m_resultBufferAlloc->getMemory(), m_resultBufferAlloc->getOffset()));
355	}
356
357	// create command pool and command buffer
358	m_cmdPool	= createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
359	m_cmdBuffer	= allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
360
361	// record command buffer
362	beginCommandBuffer(vk, *m_cmdBuffer, 0u);
363
364	// change image layout so we can use it as color attachment
365	const VkImageMemoryBarrier attachmentLayoutBarrier = makeImageMemoryBarrier(
366		VK_ACCESS_NONE_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
367		VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
368		*m_colorImage, subresourceRange);
369	vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
370							0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &attachmentLayoutBarrier);
371
372	// render single triangle
373	m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(renderSize), Vec4(0.0f, 0.0f, 0.0f, 1.0f));
374
375	m_graphicsPipeline.bind(*m_cmdBuffer);
376	vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &*m_vertexBuffer, &vertexBufferOffset);
377	vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
378
379	m_renderPass.end(vk, *m_cmdBuffer);
380
381	copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, *m_resultBuffer, tcu::IVec2(renderSize.x(), renderSize.y()));
382
383	endCommandBuffer(vk, *m_cmdBuffer);
384
385	// submit commands
386	submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
387
388	// read buffer data
389	invalidateAlloc(vk, device, *m_resultBufferAlloc);
390
391	// validate result - verification is done in glsl, just checking
392	// two texels, if test passed then r channel should be set to 255
393	const unsigned char* bufferPtr = static_cast<unsigned char*>(m_resultBufferAlloc->getHostPtr());
394	if ((bufferPtr[0] > 254) && (bufferPtr[renderSize.x()*4+8] > 254))
395		return TestStatus::pass("Pass");
396
397	const tcu::ConstPixelBufferAccess resultAccess(textureFormat, tcu::IVec3((int)renderSize.x(), (int)renderSize.y(), 1u), bufferPtr);
398	TestLog& log = m_context.getTestContext().getLog();
399	log << tcu::TestLog::ImageSet("Result of rendering", "")
400		<< TestLog::Image("Result", "", resultAccess)
401		<< tcu::TestLog::EndImageSet;
402
403	return TestStatus::fail("Fail");
404}
405
406class InterfaceMatchingTestCase : public vkt::TestCase
407{
408public:
409					InterfaceMatchingTestCase	(tcu::TestContext&	testContext,
410												 TestParamsSp		params);
411	virtual			~InterfaceMatchingTestCase	(void) = default;
412
413	void			initPrograms				(SourceCollections& sourceCollections) const override;
414	void			checkSupport				(Context& context) const override;
415	TestInstance*	createInstance				(Context& context) const override;
416
417protected:
418
419	enum class ComponentType
420	{
421		FLOAT = 0,
422		INT,
423		UINT
424	};
425
426	struct VecData
427	{
428		std::string		glslType;
429		ComponentType	componentType;
430		deUint32		componentsCount;
431		std::string		components[4];
432	};
433
434	struct DecorationData
435	{
436		std::string		namePart;
437		std::string		glslDecoration;
438		std::string		glslComponent;
439	};
440
441	// helper structure used during construction of in/out declaration
442	struct PipelineData
443	{
444		bool outDeclArray;
445		bool inFlatDecoration;		// needed for frag in
446		bool inDeclArray;
447	};
448
449	typedef std::map<std::string, std::string> SpecializationMap;
450
451	std::string				genOutAssignment			(const std::string& variableName, const VecData& outVecData) const;
452	std::string				genInVerification			(const std::string& variableName, const VecData& outVecData, const VecData& inVecData) const;
453
454	const VecData&			getVecData					(VecType vecType) const;
455	const DecorationData&	getDecorationData			(DecorationType decorationType) const;
456
457	const PipelineData&		getPipelineData				(PipelineType pipelineType) const;
458	std::string				generateName				(const TestParams& testParams) const;
459
460private:
461
462	const TestParamsSp m_params;
463};
464
465InterfaceMatchingTestCase::InterfaceMatchingTestCase(tcu::TestContext&	testContext,
466													 TestParamsSp		params)
467	: vkt::TestCase	(testContext, generateName(*params))
468	, m_params		(params)
469{
470}
471
472void InterfaceMatchingTestCase::initPrograms(SourceCollections& sourceCollections) const
473{
474	GlslSourceCollection&	glslSources				= sourceCollections.glslSources;
475	const VecData&			outVecData				= getVecData(m_params->outVecType);
476	const VecData&			inVecData				= getVecData(m_params->inVecType);
477	const DecorationData&	outDecorationData		= getDecorationData(m_params->outDeclDecoration);
478	const DecorationData&	inDecorationData		= getDecorationData(m_params->inDeclDecoration);
479	const PipelineData&		pipelineData			= getPipelineData(m_params->pipelineType);
480
481	// deterimine if decoration or array is needed for in/out declarations
482	const std::string	outDeclArray			= pipelineData.outDeclArray ? "[]" : "";
483	const std::string	inDeclArray				= pipelineData.inDeclArray  ? "[]" : "";
484	const std::string	variableToAssignArray	= pipelineData.outDeclArray ? "[gl_InvocationID]" : "";
485	const std::string	variableToVerifyArray	= pipelineData.inDeclArray  ? "[0]" : "";
486
487	std::string		outDecoration	= "";
488	std::string		inDecoration	= pipelineData.inFlatDecoration ? "flat " : "";
489	std::string		outComponent	= outDecorationData.glslComponent;
490	std::string		inComponent		= inDecorationData.glslComponent;
491	if (m_params->testType == TestType::DECORATION_MISMATCH)
492	{
493		outDecoration	= outDecorationData.glslDecoration;
494		inDecoration	= inDecorationData.glslDecoration;
495	}
496
497	std::string outDeclaration;
498	std::string inDeclaration;
499	std::string variableToAssignName;
500	std::string variableToVerifyName;
501
502	// generate in/out declarations
503	switch (m_params->definitionType)
504	{
505	case DefinitionType::LOOSE_VARIABLE:
506		outDeclaration			= "layout(location = 0" + outDecorationData.glslComponent + ") out " + outDecoration + outVecData.glslType + " looseVariable" + outDeclArray + ";\n";
507		inDeclaration			= "layout(location = 0" +  inDecorationData.glslComponent + ") in "  +  inDecoration +  inVecData.glslType + " looseVariable" + inDeclArray  + ";\n";
508		variableToAssignName	= "looseVariable" + variableToAssignArray;
509		variableToVerifyName	= "looseVariable" + variableToVerifyArray;
510		break;
511
512	case DefinitionType::MEMBER_OF_BLOCK:
513		outDeclaration		   += "layout(location = 0) out block {\n"
514								  "  vec2 dummy;\n"
515								  "layout(location = 1" + outDecorationData.glslComponent + ") " +
516								  outDecoration + outVecData.glslType + " variableInBlock;\n"
517								  "} testBlock" + outDeclArray + ";\n";
518		inDeclaration		   += "in block {\n"
519								  "layout(location = 0) vec2 dummy;\n"
520								  "layout(location = 1" + inDecorationData.glslComponent + ") " +
521								  inDecoration + inVecData.glslType + " variableInBlock;\n"
522								  "} testBlock" + inDeclArray + ";\n";
523		variableToAssignName	= "testBlock" + variableToAssignArray + ".variableInBlock";
524		variableToVerifyName	= "testBlock" + variableToVerifyArray + ".variableInBlock";
525		break;
526
527	case DefinitionType::MEMBER_OF_STRUCTURE:
528		outDeclaration		   += "layout(location = 0) out " + outDecoration + "struct {\n"
529								  "  vec2 dummy;\n"
530								  "  " + outVecData.glslType + " variableInStruct;\n"
531								  "} testStruct" + outDeclArray + ";\n";
532		inDeclaration		   += "layout(location = 0) in " + inDecoration + "struct {\n"
533								  "  vec2 dummy;\n"
534								  "  " + inVecData.glslType + " variableInStruct;\n"
535								  "} testStruct" + inDeclArray + ";\n";
536		variableToAssignName	= "testStruct" + variableToAssignArray + ".variableInStruct";
537		variableToVerifyName	= "testStruct" + variableToVerifyArray + ".variableInStruct";
538		break;
539
540	case DefinitionType::MEMBER_OF_ARRAY_OF_STRUCTURES:
541		outDeclaration		   += "layout(location = 0) out " + outDecoration + "struct {\n"
542								  "  float dummy;\n"
543								  "  " + outVecData.glslType + " variableInStruct;\n"
544								  "} testStructArray" + outDeclArray + "[3];\n";
545		inDeclaration		   += "layout(location = 0) in " + inDecoration + "struct {\n"
546								  "  float dummy;\n"
547								  "  " + inVecData.glslType + " variableInStruct;\n"
548								  "} testStructArray" + inDeclArray + "[3];\n";
549		// just verify last item from array
550		variableToAssignName	= "testStructArray" + variableToAssignArray + "[2].variableInStruct";
551		variableToVerifyName	= "testStructArray" + variableToVerifyArray + "[2].variableInStruct";
552		break;
553
554	case DefinitionType::MEMBER_OF_STRUCTURE_IN_BLOCK:
555		outDeclaration		   += "struct TestStruct {\n"
556								  "  vec2 dummy;\n"
557								  "  " + outVecData.glslType + " variableInStruct;\n"
558								  "};\n"
559								  "layout(location = 0) out block {\n"
560								  "  vec2 dummy;\n"
561								  "  " + outDecoration + "TestStruct structInBlock;\n"
562								  "} testBlock" + outDeclArray + ";\n";
563		inDeclaration		   += "struct TestStruct {\n"
564								  "  vec2 dummy;\n"
565								  "  " + inVecData.glslType + " variableInStruct;\n"
566								  "};\n"
567								  "layout(location = 0) in block {\n"
568								  "  vec2 dummy;\n"
569								  "  " + inDecoration + "TestStruct structInBlock;\n"
570								  "} testBlock" + inDeclArray + ";\n";
571		variableToAssignName	= "testBlock" + variableToAssignArray  + ".structInBlock.variableInStruct";
572		variableToVerifyName	= "testBlock" + variableToVerifyArray  + ".structInBlock.variableInStruct";
573		break;
574
575	case DefinitionType::MEMBER_OF_ARRAY_OF_STRUCTURES_IN_BLOCK:
576		outDeclaration		   += "struct TestStruct {\n"
577								  "  vec4 dummy;\n"
578								  "  " + outVecData.glslType + " variableInStruct;\n"
579								  "};\n"
580								  "layout(location = 0) out block {\n"
581								  "  " + outDecoration + "TestStruct structArrayInBlock[3];\n"
582								  "} testBlock" + outDeclArray + ";\n";
583		inDeclaration		   += "struct TestStruct {\n"
584								  "  vec4 dummy;\n"
585								  "  " + inVecData.glslType + " variableInStruct;\n"
586								  "};"
587								  "layout(location = 0) in block {\n"
588								  "  " + inDecoration + "TestStruct structArrayInBlock[3];\n"
589								  "} testBlock" + inDeclArray + ";\n";
590		// just verify second item from array
591		variableToAssignName	= "testBlock" + variableToAssignArray  + ".structArrayInBlock[1].variableInStruct";
592		variableToVerifyName	= "testBlock" + variableToVerifyArray  + ".structArrayInBlock[1].variableInStruct";
593		break;
594
595	default:
596		DE_ASSERT(DE_FALSE);
597	}
598
599	std::string outValueAssignment	= genOutAssignment (variableToAssignName, outVecData);
600	std::string inValueVerification	= genInVerification(variableToVerifyName, outVecData, inVecData);
601
602	// create specialization map and grab references to both
603	// values so we dont have to index into it in every case
604	SpecializationMap specializationMap
605	{
606		{ "DECLARATIONS",	"" },
607		{ "OPERATIONS",		"" },
608	};
609	std::string& declarations	= specializationMap["DECLARATIONS"];
610	std::string& operations		= specializationMap["OPERATIONS"];
611
612	// define vertex shader source
613	if (isPipelineOneOf(m_params->pipelineType, {
614		PipelineType::VERT_OUT_FRAG_IN,
615		PipelineType::VERT_OUT_TESC_IN_TESE_FRAG,
616		PipelineType::VERT_OUT_GEOM_IN_FRAG,
617		PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG }))
618	{
619		declarations	= outDeclaration;
620		operations		= outValueAssignment;
621	}
622	// else passthrough source
623
624	tcu::StringTemplate vertTemplate(
625		"#version 450\n"
626		"layout(location = 0) in vec4 inPosition;\n"
627		"${DECLARATIONS}"
628		"void main(void)\n"
629		"{\n"
630		"  gl_Position = inPosition;\n"
631		"${OPERATIONS}"
632		"}\n");
633	glslSources.add("vert") << glu::VertexSource(vertTemplate.specialize(specializationMap));
634
635	// define tesselation control shader source
636	bool tescNeeded = DE_FALSE;
637	switch (m_params->pipelineType)
638	{
639	case PipelineType::VERT_TESC_OUT_TESE_IN_FRAG:
640		declarations	= outDeclaration;
641		operations		= outValueAssignment;
642		tescNeeded		= DE_TRUE;
643		break;
644
645	case PipelineType::VERT_OUT_TESC_IN_TESE_FRAG:
646	case PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG:
647		declarations	= inDeclaration +
648						  "layout(location = 0) out float outResult[];\n";
649		operations		= "  float result;\n" +
650						  inValueVerification +
651						  "  outResult[gl_InvocationID] = result;\n";
652		tescNeeded		= DE_TRUE;
653		break;
654
655	case PipelineType::VERT_TESC_TESE_OUT_FRAG_IN:
656	case PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG:
657	case PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN:
658		// passthrough sources
659		tescNeeded = DE_TRUE;
660		break;
661
662	default:
663		break;
664	}
665
666	std::string tescSource = tescNeeded ?
667		StringTemplate(
668			"#version 450\n"
669			"#extension GL_EXT_tessellation_shader : require\n\n"
670			"layout(vertices = 1) out;\n\n"
671			"${DECLARATIONS}"
672			"void main(void)\n"
673			"{\n"
674			"  gl_TessLevelInner[0] = 1.0;\n"
675			"  gl_TessLevelOuter[0] = 1.0;\n"
676			"  gl_TessLevelOuter[1] = 1.0;\n"
677			"  gl_TessLevelOuter[2] = 1.0;\n"
678			"${OPERATIONS}"
679			"}\n").specialize(specializationMap)
680		: "";
681
682	// define tesselation evaluation shader source
683	bool teseNeeded = DE_FALSE;
684	switch (m_params->pipelineType)
685	{
686	case PipelineType::VERT_TESC_TESE_OUT_FRAG_IN:
687	case PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG:
688		declarations	= outDeclaration;
689		operations		= outValueAssignment;
690		teseNeeded		= DE_TRUE;
691		break;
692
693	case PipelineType::VERT_TESC_OUT_TESE_IN_FRAG:
694		declarations	= inDeclaration +
695						  "layout(location = 0) out float outResult;\n";
696		operations		= "  float result;\n" +
697						  inValueVerification +
698						  "  outResult = result;\n";
699		teseNeeded		= DE_TRUE;
700		break;
701
702	case PipelineType::VERT_OUT_TESC_IN_TESE_FRAG:
703	case PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG:
704		declarations	= "layout(location = 0) in float inResult[];\n"
705						  "layout(location = 0) out float outResult;\n";
706		operations		= "  outResult = inResult[0];\n";
707		teseNeeded		= DE_TRUE;
708		break;
709
710	case PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN:
711		// passthrough sources
712		teseNeeded = DE_TRUE;
713		break;
714
715	default:
716		break;
717	}
718
719	std::string teseSource = teseNeeded ?
720		StringTemplate(
721			"#version 450\n"
722			"#extension GL_EXT_tessellation_shader : require\n\n"
723			"layout(triangles) in;\n"
724			"${DECLARATIONS}"
725			"void main(void)\n"
726			"{\n"
727			"  gl_Position = vec4(gl_TessCoord.xy * 2.0 - 1.0, 0.0, 1.0);\n"
728			"${OPERATIONS}"
729			"}\n").specialize(specializationMap)
730		: "";
731
732	DE_ASSERT(tescSource.empty() == teseSource.empty());
733	if (!tescSource.empty())
734	{
735		glslSources.add("tesc") << glu::TessellationControlSource(tescSource);
736		glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource);
737	}
738
739	// define geometry shader source
740	bool geomNeeded = DE_FALSE;
741	switch (m_params->pipelineType)
742	{
743	case PipelineType::VERT_GEOM_OUT_FRAG_IN:
744	case PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN:
745		declarations	= outDeclaration;
746		operations		= outValueAssignment;
747		geomNeeded		= DE_TRUE;
748		break;
749
750	case PipelineType::VERT_OUT_GEOM_IN_FRAG:
751	case PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG:
752		declarations	= inDeclaration +
753						  "layout(location = 0) out float result;\n";
754		operations		= inValueVerification;
755		geomNeeded		= DE_TRUE;
756		break;
757
758	case PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG:
759		declarations	= "layout(location = 0) in float inResult[];\n"
760						  "layout(location = 0) out float outResult;\n";
761		operations		= "  outResult = inResult[0];\n";
762		geomNeeded		= DE_TRUE;
763		break;
764
765	default:
766		break;
767	}
768
769	if (geomNeeded)
770	{
771		tcu::StringTemplate geomTemplate(
772			"#version 450\n"
773			"#extension GL_EXT_geometry_shader : require\n"
774			"layout(triangles) in;\n"
775			"layout(triangle_strip, max_vertices=3) out;\n"
776			"${DECLARATIONS}"
777			"void main(void)\n"
778			"{\n"
779			"${OPERATIONS}"
780			"  gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
781			"  EmitVertex();\n"
782			"${OPERATIONS}"
783			"  gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
784			"  EmitVertex();\n"
785			"${OPERATIONS}"
786			"  gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
787			"  EmitVertex();\n"
788			"  EndPrimitive();\n"
789			"}\n");
790		glslSources.add("geom") << glu::GeometrySource(geomTemplate.specialize(specializationMap));
791	}
792
793	// define fragment shader source
794	if (isPipelineOneOf(m_params->pipelineType, {
795		PipelineType::VERT_OUT_FRAG_IN,
796		PipelineType::VERT_TESC_TESE_OUT_FRAG_IN,
797		PipelineType::VERT_GEOM_OUT_FRAG_IN,
798		PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN }))
799	{
800		declarations	= inDeclaration;
801		operations		= "  float result = 0.0;\n" +
802						  inValueVerification;
803	}
804	else // passthrough source
805	{
806		declarations	= "layout(location = 0) in flat float result;\n";
807		operations		= "";
808	}
809
810	tcu::StringTemplate fragTemplate(
811		"#version 450\n"
812		"layout(location = 0) out vec4 fragColor;\n"
813		"${DECLARATIONS}"
814		"void main(void)\n"
815		"{\n"
816		"${OPERATIONS}"
817		"  fragColor = vec4(result);\n"
818		"}\n");
819	glslSources.add("frag") << glu::FragmentSource(fragTemplate.specialize(specializationMap));
820}
821
822std::string InterfaceMatchingTestCase::genOutAssignment(const std::string& variableName, const VecData&	outVecData) const
823{
824	// generate value assignment to out variable;
825	// for vec2/looseVariable this will generate:
826	//   "looseVariable = vec2(-2.0, 3.0);"
827
828	// define separators to avoid if statements in loop
829	std::string					outSeparator(", ");
830	std::string					endSeparator("");
831	std::vector<std::string*>	outSeparators(4, &outSeparator);
832	outSeparators[outVecData.componentsCount - 1] = &endSeparator;
833
834	// generate value assignment
835	std::string outValueAssignment = std::string("  ") + variableName + " = " + outVecData.glslType + "(";
836	for (deUint32 i = 0; i < outVecData.componentsCount; ++i)
837		outValueAssignment += outVecData.components[i] + *outSeparators[i];
838
839	return outValueAssignment + ");\n";
840}
841
842std::string InterfaceMatchingTestCase::genInVerification(const std::string& variableName, const VecData& outVecData, const VecData& inVecData) const
843{
844	// generate value verification;
845	// note that input has same or less components then output;
846	// for vec2/looseVariable this will generate:
847	//   "result = float(abs(looseVariable.x - -2.0) < eps) *"
848	//            "float(abs(looseVariable.y - 3.0) < eps);\n"
849
850	static const std::string componentNames[] = { "x", "y", "z", "w" };
851
852	// define separators to avoid if statements in loop
853	std::string		inSeparator		(" *\n\t\t   ");
854	std::string		endSeparator	("");
855	std::string*	inSeparators[]	{ &inSeparator, &inSeparator, &inSeparator, &endSeparator };
856
857	inSeparators[inVecData.componentsCount - 1] = &endSeparator;
858
859	std::string			inValueVerification("  result = ");
860	tcu::StringTemplate verificationTemplate(
861		inVecData.componentType == ComponentType::FLOAT ?
862		"float(abs(" + variableName + ".${COMPONENT} - ${VALUE}) < 0.001)" :
863		"float(" + variableName + ".${COMPONENT} == ${VALUE})");
864
865	// verify each component using formula for float or int
866	for (deUint32 i = 0; i < inVecData.componentsCount; ++i)
867	{
868		inValueVerification += verificationTemplate.specialize({
869			{ "COMPONENT",	componentNames[i] },
870			{ "VALUE",		outVecData.components[i] }
871		});
872		inValueVerification += *inSeparators[i];
873	}
874
875	return inValueVerification + ";\n";
876}
877
878void InterfaceMatchingTestCase::checkSupport(Context& context) const
879{
880	if (m_params->pipelineConstructionType != PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
881	{
882		checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_params->pipelineConstructionType);
883
884		// if graphicsPipelineLibraryIndependentInterpolationDecoration is VK_FALSE then interface mismatch
885		// tests involving the Flat or NoPerspective qualifiers should be skipped for pipeline library tests
886#ifndef CTS_USES_VULKANSC
887		if (!context.getGraphicsPipelineLibraryPropertiesEXT().graphicsPipelineLibraryIndependentInterpolationDecoration)
888		{
889			if ((m_params->inDeclDecoration == DecorationType::FLAT) ||
890				(m_params->inDeclDecoration == DecorationType::NO_PERSPECTIVE) ||
891				(m_params->outDeclDecoration == DecorationType::FLAT) ||
892				(m_params->outDeclDecoration == DecorationType::NO_PERSPECTIVE))
893				TCU_THROW(NotSupportedError, "graphicsPipelineLibraryIndependentInterpolationDecoration is not supported");
894		}
895#endif // CTS_USES_VULKANSC
896	}
897
898	// when outputs from earlier stage are matched with smaller
899	// inputs in future stage request VK_KHR_maintenance4
900	if ((m_params->testType == TestType::VECTOR_LENGTH) &&
901		(m_params->outVecType != m_params->inVecType))
902	{
903		context.requireDeviceFunctionality("VK_KHR_maintenance4");
904	}
905
906	const InstanceInterface&		vki				= context.getInstanceInterface();
907	const VkPhysicalDevice			physicalDevice	= context.getPhysicalDevice();
908	const VkPhysicalDeviceFeatures	features		= getPhysicalDeviceFeatures(vki, physicalDevice);
909
910	if (isPipelineOneOf(m_params->pipelineType, {
911		PipelineType::VERT_OUT_TESC_IN_TESE_FRAG,
912		PipelineType::VERT_TESC_TESE_OUT_FRAG_IN,
913		PipelineType::VERT_TESC_OUT_TESE_IN_FRAG,
914		PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG,
915		PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG,
916		PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN }))
917		if (!features.tessellationShader)
918			TCU_THROW(NotSupportedError, "Tessellation shader not supported");
919
920	if (isPipelineOneOf(m_params->pipelineType, {
921		PipelineType::VERT_OUT_GEOM_IN_FRAG,
922		PipelineType::VERT_GEOM_OUT_FRAG_IN,
923		PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG,
924		PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG,
925		PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN }))
926		if (!features.geometryShader)
927			TCU_THROW(NotSupportedError, "Geometry shader not supported");
928}
929
930TestInstance* InterfaceMatchingTestCase::createInstance(Context& context) const
931{
932	return new InterfaceMatchingTestInstance(context, m_params);
933}
934
935const InterfaceMatchingTestCase::VecData& InterfaceMatchingTestCase::getVecData(VecType vecType) const
936{
937	static const std::map<VecType, VecData> vecDataMap
938	{
939		{ VecType::VEC2,	{ "vec2",  ComponentType::FLOAT, 2, { "-2.0",  "3.0", "",    ""    } } },
940		{ VecType::VEC3,	{ "vec3",  ComponentType::FLOAT, 3, { "-3.0",  "2.0", "5.0", ""    } } },
941		{ VecType::VEC4,	{ "vec4",  ComponentType::FLOAT, 4, { "-4.0", "-9.0", "3.0", "7.0" } } },
942		{ VecType::IVEC2,	{ "ivec2", ComponentType::INT,   2, { "-4",    "8",   "",    ""    } } },
943		{ VecType::IVEC3,	{ "ivec3", ComponentType::INT,   3, { "-5",    "10",  "15",  ""    } } },
944		{ VecType::IVEC4,	{ "ivec4", ComponentType::INT,   4, { "-16",   "12",  "20",  "80"  } } },
945		{ VecType::UVEC2,	{ "uvec2", ComponentType::UINT,  2, { "2",     "8",   "",    ""    } } },
946		{ VecType::UVEC3,	{ "uvec3", ComponentType::UINT,  3, { "3",     "9",   "27",  ""    } } },
947		{ VecType::UVEC4,	{ "uvec4", ComponentType::UINT,  4, { "4",     "16",  "64",  "256" } } },
948	};
949
950	DE_ASSERT(vecDataMap.find(vecType) != vecDataMap.end());
951	return vecDataMap.at(vecType);
952}
953
954const InterfaceMatchingTestCase::DecorationData& InterfaceMatchingTestCase::getDecorationData(DecorationType decorationType) const
955{
956	static const std::map<DecorationType, DecorationData> decorationDataMap
957	{
958		{ DecorationType::NONE,				{ "none",			"",					""					} },
959		{ DecorationType::FLAT,				{ "flat",			"flat ",			""					} },
960		{ DecorationType::NO_PERSPECTIVE,	{ "noperspective",	"noperspective ",	""					} },
961		{ DecorationType::COMPONENT0,		{ "component0",		"",					", component = 0 "	} },
962	};
963
964	DE_ASSERT(decorationDataMap.find(decorationType) != decorationDataMap.end());
965	return decorationDataMap.at(decorationType);
966}
967
968const InterfaceMatchingTestCase::PipelineData& InterfaceMatchingTestCase::getPipelineData(PipelineType pipelineType) const
969{
970	// pipelineDataMap is used to simplify generation of declarations in glsl
971	// it represent fallowing rules:
972	// * for case where tesc outputs variable it must be declarred as an array
973	// * when frag input variable is verified we need to use flat interpolation
974	// * all stages except for frag need input to be array (note: we do not use input in vert)
975
976	static const std::map<PipelineType, PipelineData> pipelineDataMap
977	{
978		//													  outArr inFlat inArr
979		{ PipelineType::VERT_OUT_FRAG_IN,					{ 0,     1,     0 } },
980		{ PipelineType::VERT_OUT_TESC_IN_TESE_FRAG,			{ 0,     0,     1 } },
981		{ PipelineType::VERT_TESC_TESE_OUT_FRAG_IN,			{ 0,     1,     0 } },
982		{ PipelineType::VERT_TESC_OUT_TESE_IN_FRAG,			{ 1,     0,     1 } },
983		{ PipelineType::VERT_OUT_GEOM_IN_FRAG,				{ 0,     0,     1 } },
984		{ PipelineType::VERT_GEOM_OUT_FRAG_IN,				{ 0,     1,     0 } },
985		{ PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG,	{ 0,     0,     1 } },
986		{ PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG,	{ 0,     0,     1 } },
987		{ PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN,	{ 0,     1,     0 } },
988	};
989
990	DE_ASSERT(pipelineDataMap.find(pipelineType) != pipelineDataMap.end());
991	return pipelineDataMap.at(pipelineType);
992}
993
994std::string InterfaceMatchingTestCase::generateName(const TestParams& testParams) const
995{
996	static const std::map<PipelineType, std::string> pipelineTypeMap
997	{
998		{ PipelineType::VERT_OUT_FRAG_IN,							"vert_out_frag_in" },
999		{ PipelineType::VERT_OUT_TESC_IN_TESE_FRAG,					"vert_out_tesc_in_tese_frag" },
1000		{ PipelineType::VERT_TESC_TESE_OUT_FRAG_IN,					"vert_tesc_tese_out_frag_in" },
1001		{ PipelineType::VERT_TESC_OUT_TESE_IN_FRAG,					"vert_tesc_out_tese_in_frag" },
1002		{ PipelineType::VERT_OUT_GEOM_IN_FRAG,						"vert_out_geom_in_frag" },
1003		{ PipelineType::VERT_GEOM_OUT_FRAG_IN,						"vert_geom_out_frag_in" },
1004		{ PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG,			"vert_out_tesc_in_tese_geom_frag" },
1005		{ PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG,			"vert_tesc_tese_out_geom_in_frag" },
1006		{ PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN,			"vert_tesc_tese_geom_out_frag_in" },
1007	};
1008
1009	static const std::map <DefinitionType, std::string> definitionTypeMap
1010	{
1011		{ DefinitionType::LOOSE_VARIABLE,							"loose_variable" },
1012		{ DefinitionType::MEMBER_OF_BLOCK,							"member_of_block" },
1013		{ DefinitionType::MEMBER_OF_STRUCTURE,						"member_of_structure" },
1014		{ DefinitionType::MEMBER_OF_ARRAY_OF_STRUCTURES,			"member_of_array_of_structures" },
1015		{ DefinitionType::MEMBER_OF_STRUCTURE_IN_BLOCK,				"member_of_structure_in_block" },
1016		{ DefinitionType::MEMBER_OF_ARRAY_OF_STRUCTURES_IN_BLOCK,	"member_of_array_of_structures_in_block" },
1017	};
1018
1019	DE_ASSERT(pipelineTypeMap.find(testParams.pipelineType) != pipelineTypeMap.end());
1020	DE_ASSERT(definitionTypeMap.find(testParams.definitionType) != definitionTypeMap.end());
1021
1022	std::string caseName;
1023
1024	if (testParams.testType == TestType::VECTOR_LENGTH)
1025		caseName = "out_" + getVecData(testParams.outVecType).glslType +
1026				   "_in_" + getVecData(testParams.inVecType).glslType;
1027	else
1028		caseName = "out_" + getDecorationData(testParams.outDeclDecoration).namePart +
1029				   "_in_" + getDecorationData(testParams.inDeclDecoration).namePart;
1030
1031	return caseName + "_" +
1032		   definitionTypeMap.at(testParams.definitionType) + "_" +
1033		   pipelineTypeMap.at(testParams.pipelineType);
1034};
1035
1036} // anonymous
1037
1038tcu::TestCaseGroup* createInterfaceMatchingTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1039{
1040	VecType vecTypeList[3][3]
1041	{
1042		{ VecType::VEC4,	VecType::VEC3,		VecType::VEC2 },	// float
1043		{ VecType::IVEC4,	VecType::IVEC3,		VecType::IVEC2 },	// int
1044		{ VecType::UVEC4,	VecType::UVEC3,		VecType::UVEC2 },	// uint
1045	};
1046
1047	PipelineType pipelineTypeList[]
1048	{
1049		PipelineType::VERT_OUT_FRAG_IN,
1050		PipelineType::VERT_OUT_TESC_IN_TESE_FRAG,
1051		PipelineType::VERT_TESC_TESE_OUT_FRAG_IN,
1052		PipelineType::VERT_TESC_OUT_TESE_IN_FRAG,
1053		PipelineType::VERT_OUT_GEOM_IN_FRAG,
1054		PipelineType::VERT_GEOM_OUT_FRAG_IN,
1055		PipelineType::VERT_OUT_TESC_IN_TESE_GEOM_FRAG,
1056		PipelineType::VERT_TESC_TESE_OUT_GEOM_IN_FRAG,
1057		PipelineType::VERT_TESC_TESE_GEOM_OUT_FRAG_IN,
1058	};
1059
1060	DefinitionType definitionsTypeList[]
1061	{
1062		DefinitionType::LOOSE_VARIABLE,
1063		DefinitionType::MEMBER_OF_BLOCK,
1064		DefinitionType::MEMBER_OF_STRUCTURE,
1065		DefinitionType::MEMBER_OF_ARRAY_OF_STRUCTURES,
1066		DefinitionType::MEMBER_OF_STRUCTURE_IN_BLOCK,
1067		DefinitionType::MEMBER_OF_ARRAY_OF_STRUCTURES_IN_BLOCK,
1068	};
1069
1070	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "interface_matching"));
1071
1072	de::MovePtr<tcu::TestCaseGroup> vectorMatching(new tcu::TestCaseGroup(testCtx, "vector_length"));
1073	for (PipelineType pipelineType : pipelineTypeList)
1074		for (DefinitionType defType : definitionsTypeList)
1075		{
1076			// iterate over vector type - float, int or uint
1077			for (deUint32 vecDataFormat = 0; vecDataFormat < 3; ++vecDataFormat)
1078			{
1079				// iterate over all out/in lenght combinations
1080				const VecType* vecType = vecTypeList[vecDataFormat];
1081				for (deUint32 outVecSizeIndex = 0; outVecSizeIndex < 3; ++outVecSizeIndex)
1082				{
1083					VecType outVecType = vecType[outVecSizeIndex];
1084					for (deUint32 inVecSizeIndex = 0; inVecSizeIndex < 3; ++inVecSizeIndex)
1085					{
1086						VecType inVecType = vecType[inVecSizeIndex];
1087						if (outVecType < inVecType)
1088							continue;
1089
1090						auto testParams = new TestParams
1091						{
1092							pipelineConstructionType,
1093							TestType::VECTOR_LENGTH,
1094							outVecType,
1095							inVecType,
1096							DecorationType::NONE,
1097							DecorationType::NONE,
1098							pipelineType,
1099							defType
1100						};
1101
1102						vectorMatching->addChild(new InterfaceMatchingTestCase(testCtx, TestParamsSp(testParams)));
1103					}
1104				}
1105			}
1106		}
1107	testGroup->addChild(vectorMatching.release());
1108
1109	std::vector<std::pair<DecorationType, DecorationType> > decorationPairs
1110	{
1111		{ DecorationType::NONE,				DecorationType::NO_PERSPECTIVE },
1112		{ DecorationType::NONE,				DecorationType::FLAT },
1113		{ DecorationType::FLAT,				DecorationType::NO_PERSPECTIVE },
1114		{ DecorationType::FLAT,				DecorationType::NONE },
1115		{ DecorationType::NO_PERSPECTIVE,	DecorationType::FLAT },
1116		{ DecorationType::NO_PERSPECTIVE,	DecorationType::NONE },
1117		{ DecorationType::COMPONENT0,		DecorationType::NONE },
1118		{ DecorationType::NONE,				DecorationType::COMPONENT0 },
1119	};
1120
1121	de::MovePtr<tcu::TestCaseGroup> decorationMismatching(new tcu::TestCaseGroup(testCtx, "decoration_mismatch"));
1122	for (PipelineType stageType : pipelineTypeList)
1123		for (DefinitionType defType : definitionsTypeList)
1124			for (const auto& decoration : decorationPairs)
1125			{
1126				// tests component = 0 only for loose variables or member of block
1127				if (((decoration.first == DecorationType::COMPONENT0) ||
1128					 (decoration.second == DecorationType::COMPONENT0)) &&
1129					((defType != DefinitionType::LOOSE_VARIABLE) &&
1130					 (defType != DefinitionType::MEMBER_OF_BLOCK)))
1131					continue;
1132
1133				auto testParams = new TestParams
1134				{
1135					pipelineConstructionType,
1136					TestType::DECORATION_MISMATCH,
1137					VecType::VEC4,
1138					VecType::VEC4,
1139					decoration.first,
1140					decoration.second,
1141					stageType,
1142					defType
1143				};
1144				decorationMismatching->addChild(new InterfaceMatchingTestCase(testCtx, TestParamsSp(testParams)));
1145			}
1146
1147	testGroup->addChild(decorationMismatching.release());
1148	return testGroup.release();
1149}
1150
1151} // pipeline
1152} // vkt
1153