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