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