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