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