• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 namespace vkt
45 {
46 namespace pipeline
47 {
48 
49 using namespace vk;
50 using namespace de;
51 using namespace tcu;
52 
53 namespace
54 {
55 
56 enum class TestType
57 {
58 	VECTOR_LENGTH			= 0,
59 	DECORATION_MISMATCH,
60 };
61 
62 enum class VecType
63 {
64 	VEC2 = 0,
65 	VEC3,
66 	VEC4,
67 	IVEC2,
68 	IVEC3,
69 	IVEC4,
70 	UVEC2,
71 	UVEC3,
72 	UVEC4,
73 };
74 
75 enum class DecorationType
76 {
77 	NONE = 0,
78 	FLAT,
79 	NO_PERSPECTIVE,
80 	COMPONENT0
81 };
82 
83 enum 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 
104 enum 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 
114 struct 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 
129 typedef de::SharedPtr<TestParams> TestParamsSp;
130 
131 // helper function that check if specified pipeline is in set of pipelines
isPipelineOneOf(PipelineType pipelineType,std::set<PipelineType> pipelines)132 bool isPipelineOneOf(PipelineType pipelineType, std::set<PipelineType> pipelines)
133 {
134 	return !!pipelines.count(pipelineType);
135 }
136 
137 class InterfaceMatchingTestInstance : public vkt::TestInstance
138 {
139 public:
140 						InterfaceMatchingTestInstance	(Context&			context,
141 														 const TestParamsSp	params);
142 	virtual				~InterfaceMatchingTestInstance	(void) = default;
143 
144 	tcu::TestStatus		iterate(void) override;
145 
146 private:
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 
InterfaceMatchingTestInstance(Context & context,const TestParamsSp params)174 InterfaceMatchingTestInstance::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 
iterate(void)183 tcu::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 
406 class InterfaceMatchingTestCase : public vkt::TestCase
407 {
408 public:
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 
417 protected:
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 
460 private:
461 
462 	const TestParamsSp m_params;
463 };
464 
InterfaceMatchingTestCase(tcu::TestContext & testContext,TestParamsSp params)465 InterfaceMatchingTestCase::InterfaceMatchingTestCase(tcu::TestContext&	testContext,
466 													 TestParamsSp		params)
467 	: vkt::TestCase	(testContext, generateName(*params))
468 	, m_params		(params)
469 {
470 }
471 
initPrograms(SourceCollections & sourceCollections) const472 void 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 
genOutAssignment(const std::string & variableName,const VecData & outVecData) const822 std::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 
genInVerification(const std::string & variableName,const VecData & outVecData,const VecData & inVecData) const842 std::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 
checkSupport(Context & context) const878 void 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 
createInstance(Context & context) const930 TestInstance* InterfaceMatchingTestCase::createInstance(Context& context) const
931 {
932 	return new InterfaceMatchingTestInstance(context, m_params);
933 }
934 
getVecData(VecType vecType) const935 const 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 
getDecorationData(DecorationType decorationType) const954 const 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 
getPipelineData(PipelineType pipelineType) const968 const 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 
generateName(const TestParams & testParams) const994 std::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 
createInterfaceMatchingTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1038 tcu::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