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