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