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