xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Imagination Technologies Ltd.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Vertex Input Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineVertexInputTests.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktPipelineClearUtil.hpp"
30 #include "vktPipelineImageUtil.hpp"
31 #include "vktPipelineVertexUtil.hpp"
32 #include "vktPipelineReferenceRenderer.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestCaseUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkRef.hpp"
40 #include "vkRefUtil.hpp"
41 #include "vkTypeUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
44 #include "tcuFloat.hpp"
45 #include "tcuImageCompare.hpp"
46 #include "tcuFloat.hpp"
47 #include "deMemory.h"
48 #include "deRandom.hpp"
49 #include "deStringUtil.hpp"
50 #include "deUniquePtr.hpp"
51 
52 #include <sstream>
53 #include <vector>
54 #include <map>
55 #include <memory>
56 
57 namespace vkt
58 {
59 namespace pipeline
60 {
61 
62 namespace
63 {
64 
65 using namespace vk;
66 
67 constexpr int kMaxComponents = 4;
68 
isSupportedVertexFormat(Context & context,VkFormat format)69 bool isSupportedVertexFormat(Context &context, VkFormat format)
70 {
71     if (isVertexFormatDouble(format) && !context.getDeviceFeatures().shaderFloat64)
72         return false;
73 
74     VkFormatProperties formatProps;
75     deMemset(&formatProps, 0, sizeof(VkFormatProperties));
76     context.getInstanceInterface().getPhysicalDeviceFormatProperties(context.getPhysicalDevice(), format, &formatProps);
77 
78     return (formatProps.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0u;
79 }
80 
getRepresentableDifferenceUnorm(VkFormat format)81 float getRepresentableDifferenceUnorm(VkFormat format)
82 {
83     DE_ASSERT(isVertexFormatUnorm(format) || isVertexFormatSRGB(format));
84 
85     return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8)) - 1);
86 }
87 
getRepresentableDifferenceUnormPacked(VkFormat format,uint32_t componentNdx)88 float getRepresentableDifferenceUnormPacked(VkFormat format, uint32_t componentNdx)
89 {
90     DE_ASSERT((isVertexFormatUnorm(format) || isVertexFormatSRGB(format)) && isVertexFormatPacked(format));
91 
92     return 1.0f / float((1 << (getPackedVertexFormatComponentWidth(format, componentNdx))) - 1);
93 }
94 
getRepresentableDifferenceSnorm(VkFormat format)95 float getRepresentableDifferenceSnorm(VkFormat format)
96 {
97     DE_ASSERT(isVertexFormatSnorm(format));
98 
99     return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8 - 1)) - 1);
100 }
101 
getRepresentableDifferenceSnormPacked(VkFormat format,uint32_t componentNdx)102 float getRepresentableDifferenceSnormPacked(VkFormat format, uint32_t componentNdx)
103 {
104     DE_ASSERT(isVertexFormatSnorm(format) && isVertexFormatPacked(format));
105 
106     return 1.0f / float((1 << (getPackedVertexFormatComponentWidth(format, componentNdx) - 1)) - 1);
107 }
108 
getNextMultipleOffset(uint32_t divisor,uint32_t value)109 uint32_t getNextMultipleOffset(uint32_t divisor, uint32_t value)
110 {
111     if (value % divisor == 0)
112         return 0;
113     else
114         return divisor - (value % divisor);
115 }
116 
117 class VertexInputTest : public vkt::TestCase
118 {
119 public:
120     enum GlslType
121     {
122         GLSL_TYPE_INT,
123         GLSL_TYPE_IVEC2,
124         GLSL_TYPE_IVEC3,
125         GLSL_TYPE_IVEC4,
126 
127         GLSL_TYPE_UINT,
128         GLSL_TYPE_UVEC2,
129         GLSL_TYPE_UVEC3,
130         GLSL_TYPE_UVEC4,
131 
132         GLSL_TYPE_FLOAT,
133         GLSL_TYPE_VEC2,
134         GLSL_TYPE_VEC3,
135         GLSL_TYPE_VEC4,
136 
137         GLSL_TYPE_F16,
138         GLSL_TYPE_F16VEC2,
139         GLSL_TYPE_F16VEC3,
140         GLSL_TYPE_F16VEC4,
141 
142         GLSL_TYPE_MAT2,
143         GLSL_TYPE_MAT3,
144         GLSL_TYPE_MAT4,
145 
146         GLSL_TYPE_DOUBLE,
147         GLSL_TYPE_DVEC2,
148         GLSL_TYPE_DVEC3,
149         GLSL_TYPE_DVEC4,
150         GLSL_TYPE_DMAT2,
151         GLSL_TYPE_DMAT3,
152         GLSL_TYPE_DMAT4,
153 
154         GLSL_TYPE_COUNT
155     };
156 
157     enum GlslBasicType
158     {
159         GLSL_BASIC_TYPE_INT,
160         GLSL_BASIC_TYPE_UINT,
161         GLSL_BASIC_TYPE_FLOAT,
162         GLSL_BASIC_TYPE_DOUBLE,
163         GLSL_BASIC_TYPE_FLOAT16,
164     };
165 
166     enum BindingMapping
167     {
168         BINDING_MAPPING_ONE_TO_ONE, //!< Vertex input bindings will not contain data for more than one attribute.
169         BINDING_MAPPING_ONE_TO_MANY //!< Vertex input bindings can contain data for more than one attribute.
170     };
171 
172     enum AttributeLayout
173     {
174         ATTRIBUTE_LAYOUT_INTERLEAVED, //!< Attribute data is bundled together as if in a structure: [pos 0][color 0][pos 1][color 1]...
175         ATTRIBUTE_LAYOUT_SEQUENTIAL //!< Data for each attribute is laid out separately: [pos 0][pos 1]...[color 0][color 1]...
176         //   Sequential only makes a difference if ONE_TO_MANY mapping is used (more than one attribute in a binding).
177     };
178 
179     enum LayoutSkip
180     {
181         LAYOUT_SKIP_ENABLED, //!< Skip one location slot after each attribute
182         LAYOUT_SKIP_DISABLED //!< Consume locations sequentially
183     };
184 
185     enum LayoutOrder
186     {
187         LAYOUT_ORDER_IN_ORDER,    //!< Assign locations in order
188         LAYOUT_ORDER_OUT_OF_ORDER //!< Assign locations out of order
189     };
190 
191     struct AttributeInfo
192     {
193         GlslType glslType;
194         VkFormat vkType;
195         VkVertexInputRate inputRate;
196     };
197 
198     struct GlslTypeDescription
199     {
200         const char *name;
201         int vertexInputComponentCount;
202         int vertexInputCount;
203         GlslBasicType basicType;
204     };
205 
206     static const GlslTypeDescription s_glslTypeDescriptions[GLSL_TYPE_COUNT];
207 
208     VertexInputTest(tcu::TestContext &testContext, const std::string &name,
209                     const PipelineConstructionType pipelineConstructionType,
210                     const std::vector<AttributeInfo> &attributeInfos, BindingMapping bindingMapping,
211                     AttributeLayout attributeLayout, LayoutSkip layoutSkip = LAYOUT_SKIP_DISABLED,
212                     LayoutOrder layoutOrder = LAYOUT_ORDER_IN_ORDER, const bool testMissingComponents = false);
213 
~VertexInputTest(void)214     virtual ~VertexInputTest(void)
215     {
216     }
217     virtual void initPrograms(SourceCollections &programCollection) const;
218     virtual void checkSupport(Context &context) const;
219     virtual TestInstance *createInstance(Context &context) const;
220     static bool isCompatibleType(VkFormat format, GlslType glslType);
221 
222 private:
223     AttributeInfo getAttributeInfo(size_t attributeNdx) const;
224     size_t getNumAttributes(void) const;
225     std::string getGlslExtensions(void) const;
226     std::string getGlslInputDeclarations(void) const;
227     std::string getGlslVertexCheck(void) const;
228     std::string getGlslAttributeConditions(const AttributeInfo &attributeInfo, const std::string attributeIndex) const;
229     static tcu::Vec4 getFormatThreshold(VkFormat format);
230 
231     const PipelineConstructionType m_pipelineConstructionType;
232     const std::vector<AttributeInfo> m_attributeInfos;
233     const BindingMapping m_bindingMapping;
234     const AttributeLayout m_attributeLayout;
235     const LayoutSkip m_layoutSkip;
236     mutable std::vector<uint32_t> m_locations;
237     const bool m_queryMaxAttributes;
238     bool m_usesDoubleType;
239     bool m_usesFloat16Type;
240     mutable size_t m_maxAttributes;
241     const bool m_testMissingComponents;
242 };
243 
244 class VertexInputInstance : public vkt::TestInstance
245 {
246 public:
247     struct VertexInputAttributeDescription
248     {
249         VertexInputTest::GlslType glslType;
250         int vertexInputIndex;
251         VkVertexInputAttributeDescription vkDescription;
252     };
253 
254     typedef std::vector<VertexInputAttributeDescription> AttributeDescriptionList;
255 
256     VertexInputInstance(Context &context, const PipelineConstructionType pipelineConstructionType,
257                         const AttributeDescriptionList &attributeDescriptions,
258                         const std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
259                         const std::vector<VkDeviceSize> &bindingOffsets);
260 
261     virtual ~VertexInputInstance(void);
262     virtual tcu::TestStatus iterate(void);
263 
264     static void writeVertexInputData(uint8_t *destPtr, const VkVertexInputBindingDescription &bindingDescription,
265                                      const VkDeviceSize bindingOffset, const AttributeDescriptionList &attributes);
266     static void writeVertexInputValue(uint8_t *destPtr, const VertexInputAttributeDescription &attributes, int indexId);
267 
268 private:
269     tcu::TestStatus verifyImage(void);
270 
271 private:
272     std::vector<VkBuffer> m_vertexBuffers;
273     std::vector<Allocation *> m_vertexBufferAllocs;
274 
275     const tcu::UVec2 m_renderSize;
276     const VkFormat m_colorFormat;
277 
278     Move<VkImage> m_colorImage;
279     de::MovePtr<Allocation> m_colorImageAlloc;
280     Move<VkImage> m_depthImage;
281     Move<VkImageView> m_colorAttachmentView;
282     RenderPassWrapper m_renderPass;
283 
284     ShaderWrapper m_vertexShaderModule;
285     ShaderWrapper m_fragmentShaderModule;
286 
287     PipelineLayoutWrapper m_pipelineLayout;
288     GraphicsPipelineWrapper m_graphicsPipeline;
289 
290     Move<VkCommandPool> m_cmdPool;
291     Move<VkCommandBuffer> m_cmdBuffer;
292 };
293 
294 const VertexInputTest::GlslTypeDescription VertexInputTest::s_glslTypeDescriptions[GLSL_TYPE_COUNT] = {
295     {"int", 1, 1, GLSL_BASIC_TYPE_INT},           {"ivec2", 2, 1, GLSL_BASIC_TYPE_INT},
296     {"ivec3", 3, 1, GLSL_BASIC_TYPE_INT},         {"ivec4", 4, 1, GLSL_BASIC_TYPE_INT},
297 
298     {"uint", 1, 1, GLSL_BASIC_TYPE_UINT},         {"uvec2", 2, 1, GLSL_BASIC_TYPE_UINT},
299     {"uvec3", 3, 1, GLSL_BASIC_TYPE_UINT},        {"uvec4", 4, 1, GLSL_BASIC_TYPE_UINT},
300 
301     {"float", 1, 1, GLSL_BASIC_TYPE_FLOAT},       {"vec2", 2, 1, GLSL_BASIC_TYPE_FLOAT},
302     {"vec3", 3, 1, GLSL_BASIC_TYPE_FLOAT},        {"vec4", 4, 1, GLSL_BASIC_TYPE_FLOAT},
303 
304     {"float16_t", 1, 1, GLSL_BASIC_TYPE_FLOAT16}, {"f16vec2", 2, 1, GLSL_BASIC_TYPE_FLOAT16},
305     {"f16vec3", 3, 1, GLSL_BASIC_TYPE_FLOAT16},   {"f16vec4", 4, 1, GLSL_BASIC_TYPE_FLOAT16},
306 
307     {"mat2", 2, 2, GLSL_BASIC_TYPE_FLOAT},        {"mat3", 3, 3, GLSL_BASIC_TYPE_FLOAT},
308     {"mat4", 4, 4, GLSL_BASIC_TYPE_FLOAT},
309 
310     {"double", 1, 1, GLSL_BASIC_TYPE_DOUBLE},     {"dvec2", 2, 1, GLSL_BASIC_TYPE_DOUBLE},
311     {"dvec3", 3, 1, GLSL_BASIC_TYPE_DOUBLE},      {"dvec4", 4, 1, GLSL_BASIC_TYPE_DOUBLE},
312     {"dmat2", 2, 2, GLSL_BASIC_TYPE_DOUBLE},      {"dmat3", 3, 3, GLSL_BASIC_TYPE_DOUBLE},
313     {"dmat4", 4, 4, GLSL_BASIC_TYPE_DOUBLE}};
314 
expandGlslNameToFullComponents(const char * name)315 const char *expandGlslNameToFullComponents(const char *name)
316 {
317     static const std::map<std::string, std::string> nameMap
318     {
319         std::make_pair("int", "ivec4"), std::make_pair("ivec2", "ivec4"), std::make_pair("ivec3", "ivec4"),
320             std::make_pair("ivec4", "ivec4"), std::make_pair("uint", "uvec4"), std::make_pair("uvec2", "uvec4"),
321             std::make_pair("uvec3", "uvec4"), std::make_pair("uvec4", "uvec4"), std::make_pair("float", "vec4"),
322             std::make_pair("vec2", "vec4"), std::make_pair("vec3", "vec4"), std::make_pair("vec4", "vec4"),
323             std::make_pair("float16_t", "f16vec4"), std::make_pair("f16vec2", "f16vec4"),
324             std::make_pair("f16vec3", "f16vec4"), std::make_pair("f16vec4", "f16vec4"),
325             std::make_pair("mat2", "mat2x4"), std::make_pair("mat3", "mat3x4"), std::make_pair("mat4", "mat4"),
326 #if 0
327         // 64-bit types don't have default values, so they cannot be used in missing component tests.
328         // In addition, they may be expanded from one location to using more than one, which creates vertex input mismatches.
329         std::make_pair("double", "dvec4"),
330         std::make_pair("dvec2", "dvec4"),
331         std::make_pair("dvec3", "dvec4"),
332         std::make_pair("dvec4", "dvec4"),
333         std::make_pair("dmat2", "dmat2x4"),
334         std::make_pair("dmat3", "dmat3x4"),
335         std::make_pair("dmat4", "dmat4"),
336 #endif
337     };
338 
339     const auto pos = nameMap.find(name);
340     if (pos == nameMap.end())
341         return nullptr;
342     return pos->second.c_str();
343 }
344 
getAttributeBinding(const VertexInputTest::BindingMapping bindingMapping,const VkVertexInputRate firstInputRate,const VkVertexInputRate inputRate,const uint32_t attributeNdx)345 uint32_t getAttributeBinding(const VertexInputTest::BindingMapping bindingMapping,
346                              const VkVertexInputRate firstInputRate, const VkVertexInputRate inputRate,
347                              const uint32_t attributeNdx)
348 {
349     if (bindingMapping == VertexInputTest::BINDING_MAPPING_ONE_TO_ONE)
350     {
351         // Each attribute uses a unique binding
352         return attributeNdx;
353     }
354     else // bindingMapping == BINDING_MAPPING_ONE_TO_MANY
355     {
356         // Alternate between two bindings
357         return uint32_t(firstInputRate + inputRate) % 2u;
358     }
359 }
360 
361 //! Number of locations used up by an attribute.
getConsumedLocations(const VertexInputTest::AttributeInfo & attributeInfo)362 uint32_t getConsumedLocations(const VertexInputTest::AttributeInfo &attributeInfo)
363 {
364     // double formats with more than 2 components will take 2 locations
365     const VertexInputTest::GlslType type = attributeInfo.glslType;
366     if ((type == VertexInputTest::GLSL_TYPE_DMAT2 || type == VertexInputTest::GLSL_TYPE_DMAT3 ||
367          type == VertexInputTest::GLSL_TYPE_DMAT4) &&
368         (attributeInfo.vkType == VK_FORMAT_R64G64B64_SFLOAT || attributeInfo.vkType == VK_FORMAT_R64G64B64A64_SFLOAT))
369     {
370         return 2u;
371     }
372     else
373         return 1u;
374 }
375 
VertexInputTest(tcu::TestContext & testContext,const std::string & name,const PipelineConstructionType pipelineConstructionType,const std::vector<AttributeInfo> & attributeInfos,BindingMapping bindingMapping,AttributeLayout attributeLayout,LayoutSkip layoutSkip,LayoutOrder layoutOrder,const bool testMissingComponents)376 VertexInputTest::VertexInputTest(tcu::TestContext &testContext, const std::string &name,
377                                  const PipelineConstructionType pipelineConstructionType,
378                                  const std::vector<AttributeInfo> &attributeInfos, BindingMapping bindingMapping,
379                                  AttributeLayout attributeLayout, LayoutSkip layoutSkip, LayoutOrder layoutOrder,
380                                  const bool testMissingComponents)
381     : vkt::TestCase(testContext, name)
382     , m_pipelineConstructionType(pipelineConstructionType)
383     , m_attributeInfos(attributeInfos)
384     , m_bindingMapping(bindingMapping)
385     , m_attributeLayout(attributeLayout)
386     , m_layoutSkip(layoutSkip)
387     , m_queryMaxAttributes(attributeInfos.size() == 0)
388     , m_usesDoubleType(false)
389     , m_usesFloat16Type(false)
390     , m_maxAttributes(16)
391     , m_testMissingComponents(testMissingComponents)
392 {
393     DE_ASSERT(m_attributeLayout == ATTRIBUTE_LAYOUT_INTERLEAVED || m_bindingMapping == BINDING_MAPPING_ONE_TO_MANY);
394 
395     for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
396     {
397         const auto &basicType = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].basicType;
398 
399         if (basicType == GLSL_BASIC_TYPE_DOUBLE)
400             m_usesDoubleType = true;
401         else if (basicType == GLSL_BASIC_TYPE_FLOAT16)
402             m_usesFloat16Type = true;
403     }
404 
405     // Determine number of location slots required for each attribute
406     uint32_t attributeLocation = 0;
407     std::vector<uint32_t> locationSlotsNeeded;
408     const size_t numAttributes = getNumAttributes();
409 
410     for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
411     {
412         const AttributeInfo &attributeInfo             = getAttributeInfo(attributeNdx);
413         const GlslTypeDescription &glslTypeDescription = s_glslTypeDescriptions[attributeInfo.glslType];
414         const uint32_t prevAttributeLocation           = attributeLocation;
415 
416         attributeLocation += glslTypeDescription.vertexInputCount * getConsumedLocations(attributeInfo);
417 
418         if (m_layoutSkip == LAYOUT_SKIP_ENABLED)
419             attributeLocation++;
420 
421         locationSlotsNeeded.push_back(attributeLocation - prevAttributeLocation);
422     }
423 
424     if (layoutOrder == LAYOUT_ORDER_IN_ORDER)
425     {
426         uint32_t loc = 0;
427 
428         // Assign locations in order
429         for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
430         {
431             m_locations.push_back(loc);
432             loc += locationSlotsNeeded[attributeNdx];
433         }
434     }
435     else
436     {
437         // Assign locations out of order
438         std::vector<uint32_t> indices;
439         std::vector<uint32_t> slots;
440         uint32_t slot = 0;
441 
442         // Mix the location slots: first all even and then all odd attributes.
443         for (uint32_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
444             if (attributeNdx % 2 == 0)
445                 indices.push_back(attributeNdx);
446         for (uint32_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
447             if (attributeNdx % 2 != 0)
448                 indices.push_back(attributeNdx);
449 
450         for (size_t i = 0; i < indices.size(); i++)
451         {
452             slots.push_back(slot);
453             slot += locationSlotsNeeded[indices[i]];
454         }
455 
456         for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
457         {
458             uint32_t slotIdx = 0;
459             for (uint32_t i = 0; i < (uint32_t)indices.size(); i++)
460                 if (attributeNdx == indices[i])
461                     slotIdx = i;
462             m_locations.push_back(slots[slotIdx]);
463         }
464     }
465 }
466 
getAttributeInfo(size_t attributeNdx) const467 VertexInputTest::AttributeInfo VertexInputTest::getAttributeInfo(size_t attributeNdx) const
468 {
469     if (m_queryMaxAttributes)
470     {
471         AttributeInfo attributeInfo = {GLSL_TYPE_VEC4, VK_FORMAT_R8G8B8A8_SNORM,
472                                        (attributeNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX :
473                                                                  VK_VERTEX_INPUT_RATE_INSTANCE};
474 
475         return attributeInfo;
476     }
477     else
478     {
479         return m_attributeInfos.at(attributeNdx);
480     }
481 }
482 
getNumAttributes(void) const483 size_t VertexInputTest::getNumAttributes(void) const
484 {
485     if (m_queryMaxAttributes)
486         return m_maxAttributes;
487     else
488         return m_attributeInfos.size();
489 }
490 
checkSupport(Context & context) const491 void VertexInputTest::checkSupport(Context &context) const
492 {
493     const uint32_t maxAttributes = context.getDeviceProperties().limits.maxVertexInputAttributes;
494 
495     if (m_attributeInfos.size() > maxAttributes)
496         TCU_THROW(NotSupportedError, "Unsupported number of vertex input attributes, maxVertexInputAttributes: " +
497                                          de::toString(maxAttributes));
498 
499     if (m_usesFloat16Type)
500     {
501         const auto &sf16i8Features = context.getShaderFloat16Int8Features();
502         if (!sf16i8Features.shaderFloat16)
503             TCU_THROW(NotSupportedError, "shaderFloat16 not supported");
504 
505         const auto &storage16Features = context.get16BitStorageFeatures();
506         if (!storage16Features.storageInputOutput16)
507             TCU_THROW(NotSupportedError, "storageInputOutput16 not supported");
508     }
509 
510     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
511                                           m_pipelineConstructionType);
512 }
513 
createInstance(Context & context) const514 TestInstance *VertexInputTest::createInstance(Context &context) const
515 {
516     typedef VertexInputInstance::VertexInputAttributeDescription VertexInputAttributeDescription;
517 
518     // Check upfront for maximum number of vertex input attributes
519     {
520         const InstanceInterface &vki        = context.getInstanceInterface();
521         const VkPhysicalDevice physDevice   = context.getPhysicalDevice();
522         const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits;
523 
524         const uint32_t maxAttributes = limits.maxVertexInputAttributes;
525 
526         // Use VkPhysicalDeviceLimits::maxVertexInputAttributes
527         if (m_queryMaxAttributes)
528         {
529             m_maxAttributes = maxAttributes;
530             m_locations.clear();
531             for (uint32_t i = 0; i < maxAttributes; i++)
532                 m_locations.push_back(i);
533         }
534     }
535 
536     // Create enough binding descriptions with random offsets
537     std::vector<VkVertexInputBindingDescription> bindingDescriptions;
538     std::vector<VkDeviceSize> bindingOffsets;
539     const size_t numAttributes = getNumAttributes();
540     const size_t numBindings =
541         (m_bindingMapping == BINDING_MAPPING_ONE_TO_ONE) ? numAttributes : ((numAttributes > 1) ? 2 : 1);
542     const VkVertexInputRate firstInputrate = getAttributeInfo(0).inputRate;
543 
544     for (size_t bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
545     {
546         // Bindings alternate between STEP_RATE_VERTEX and STEP_RATE_INSTANCE
547         const VkVertexInputRate inputRate =
548             ((firstInputrate + bindingNdx) % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
549 
550         // Stride will be updated when creating the attribute descriptions
551         const VkVertexInputBindingDescription bindingDescription = {
552             static_cast<uint32_t>(bindingNdx), // uint32_t binding;
553             0u,                                // uint32_t stride;
554             inputRate                          // VkVertexInputRate inputRate;
555         };
556 
557         bindingDescriptions.push_back(bindingDescription);
558         bindingOffsets.push_back(4 * bindingNdx);
559     }
560 
561     std::vector<VertexInputAttributeDescription> attributeDescriptions;
562     std::vector<uint32_t> attributeOffsets(bindingDescriptions.size(), 0);
563     std::vector<uint32_t> attributeMaxSizes(bindingDescriptions.size(),
564                                             0); // max component or vector size, depending on which layout we are using
565     std::vector<uint32_t> attributeMaxCompSizes(bindingDescriptions.size(), 0u); // max component size for each binding.
566     std::vector<uint32_t> bindingSeqStrides(bindingDescriptions.size(),
567                                             0u); // strides for bindings in sequential layout mode
568 
569     // To place the attributes sequentially we need to know the largest attribute and use its size in stride and offset calculations.
570     if (m_attributeLayout == ATTRIBUTE_LAYOUT_SEQUENTIAL)
571     {
572         for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
573         {
574             const AttributeInfo &attributeInfo = getAttributeInfo(attributeNdx);
575             const uint32_t attributeBinding    = getAttributeBinding(
576                 m_bindingMapping, firstInputrate, attributeInfo.inputRate, static_cast<uint32_t>(attributeNdx));
577             const uint32_t inputSize    = getVertexFormatSize(attributeInfo.vkType);
578             const auto componentSize    = getVertexFormatComponentSize(attributeInfo.vkType);
579             const auto maxSize          = de::max(attributeMaxSizes[attributeBinding], inputSize);
580             const auto maxComponentSize = de::max(attributeMaxCompSizes[attributeBinding], componentSize);
581 
582             attributeMaxSizes[attributeBinding]     = maxSize;
583             attributeMaxCompSizes[attributeBinding] = maxComponentSize;
584         }
585 
586         // Round up the maximum size so the components are always aligned.
587         for (size_t bindingIdx = 0u; bindingIdx < bindingSeqStrides.size(); ++bindingIdx)
588             bindingSeqStrides[bindingIdx] =
589                 de::roundUp(attributeMaxSizes[bindingIdx], attributeMaxCompSizes[bindingIdx]);
590     }
591 
592     // Create attribute descriptions, assign them to bindings and update stride.
593     for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
594     {
595         const AttributeInfo &attributeInfo             = getAttributeInfo(attributeNdx);
596         const GlslTypeDescription &glslTypeDescription = s_glslTypeDescriptions[attributeInfo.glslType];
597         const uint32_t inputSize                       = getVertexFormatSize(attributeInfo.vkType);
598         const uint32_t attributeBinding = getAttributeBinding(m_bindingMapping, firstInputrate, attributeInfo.inputRate,
599                                                               static_cast<uint32_t>(attributeNdx));
600         const uint32_t vertexCount      = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? (4 * 2) : 2;
601 
602         VertexInputAttributeDescription attributeDescription = {
603             attributeInfo.glslType, // GlslType glslType;
604             0,                      // int vertexInputIndex;
605             {
606                 0u,                   // uint32_t    location;
607                 attributeBinding,     // uint32_t    binding;
608                 attributeInfo.vkType, // VkFormat    format;
609                 0u,                   // uint32_t    offset;
610             },
611         };
612 
613         // Matrix types add each column as a separate attribute.
614         for (int descNdx = 0; descNdx < glslTypeDescription.vertexInputCount; ++descNdx)
615         {
616             attributeDescription.vertexInputIndex = descNdx;
617             attributeDescription.vkDescription.location =
618                 m_locations[attributeNdx] + getConsumedLocations(attributeInfo) * descNdx;
619 
620             if (m_attributeLayout == ATTRIBUTE_LAYOUT_INTERLEAVED)
621             {
622                 const uint32_t offsetToComponentAlignment = getNextMultipleOffset(
623                     inputSize, (uint32_t)bindingOffsets[attributeBinding] + attributeOffsets[attributeBinding]);
624 
625                 attributeOffsets[attributeBinding] += offsetToComponentAlignment;
626 
627                 attributeDescription.vkDescription.offset = attributeOffsets[attributeBinding];
628                 attributeDescriptions.push_back(attributeDescription);
629 
630                 bindingDescriptions[attributeBinding].stride += offsetToComponentAlignment + inputSize;
631                 attributeOffsets[attributeBinding] += inputSize;
632                 attributeMaxSizes[attributeBinding] = de::max(attributeMaxSizes[attributeBinding], inputSize);
633             }
634             else // m_attributeLayout == ATTRIBUTE_LAYOUT_SEQUENTIAL
635             {
636                 attributeDescription.vkDescription.offset = attributeOffsets[attributeBinding];
637                 attributeDescriptions.push_back(attributeDescription);
638 
639                 attributeOffsets[attributeBinding] += vertexCount * bindingSeqStrides[attributeBinding];
640             }
641         }
642 
643         if (m_attributeLayout == ATTRIBUTE_LAYOUT_SEQUENTIAL)
644             bindingDescriptions[attributeBinding].stride = bindingSeqStrides[attributeBinding];
645     }
646 
647     if (m_attributeLayout == ATTRIBUTE_LAYOUT_INTERLEAVED)
648     {
649         // Make sure the stride results in aligned access
650         for (size_t bindingNdx = 0; bindingNdx < bindingDescriptions.size(); ++bindingNdx)
651         {
652             auto &stride = bindingDescriptions[bindingNdx].stride; // note: by reference to modify it below.
653 
654             if (attributeMaxSizes[bindingNdx] > 0)
655                 stride += getNextMultipleOffset(attributeMaxSizes[bindingNdx], stride);
656         }
657     }
658 
659     // Check upfront for maximum number of vertex input bindings
660     {
661         const InstanceInterface &vki        = context.getInstanceInterface();
662         const VkPhysicalDevice physDevice   = context.getPhysicalDevice();
663         const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits;
664 
665         const uint32_t maxBindings = limits.maxVertexInputBindings;
666 
667         if (bindingDescriptions.size() > maxBindings)
668         {
669             const std::string notSupportedStr =
670                 "Unsupported number of vertex input bindings, maxVertexInputBindings: " + de::toString(maxBindings);
671             TCU_THROW(NotSupportedError, notSupportedStr.c_str());
672         }
673     }
674 
675     // Portability requires stride to be multiply of minVertexInputBindingStrideAlignment
676 #ifndef CTS_USES_VULKANSC
677     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
678     {
679         uint32_t minStrideAlignment = context.getPortabilitySubsetProperties().minVertexInputBindingStrideAlignment;
680         for (size_t bindingNdx = 0; bindingNdx < bindingDescriptions.size(); ++bindingNdx)
681         {
682             if ((bindingDescriptions[bindingNdx].stride % minStrideAlignment) != 0)
683                 TCU_THROW(NotSupportedError,
684                           "VK_KHR_portability_subset: stride is not multiply of minVertexInputBindingStrideAlignment");
685         }
686     }
687 #endif // CTS_USES_VULKANSC
688 
689     return new VertexInputInstance(context, m_pipelineConstructionType, attributeDescriptions, bindingDescriptions,
690                                    bindingOffsets);
691 }
692 
initPrograms(SourceCollections & programCollection) const693 void VertexInputTest::initPrograms(SourceCollections &programCollection) const
694 {
695     std::ostringstream vertexSrc;
696 
697     vertexSrc << "#version 460\n"
698               << getGlslExtensions() << "layout(constant_id = 0) const int numAttributes = " << m_maxAttributes << ";\n"
699               << getGlslInputDeclarations() << "layout(location = 0) out highp vec4 vtxColor;\n"
700               << "out gl_PerVertex {\n"
701               << "  vec4 gl_Position;\n"
702               << "};\n";
703 
704     vertexSrc << "void main (void)\n"
705               << "{\n"
706               << getGlslVertexCheck() << "}\n";
707 
708     programCollection.glslSources.add("attribute_test_vert") << glu::VertexSource(vertexSrc.str());
709 
710     programCollection.glslSources.add("attribute_test_frag")
711         << glu::FragmentSource("#version 460\n"
712                                "layout(location = 0) in highp vec4 vtxColor;\n"
713                                "layout(location = 0) out highp vec4 fragColor;\n"
714                                "void main (void)\n"
715                                "{\n"
716                                "    fragColor = vtxColor;\n"
717                                "}\n");
718 }
719 
getGlslExtensions(void) const720 std::string VertexInputTest::getGlslExtensions(void) const
721 {
722     std::string extensions;
723 
724     if (m_usesFloat16Type)
725         extensions += "#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require\n";
726 
727     return extensions;
728 }
729 
getGlslInputDeclarations(void) const730 std::string VertexInputTest::getGlslInputDeclarations(void) const
731 {
732     std::ostringstream glslInputs;
733 
734     if (m_queryMaxAttributes)
735     {
736         // Don't use the first input binding to leave room for VertexIndex and InstanceIndex, which count towards the
737         // total number of inputs attributes. Leave the first binding so that the largest location number are still used.
738         const GlslTypeDescription &glslTypeDesc = s_glslTypeDescriptions[GLSL_TYPE_VEC4];
739         glslInputs << "layout(location = 1) in " << glslTypeDesc.name << " attr[numAttributes-1];\n";
740     }
741     else
742     {
743         for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
744         {
745             const char *declType = nullptr;
746             if (m_testMissingComponents)
747             {
748                 const auto &glslType = m_attributeInfos[attributeNdx].glslType;
749                 const auto &typeInfo = s_glslTypeDescriptions[glslType];
750 
751                 DE_ASSERT(typeInfo.vertexInputComponentCount < kMaxComponents);
752                 DE_ASSERT(typeInfo.basicType != GLSL_BASIC_TYPE_DOUBLE);
753 
754                 // Find the equivalent type with 4 components.
755                 declType = expandGlslNameToFullComponents(typeInfo.name);
756             }
757             else
758                 declType = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].name;
759 
760             glslInputs << "layout(location = " << m_locations[attributeNdx] << ") in " << declType << " attr"
761                        << attributeNdx << ";\n";
762         }
763     }
764 
765     return glslInputs.str();
766 }
767 
getGlslVertexCheck(void) const768 std::string VertexInputTest::getGlslVertexCheck(void) const
769 {
770     std::ostringstream glslCode;
771     std::string inputCountStr;
772 
773     glslCode << "    int okCount = 0;\n";
774 
775     if (m_queryMaxAttributes)
776     {
777         DE_ASSERT(!m_testMissingComponents);
778 
779         // numAttributes will be replaced later by a specialisation constant, so this loop and
780         // the multiplication by numAttributes, below, must happen in the shader itself.
781         const AttributeInfo attributeInfo = getAttributeInfo(0);
782 
783         glslCode << "    for (int checkNdx = 1; checkNdx < numAttributes; checkNdx++)\n"
784                  << "    {\n"
785                  << "        uint index = (checkNdx % 2 == 0) ? gl_VertexIndex : gl_InstanceIndex;\n";
786 
787         // Because our location is offset by 1 relative to the API definitions, checkNdx-1 here.
788         glslCode << getGlslAttributeConditions(attributeInfo, "checkNdx-1") << "    }\n";
789 
790         const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
791         int totalInputComponentCount =
792             vertexInputCount *
793             VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
794 
795         // Don't count components from location 0 which was skipped.
796         inputCountStr = std::to_string(totalInputComponentCount) + " * (numAttributes-1)";
797     }
798     else
799     {
800         // Generate 1 check per attribute and work out the number of components at compile time.
801         int totalInputComponentCount = 0;
802         for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
803         {
804             glslCode << getGlslAttributeConditions(m_attributeInfos[attributeNdx], de::toString(attributeNdx));
805 
806             const int vertexInputCount =
807                 VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputCount;
808             const int vertexCompCount = VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType]
809                                             .vertexInputComponentCount;
810             totalInputComponentCount +=
811                 vertexInputCount * ((!m_testMissingComponents) ? vertexCompCount : kMaxComponents - vertexCompCount);
812         }
813 
814         inputCountStr = std::to_string(totalInputComponentCount);
815     }
816 
817     glslCode << "    if (okCount == " << inputCountStr
818              << ")\n"
819                 "    {\n"
820                 "        if (gl_InstanceIndex == 0)\n"
821                 "            vtxColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
822                 "        else\n"
823                 "            vtxColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
824                 "    }\n"
825                 "    else\n"
826                 "    {\n"
827                 "        vtxColor = vec4(okCount / float("
828              << inputCountStr << "), 0.0f, 0.0f, 1.0);\n"
829              << "    }\n\n"
830                 "    if (gl_InstanceIndex == 0)\n"
831                 "    {\n"
832                 "        if (gl_VertexIndex == 0) gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
833                 "        else if (gl_VertexIndex == 1) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
834                 "        else if (gl_VertexIndex == 2) gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
835                 "        else if (gl_VertexIndex == 3) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
836                 "        else gl_Position = vec4(0.0);\n"
837                 "    }\n"
838                 "    else\n"
839                 "    {\n"
840                 "        if (gl_VertexIndex == 0) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
841                 "        else if (gl_VertexIndex == 1) gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
842                 "        else if (gl_VertexIndex == 2) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
843                 "        else if (gl_VertexIndex == 3) gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
844                 "        else gl_Position = vec4(0.0);\n"
845                 "    }\n";
846 
847     return glslCode.str();
848 }
849 
getGlslAttributeConditions(const AttributeInfo & attributeInfo,const std::string attributeIndex) const850 std::string VertexInputTest::getGlslAttributeConditions(const AttributeInfo &attributeInfo,
851                                                         const std::string attributeIndex) const
852 {
853     std::ostringstream glslCode;
854     std::ostringstream attributeVar;
855     const int componentCount =
856         VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
857     const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
858     const uint32_t totalComponentCount = componentCount * vertexInputCount;
859     const tcu::Vec4 threshold          = getFormatThreshold(attributeInfo.vkType);
860     const std::string indexStr         = m_queryMaxAttributes ? "[" + attributeIndex + "]" : attributeIndex;
861     const std::string indentStr        = m_queryMaxAttributes ? "\t\t" : "\t";
862     uint32_t componentIndex            = 0;
863     uint32_t orderNdx;
864     std::string indexId;
865 
866     const uint32_t BGROrder[]  = {2, 1, 0, 3};
867     const uint32_t ABGROrder[] = {3, 2, 1, 0};
868     const uint32_t ARGBOrder[] = {1, 2, 3, 0};
869 
870     if (m_queryMaxAttributes)
871         indexId = "index";
872     else
873         indexId = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? "gl_VertexIndex" : "gl_InstanceIndex";
874 
875     attributeVar << "attr" << indexStr;
876 
877     glslCode << std::fixed;
878 
879     for (int columnNdx = 0; columnNdx < vertexInputCount; columnNdx++)
880     {
881         for (int rowNdx = 0; rowNdx < kMaxComponents; rowNdx++)
882         {
883             if (isVertexFormatComponentOrderABGR(attributeInfo.vkType))
884                 orderNdx = ABGROrder[rowNdx];
885             else if (isVertexFormatComponentOrderARGB(attributeInfo.vkType))
886                 orderNdx = ARGBOrder[rowNdx];
887             else
888                 orderNdx = BGROrder[rowNdx];
889 
890             std::string accessStr;
891             {
892                 // Build string representing the access to the attribute component
893                 std::ostringstream accessStream;
894                 accessStream << attributeVar.str();
895 
896                 if (vertexInputCount == 1)
897                 {
898                     if (componentCount > 1 || m_testMissingComponents)
899                         accessStream << "[" << rowNdx << "]";
900                 }
901                 else
902                 {
903                     accessStream << "[" << columnNdx << "][" << rowNdx << "]";
904                 }
905 
906                 accessStr = accessStream.str();
907             }
908 
909             if (rowNdx < componentCount && !m_testMissingComponents)
910             {
911                 if (isVertexFormatSint(attributeInfo.vkType))
912                 {
913                     if (isVertexFormatPacked(attributeInfo.vkType))
914                     {
915                         const int32_t maxIntValue =
916                             (1 << (getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx) - 1)) - 1;
917                         const int32_t minIntValue = -maxIntValue;
918 
919                         glslCode << indentStr << "if (" << accessStr << " == clamp(-(" << totalComponentCount << " * "
920                                  << indexId << " + " << componentIndex << "), " << minIntValue << ", " << maxIntValue
921                                  << "))\n";
922                     }
923                     else
924                         glslCode << indentStr << "if (" << accessStr << " == -(" << totalComponentCount << " * "
925                                  << indexId << " + " << componentIndex << "))\n";
926                 }
927                 else if (isVertexFormatUint(attributeInfo.vkType))
928                 {
929                     if (isVertexFormatPacked(attributeInfo.vkType))
930                     {
931                         const uint32_t maxUintValue =
932                             (1 << getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx)) - 1;
933 
934                         glslCode << indentStr << "if (" << accessStr << " == clamp(uint(" << totalComponentCount
935                                  << " * " << indexId << " + " << componentIndex << "), 0, " << maxUintValue << "))\n";
936                     }
937                     else
938                         glslCode << indentStr << "if (" << accessStr << " == uint(" << totalComponentCount << " * "
939                                  << indexId << " + " << componentIndex << "))\n";
940                 }
941                 else if (isVertexFormatSfloat(attributeInfo.vkType))
942                 {
943                     const auto &basicType = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType;
944 
945                     if (basicType == VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
946                     {
947                         glslCode << indentStr << "if (abs(" << accessStr << " + double(0.01 * (" << totalComponentCount
948                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double("
949                                  << threshold[rowNdx] << "))\n";
950                     }
951                     else if (basicType == VertexInputTest::GLSL_BASIC_TYPE_FLOAT16)
952                     {
953                         glslCode << indentStr << "if (abs(" << accessStr << " + float16_t(0.01HF * ("
954                                  << totalComponentCount << ".0HF * float16_t(" << indexId << ") + " << componentIndex
955                                  << ".0HF))) < float16_t(" << threshold[rowNdx] << "HF))\n";
956                     }
957                     else
958                     {
959                         glslCode << indentStr << "if (abs(" << accessStr << " + (0.01 * (" << totalComponentCount
960                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < "
961                                  << threshold[rowNdx] << ")\n";
962                     }
963                 }
964                 else if (isVertexFormatSscaled(attributeInfo.vkType))
965                 {
966                     if (isVertexFormatPacked(attributeInfo.vkType))
967                     {
968                         const float maxScaledValue =
969                             float((1 << (getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx) - 1)) - 1);
970                         const float minScaledValue = -maxScaledValue - 1.0f;
971 
972                         glslCode << indentStr << "if (abs(" << accessStr << " + clamp(" << totalComponentCount
973                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0, " << minScaledValue
974                                  << ", " << maxScaledValue << ")) < " << threshold[orderNdx] << ")\n";
975                     }
976                     else
977                         glslCode << indentStr << "if (abs(" << accessStr << " + (" << totalComponentCount
978                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < "
979                                  << threshold[rowNdx] << ")\n";
980                 }
981                 else if (isVertexFormatUscaled(attributeInfo.vkType))
982                 {
983                     if (isVertexFormatPacked(attributeInfo.vkType))
984                     {
985                         const float maxScaledValue =
986                             float((1 << getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx)) - 1);
987 
988                         glslCode << indentStr << "if (abs(" << accessStr << " - clamp(" << totalComponentCount
989                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0, 0, " << maxScaledValue
990                                  << ")) < " << threshold[orderNdx] << ")\n";
991                     }
992                     else
993                         glslCode << indentStr << "if (abs(" << accessStr << " - (" << totalComponentCount
994                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < "
995                                  << threshold[rowNdx] << ")\n";
996                 }
997                 else if (isVertexFormatSnorm(attributeInfo.vkType))
998                 {
999                     const float representableDiff =
1000                         isVertexFormatPacked(attributeInfo.vkType) ?
1001                             getRepresentableDifferenceSnormPacked(attributeInfo.vkType, orderNdx) :
1002                             getRepresentableDifferenceSnorm(attributeInfo.vkType);
1003 
1004                     if (isVertexFormatPacked(attributeInfo.vkType))
1005                         glslCode << indentStr << "if (abs(" << accessStr << " - clamp((-1.0 + " << representableDiff
1006                                  << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + "
1007                                  << componentIndex << ".0)), -1.0, 1.0)) < " << threshold[orderNdx] << ")\n";
1008                     else
1009                         glslCode << indentStr << "if (abs(" << accessStr << " - (-1.0 + " << representableDiff << " * ("
1010                                  << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex
1011                                  << ".0))) < " << threshold[rowNdx] << ")\n";
1012                 }
1013                 else if (isVertexFormatUnorm(attributeInfo.vkType) || isVertexFormatSRGB(attributeInfo.vkType))
1014                 {
1015                     const float representableDiff =
1016                         isVertexFormatPacked(attributeInfo.vkType) ?
1017                             getRepresentableDifferenceUnormPacked(attributeInfo.vkType, orderNdx) :
1018                             getRepresentableDifferenceUnorm(attributeInfo.vkType);
1019 
1020                     if (isVertexFormatPacked(attributeInfo.vkType))
1021                         glslCode << indentStr << "if (abs(" << accessStr << " - "
1022                                  << "clamp((" << representableDiff << " * (" << totalComponentCount << ".0 * float("
1023                                  << indexId << ") + " << componentIndex << ".0)), 0.0, 1.0)) < " << threshold[orderNdx]
1024                                  << ")\n";
1025                     else
1026                         glslCode << indentStr << "if (abs(" << accessStr << " - "
1027                                  << "(" << representableDiff << " * (" << totalComponentCount << ".0 * float("
1028                                  << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
1029                 }
1030                 else if (isVertexFormatUfloat(attributeInfo.vkType))
1031                 {
1032                     const auto &basicType = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType;
1033 
1034                     if (basicType == VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
1035                     {
1036                         glslCode << indentStr << "if (abs(" << accessStr << " - double(0.01 * (" << totalComponentCount
1037                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double("
1038                                  << threshold[rowNdx] << "))\n";
1039                     }
1040                     else if (basicType == VertexInputTest::GLSL_BASIC_TYPE_FLOAT16)
1041                     {
1042                         glslCode << indentStr << "if (abs(" << accessStr << " - float16_t(0.01HF * ("
1043                                  << totalComponentCount << ".0HF * float16_t(" << indexId << ") + " << componentIndex
1044                                  << ".0HF))) < float16_t(" << threshold[rowNdx] << "HF))\n";
1045                     }
1046                     else
1047                     {
1048                         glslCode << indentStr << "if (abs(" << accessStr << " - (0.01 * (" << totalComponentCount
1049                                  << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < ("
1050                                  << threshold[rowNdx] << "))\n";
1051                     }
1052                 }
1053                 else
1054                 {
1055                     DE_ASSERT(false);
1056                 }
1057 
1058                 glslCode << indentStr << "\tokCount++;\n\n";
1059 
1060                 componentIndex++;
1061             }
1062             else if (rowNdx >= componentCount && m_testMissingComponents)
1063             {
1064                 const auto expectedValue = ((rowNdx == (kMaxComponents - 1)) ?
1065                                                 1u :
1066                                                 0u); // Color components are expanded with zeros and alpha with one.
1067                 const auto &basicType    = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType;
1068                 std::string glslType;
1069 
1070                 switch (basicType)
1071                 {
1072                 case GLSL_BASIC_TYPE_INT:
1073                     glslType = "int";
1074                     break;
1075                 case GLSL_BASIC_TYPE_UINT:
1076                     glslType = "uint";
1077                     break;
1078                 case GLSL_BASIC_TYPE_FLOAT:
1079                     glslType = "float";
1080                     break;
1081                 case GLSL_BASIC_TYPE_DOUBLE:
1082                     glslType = "double";
1083                     break;
1084                 case GLSL_BASIC_TYPE_FLOAT16:
1085                     glslType = "float16_t";
1086                     break;
1087                 default:
1088                     DE_ASSERT(false);
1089                     break;
1090                 }
1091 
1092                 glslCode << indentStr << "if (" << accessStr << " == " << glslType << "(" << expectedValue << "))\n";
1093                 glslCode << indentStr << "\tokCount++;\n\n";
1094             }
1095         }
1096     }
1097     return glslCode.str();
1098 }
1099 
getFormatThreshold(VkFormat format)1100 tcu::Vec4 VertexInputTest::getFormatThreshold(VkFormat format)
1101 {
1102     using tcu::Vec4;
1103 
1104     switch (format)
1105     {
1106     case VK_FORMAT_R32_SFLOAT:
1107     case VK_FORMAT_R32G32_SFLOAT:
1108     case VK_FORMAT_R32G32B32_SFLOAT:
1109     case VK_FORMAT_R32G32B32A32_SFLOAT:
1110     case VK_FORMAT_R64_SFLOAT:
1111     case VK_FORMAT_R64G64_SFLOAT:
1112     case VK_FORMAT_R64G64B64_SFLOAT:
1113     case VK_FORMAT_R64G64B64A64_SFLOAT:
1114         return Vec4(0.00001f);
1115 
1116     default:
1117         break;
1118     }
1119 
1120     if (isVertexFormatSnorm(format))
1121     {
1122         return (isVertexFormatPacked(format) ? Vec4(1.5f * getRepresentableDifferenceSnormPacked(format, 0),
1123                                                     1.5f * getRepresentableDifferenceSnormPacked(format, 1),
1124                                                     1.5f * getRepresentableDifferenceSnormPacked(format, 2),
1125                                                     1.5f * getRepresentableDifferenceSnormPacked(format, 3)) :
1126                                                Vec4(1.5f * getRepresentableDifferenceSnorm(format)));
1127     }
1128     else if (isVertexFormatUnorm(format))
1129     {
1130         return (isVertexFormatPacked(format) ? Vec4(1.5f * getRepresentableDifferenceUnormPacked(format, 0),
1131                                                     1.5f * getRepresentableDifferenceUnormPacked(format, 1),
1132                                                     1.5f * getRepresentableDifferenceUnormPacked(format, 2),
1133                                                     1.5f * getRepresentableDifferenceUnormPacked(format, 3)) :
1134                                                Vec4(1.5f * getRepresentableDifferenceUnorm(format)));
1135     }
1136     else if (isVertexFormatUfloat(format))
1137     {
1138         return Vec4(0.008f);
1139     }
1140 
1141     return Vec4(0.001f);
1142 }
1143 
VertexInputInstance(Context & context,const PipelineConstructionType pipelineConstructionType,const AttributeDescriptionList & attributeDescriptions,const std::vector<VkVertexInputBindingDescription> & bindingDescriptions,const std::vector<VkDeviceSize> & bindingOffsets)1144 VertexInputInstance::VertexInputInstance(Context &context, const PipelineConstructionType pipelineConstructionType,
1145                                          const AttributeDescriptionList &attributeDescriptions,
1146                                          const std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
1147                                          const std::vector<VkDeviceSize> &bindingOffsets)
1148     : vkt::TestInstance(context)
1149     , m_renderSize(16, 16)
1150     , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM)
1151     , m_graphicsPipeline(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(),
1152                          context.getDevice(), context.getDeviceExtensions(), pipelineConstructionType)
1153 {
1154     DE_ASSERT(bindingDescriptions.size() == bindingOffsets.size());
1155 
1156     const DeviceInterface &vk       = context.getDeviceInterface();
1157     const VkDevice vkDevice         = context.getDevice();
1158     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1159     SimpleAllocator memAlloc(
1160         vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
1161     const VkComponentMapping componentMappingRGBA = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1162                                                      VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
1163 
1164     // Check upfront for unsupported features
1165     for (size_t attributeNdx = 0; attributeNdx < attributeDescriptions.size(); attributeNdx++)
1166     {
1167         const VkVertexInputAttributeDescription &attributeDescription =
1168             attributeDescriptions[attributeNdx].vkDescription;
1169         if (!isSupportedVertexFormat(context, attributeDescription.format))
1170         {
1171             throw tcu::NotSupportedError(std::string("Unsupported format for vertex input: ") +
1172                                          getFormatName(attributeDescription.format));
1173         }
1174     }
1175 
1176     // Create color image
1177     {
1178         const VkImageCreateInfo colorImageParams = {
1179             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                   // VkStructureType sType;
1180             DE_NULL,                                                               // const void* pNext;
1181             0u,                                                                    // VkImageCreateFlags flags;
1182             VK_IMAGE_TYPE_2D,                                                      // VkImageType imageType;
1183             m_colorFormat,                                                         // VkFormat format;
1184             {m_renderSize.x(), m_renderSize.y(), 1u},                              // VkExtent3D extent;
1185             1u,                                                                    // uint32_t mipLevels;
1186             1u,                                                                    // uint32_t arrayLayers;
1187             VK_SAMPLE_COUNT_1_BIT,                                                 // VkSampleCountFlagBits samples;
1188             VK_IMAGE_TILING_OPTIMAL,                                               // VkImageTiling tiling;
1189             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
1190             VK_SHARING_MODE_EXCLUSIVE,                                             // VkSharingMode sharingMode;
1191             1u,                                                                    // uint32_t queueFamilyIndexCount;
1192             &queueFamilyIndex,         // const uint32_t* pQueueFamilyIndices;
1193             VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1194         };
1195 
1196         m_colorImage = createImage(vk, vkDevice, &colorImageParams);
1197 
1198         // Allocate and bind color image memory
1199         m_colorImageAlloc =
1200             memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
1201         VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(),
1202                                     m_colorImageAlloc->getOffset()));
1203     }
1204 
1205     // Create color attachment view
1206     {
1207         const VkImageViewCreateInfo colorAttachmentViewParams = {
1208             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,    // VkStructureType sType;
1209             DE_NULL,                                     // const void* pNext;
1210             0u,                                          // VkImageViewCreateFlags flags;
1211             *m_colorImage,                               // VkImage image;
1212             VK_IMAGE_VIEW_TYPE_2D,                       // VkImageViewType viewType;
1213             m_colorFormat,                               // VkFormat format;
1214             componentMappingRGBA,                        // VkComponentMapping components;
1215             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
1216         };
1217 
1218         m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
1219     }
1220 
1221     // Create render pass
1222     m_renderPass = RenderPassWrapper(pipelineConstructionType, vk, vkDevice, m_colorFormat);
1223 
1224     // Create framebuffer
1225     {
1226         const VkFramebufferCreateInfo framebufferParams = {
1227             VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1228             DE_NULL,                                   // const void* pNext;
1229             0u,                                        // VkFramebufferCreateFlags flags;
1230             *m_renderPass,                             // VkRenderPass renderPass;
1231             1u,                                        // uint32_t attachmentCount;
1232             &m_colorAttachmentView.get(),              // const VkImageView* pAttachments;
1233             (uint32_t)m_renderSize.x(),                // uint32_t width;
1234             (uint32_t)m_renderSize.y(),                // uint32_t height;
1235             1u                                         // uint32_t layers;
1236         };
1237 
1238         m_renderPass.createFramebuffer(vk, vkDevice, &framebufferParams, *m_colorImage);
1239     }
1240 
1241     // Create pipeline layout
1242     {
1243         const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
1244             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1245             DE_NULL,                                       // const void* pNext;
1246             0u,                                            // VkPipelineLayoutCreateFlags flags;
1247             0u,                                            // uint32_t setLayoutCount;
1248             DE_NULL,                                       // const VkDescriptorSetLayout* pSetLayouts;
1249             0u,                                            // uint32_t pushConstantRangeCount;
1250             DE_NULL                                        // const VkPushConstantRange* pPushConstantRanges;
1251         };
1252 
1253         m_pipelineLayout = PipelineLayoutWrapper(pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
1254     }
1255 
1256     m_vertexShaderModule   = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_vert"), 0);
1257     m_fragmentShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_frag"), 0);
1258 
1259     // Create specialization constant
1260     uint32_t specializationData = static_cast<uint32_t>(attributeDescriptions.size());
1261 
1262     const VkSpecializationMapEntry specializationMapEntry = {
1263         0,                          // uint32_t                            constantID
1264         0,                          // uint32_t                            offset
1265         sizeof(specializationData), // uint32_t                            size
1266     };
1267     const VkSpecializationInfo specializationInfo = {
1268         1,                          // uint32_t                            mapEntryCount
1269         &specializationMapEntry,    // const void*                        pMapEntries
1270         sizeof(specializationData), // size_t                            dataSize
1271         &specializationData         // const void*                        pData
1272     };
1273 
1274     // Create pipeline
1275     {
1276         // Create vertex attribute array and check if their VK formats are supported
1277         std::vector<VkVertexInputAttributeDescription> vkAttributeDescriptions;
1278         for (size_t attributeNdx = 0; attributeNdx < attributeDescriptions.size(); attributeNdx++)
1279         {
1280             const VkVertexInputAttributeDescription &attributeDescription =
1281                 attributeDescriptions[attributeNdx].vkDescription;
1282             vkAttributeDescriptions.push_back(attributeDescription);
1283         }
1284 
1285         const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
1286             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1287             DE_NULL,                                                   // const void* pNext;
1288             0u,                                                        // VkPipelineVertexInputStateCreateFlags flags;
1289             (uint32_t)bindingDescriptions.size(),                      // uint32_t vertexBindingDescriptionCount;
1290             bindingDescriptions.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1291             (uint32_t)vkAttributeDescriptions.size(), // uint32_t vertexAttributeDescriptionCount;
1292             vkAttributeDescriptions.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1293         };
1294 
1295         const std::vector<VkViewport> viewport{makeViewport(m_renderSize)};
1296         const std::vector<VkRect2D> scissor{makeRect2D(m_renderSize)};
1297 
1298         const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1299             false,                                                // VkBool32 blendEnable;
1300             VK_BLEND_FACTOR_ONE,                                  // VkBlendFactor srcColorBlendFactor;
1301             VK_BLEND_FACTOR_ZERO,                                 // VkBlendFactor dstColorBlendFactor;
1302             VK_BLEND_OP_ADD,                                      // VkBlendOp colorBlendOp;
1303             VK_BLEND_FACTOR_ONE,                                  // VkBlendFactor srcAlphaBlendFactor;
1304             VK_BLEND_FACTOR_ZERO,                                 // VkBlendFactor dstAlphaBlendFactor;
1305             VK_BLEND_OP_ADD,                                      // VkBlendOp alphaBlendOp;
1306             VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
1307                 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
1308 
1309         const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = {
1310             VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1311             DE_NULL,                                                  // const void* pNext;
1312             0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
1313             false,                                                    // VkBool32 logicOpEnable;
1314             VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
1315             1u,                                                       // uint32_t attachmentCount;
1316             &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
1317             {0.0f, 0.0f, 0.0f, 0.0f},   // float blendConstants[4];
1318         };
1319 
1320         m_graphicsPipeline.setDefaultRasterizationState()
1321             .setDefaultDepthStencilState()
1322             .setDefaultMultisampleState()
1323             .setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
1324             .setupVertexInputState(&vertexInputStateParams)
1325             .setupPreRasterizationShaderState(viewport, scissor, m_pipelineLayout, *m_renderPass, 0u,
1326                                               m_vertexShaderModule, DE_NULL, ShaderWrapper(), ShaderWrapper(),
1327                                               ShaderWrapper(), &specializationInfo)
1328             .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, m_fragmentShaderModule)
1329             .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
1330             .setMonolithicPipelineLayout(m_pipelineLayout)
1331             .buildPipeline();
1332     }
1333 
1334     // Create vertex buffer
1335     {
1336         // calculate buffer size
1337         // 32 is maximal attribute size (4*sizeof(double)),
1338         // 8 maximal vertex count used in writeVertexInputData
1339         VkDeviceSize bufferSize = 32 * 8 * attributeDescriptions.size();
1340 
1341         const VkBufferCreateInfo vertexBufferParams = {
1342             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1343             DE_NULL,                              // const void* pNext;
1344             0u,                                   // VkBufferCreateFlags flags;
1345             bufferSize,                           // VkDeviceSize size;
1346             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
1347             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1348             1u,                                   // uint32_t queueFamilyIndexCount;
1349             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
1350         };
1351 
1352         // Upload data for each vertex input binding
1353         for (uint32_t bindingNdx = 0; bindingNdx < bindingDescriptions.size(); bindingNdx++)
1354         {
1355             Move<VkBuffer> vertexBuffer               = createBuffer(vk, vkDevice, &vertexBufferParams);
1356             de::MovePtr<Allocation> vertexBufferAlloc = memAlloc.allocate(
1357                 getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
1358 
1359             VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferAlloc->getMemory(),
1360                                          vertexBufferAlloc->getOffset()));
1361 
1362             writeVertexInputData((uint8_t *)vertexBufferAlloc->getHostPtr(), bindingDescriptions[bindingNdx],
1363                                  bindingOffsets[bindingNdx], attributeDescriptions);
1364             flushAlloc(vk, vkDevice, *vertexBufferAlloc);
1365 
1366             m_vertexBuffers.push_back(vertexBuffer.disown());
1367             m_vertexBufferAllocs.push_back(vertexBufferAlloc.release());
1368         }
1369     }
1370 
1371     // Create command pool
1372     m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1373 
1374     // Create command buffer
1375     {
1376         const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
1377 
1378         const VkImageMemoryBarrier attachmentLayoutBarrier = {
1379             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,      // VkStructureType sType;
1380             DE_NULL,                                     // const void* pNext;
1381             0u,                                          // VkAccessFlags srcAccessMask;
1382             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,        // VkAccessFlags dstAccessMask;
1383             VK_IMAGE_LAYOUT_UNDEFINED,                   // VkImageLayout oldLayout;
1384             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,    // VkImageLayout newLayout;
1385             VK_QUEUE_FAMILY_IGNORED,                     // uint32_t srcQueueFamilyIndex;
1386             VK_QUEUE_FAMILY_IGNORED,                     // uint32_t dstQueueFamilyIndex;
1387             *m_colorImage,                               // VkImage image;
1388             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
1389         };
1390 
1391         m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1392 
1393         beginCommandBuffer(vk, *m_cmdBuffer, 0u);
1394 
1395         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1396                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u,
1397                               DE_NULL, 1u, &attachmentLayoutBarrier);
1398 
1399         m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()),
1400                            attachmentClearValue);
1401 
1402         m_graphicsPipeline.bind(*m_cmdBuffer);
1403 
1404         std::vector<VkBuffer> vertexBuffers;
1405         for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
1406             vertexBuffers.push_back(m_vertexBuffers[bufferNdx]);
1407 
1408         if (vertexBuffers.size() <= 1)
1409         {
1410             // One vertex buffer
1411             vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, (uint32_t)vertexBuffers.size(), vertexBuffers.data(),
1412                                     bindingOffsets.data());
1413         }
1414         else
1415         {
1416             // Smoke-test vkCmdBindVertexBuffers(..., startBinding, ... )
1417 
1418             const uint32_t firstHalfLength  = (uint32_t)vertexBuffers.size() / 2;
1419             const uint32_t secondHalfLength = firstHalfLength + (uint32_t)(vertexBuffers.size() % 2);
1420 
1421             // Bind first half of vertex buffers
1422             vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, firstHalfLength, vertexBuffers.data(), bindingOffsets.data());
1423 
1424             // Bind second half of vertex buffers
1425             vk.cmdBindVertexBuffers(*m_cmdBuffer, firstHalfLength, secondHalfLength,
1426                                     vertexBuffers.data() + firstHalfLength, bindingOffsets.data() + firstHalfLength);
1427         }
1428 
1429         vk.cmdDraw(*m_cmdBuffer, 4, 2, 0, 0);
1430 
1431         m_renderPass.end(vk, *m_cmdBuffer);
1432         endCommandBuffer(vk, *m_cmdBuffer);
1433     }
1434 }
1435 
~VertexInputInstance(void)1436 VertexInputInstance::~VertexInputInstance(void)
1437 {
1438     const DeviceInterface &vk = m_context.getDeviceInterface();
1439     const VkDevice vkDevice   = m_context.getDevice();
1440 
1441     for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
1442         vk.destroyBuffer(vkDevice, m_vertexBuffers[bufferNdx], DE_NULL);
1443 
1444     for (size_t allocNdx = 0; allocNdx < m_vertexBufferAllocs.size(); allocNdx++)
1445         delete m_vertexBufferAllocs[allocNdx];
1446 }
1447 
writeVertexInputData(uint8_t * destPtr,const VkVertexInputBindingDescription & bindingDescription,const VkDeviceSize bindingOffset,const AttributeDescriptionList & attributes)1448 void VertexInputInstance::writeVertexInputData(uint8_t *destPtr,
1449                                                const VkVertexInputBindingDescription &bindingDescription,
1450                                                const VkDeviceSize bindingOffset,
1451                                                const AttributeDescriptionList &attributes)
1452 {
1453     const uint32_t vertexCount = (bindingDescription.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? (4 * 2) : 2;
1454 
1455     uint8_t *destOffsetPtr = ((uint8_t *)destPtr) + bindingOffset;
1456     for (uint32_t vertexNdx = 0; vertexNdx < vertexCount; vertexNdx++)
1457     {
1458         for (size_t attributeNdx = 0; attributeNdx < attributes.size(); attributeNdx++)
1459         {
1460             const VertexInputAttributeDescription &attribDesc = attributes[attributeNdx];
1461 
1462             // Only write vertex input data to bindings referenced by attribute descriptions
1463             if (attribDesc.vkDescription.binding == bindingDescription.binding)
1464             {
1465                 writeVertexInputValue(destOffsetPtr + attribDesc.vkDescription.offset, attribDesc, vertexNdx);
1466             }
1467         }
1468         destOffsetPtr += bindingDescription.stride;
1469     }
1470 }
1471 
writeVertexInputValueSint(uint8_t * destPtr,VkFormat format,int componentNdx,int32_t value)1472 void writeVertexInputValueSint(uint8_t *destPtr, VkFormat format, int componentNdx, int32_t value)
1473 {
1474     const uint32_t componentSize = getVertexFormatComponentSize(format);
1475     uint8_t *destFormatPtr       = ((uint8_t *)destPtr) + componentSize * componentNdx;
1476 
1477     switch (componentSize)
1478     {
1479     case 1:
1480         *((int8_t *)destFormatPtr) = (int8_t)value;
1481         break;
1482 
1483     case 2:
1484         *((int16_t *)destFormatPtr) = (int16_t)value;
1485         break;
1486 
1487     case 4:
1488         *((int32_t *)destFormatPtr) = (int32_t)value;
1489         break;
1490 
1491     default:
1492         DE_ASSERT(false);
1493     }
1494 }
1495 
writeVertexInputValueIntPacked(uint8_t * destPtr,uint32_t & packedFormat,uint32_t & componentOffset,VkFormat format,uint32_t componentNdx,uint32_t value)1496 void writeVertexInputValueIntPacked(uint8_t *destPtr, uint32_t &packedFormat, uint32_t &componentOffset,
1497                                     VkFormat format, uint32_t componentNdx, uint32_t value)
1498 {
1499     const uint32_t componentWidth = getPackedVertexFormatComponentWidth(format, componentNdx);
1500     const uint32_t componentCount = getVertexFormatComponentCount(format);
1501     const uint32_t usedBits       = ~(uint32_t)0 >> ((getVertexFormatSize(format) * 8) - componentWidth);
1502 
1503     componentOffset -= componentWidth;
1504     packedFormat |= (((uint32_t)value & usedBits) << componentOffset);
1505 
1506     if (componentNdx == componentCount - 1)
1507         *((uint32_t *)destPtr) = (uint32_t)packedFormat;
1508 }
1509 
writeVertexInputValueUint(uint8_t * destPtr,VkFormat format,int componentNdx,uint32_t value)1510 void writeVertexInputValueUint(uint8_t *destPtr, VkFormat format, int componentNdx, uint32_t value)
1511 {
1512     const uint32_t componentSize = getVertexFormatComponentSize(format);
1513     uint8_t *destFormatPtr       = ((uint8_t *)destPtr) + componentSize * componentNdx;
1514 
1515     switch (componentSize)
1516     {
1517     case 1:
1518         *((uint8_t *)destFormatPtr) = (uint8_t)value;
1519         break;
1520 
1521     case 2:
1522         *((uint16_t *)destFormatPtr) = (uint16_t)value;
1523         break;
1524 
1525     case 4:
1526         *((uint32_t *)destFormatPtr) = (uint32_t)value;
1527         break;
1528 
1529     default:
1530         DE_ASSERT(false);
1531     }
1532 }
1533 
writeVertexInputValueSfloat(uint8_t * destPtr,VkFormat format,int componentNdx,float value)1534 void writeVertexInputValueSfloat(uint8_t *destPtr, VkFormat format, int componentNdx, float value)
1535 {
1536     const uint32_t componentSize = getVertexFormatComponentSize(format);
1537     uint8_t *destFormatPtr       = ((uint8_t *)destPtr) + componentSize * componentNdx;
1538 
1539     switch (componentSize)
1540     {
1541     case 2:
1542     {
1543         tcu::Float16 f16(value);
1544         deMemcpy(destFormatPtr, &f16, sizeof(f16));
1545         break;
1546     }
1547 
1548     case 4:
1549         deMemcpy(destFormatPtr, &value, sizeof(value));
1550         break;
1551 
1552     default:
1553         DE_ASSERT(false);
1554     }
1555 }
1556 
writeVertexInputValueUfloat(uint8_t * destPtr,uint32_t & packedFormat,uint32_t & componentOffset,VkFormat format,uint32_t componentNdx,float value)1557 void writeVertexInputValueUfloat(uint8_t *destPtr, uint32_t &packedFormat, uint32_t &componentOffset, VkFormat format,
1558                                  uint32_t componentNdx, float value)
1559 {
1560     tcu::Float16 f16(value);
1561 
1562     const uint32_t componentWidth = getPackedVertexFormatComponentWidth(format, componentNdx);
1563     const uint32_t componentCount = getVertexFormatComponentCount(format);
1564     const uint32_t usedBits       = ~(uint32_t)0 >> ((getVertexFormatSize(format) * 8) - componentWidth);
1565     // The ufloat 10 or 11 has no sign bit, but the same exponent bits than float16.
1566     // The sign bit will be removed by the mask. Therefore we pick one more mantissa bit.
1567     uint32_t valueUFloat = f16.bits() >> (16 - componentWidth - 1);
1568 
1569     // TODO: VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 not supported.
1570     DE_ASSERT(format == VK_FORMAT_B10G11R11_UFLOAT_PACK32);
1571 
1572     componentOffset -= componentWidth;
1573     packedFormat |= (valueUFloat & usedBits) << componentOffset;
1574 
1575     if (componentNdx == componentCount - 1)
1576         *((uint32_t *)destPtr) = (uint32_t)packedFormat;
1577 }
1578 
writeVertexInputValue(uint8_t * destPtr,const VertexInputAttributeDescription & attribute,int indexId)1579 void VertexInputInstance::writeVertexInputValue(uint8_t *destPtr, const VertexInputAttributeDescription &attribute,
1580                                                 int indexId)
1581 {
1582     const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputCount;
1583     const int componentCount   = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputComponentCount;
1584     const uint32_t totalComponentCount = componentCount * vertexInputCount;
1585     const uint32_t vertexInputIndex    = indexId * totalComponentCount + attribute.vertexInputIndex * componentCount;
1586     const bool hasBGROrder             = isVertexFormatComponentOrderBGR(attribute.vkDescription.format);
1587     const bool hasABGROrder            = isVertexFormatComponentOrderABGR(attribute.vkDescription.format);
1588     const bool hasARGBOrder            = isVertexFormatComponentOrderARGB(attribute.vkDescription.format);
1589     uint32_t componentOffset           = getVertexFormatSize(attribute.vkDescription.format) * 8;
1590     uint32_t packedFormat32            = 0;
1591     uint32_t swizzledNdx;
1592 
1593     const uint32_t BGRSwizzle[]  = {2, 1, 0, 3};
1594     const uint32_t ABGRSwizzle[] = {3, 2, 1, 0};
1595     const uint32_t ARGBSwizzle[] = {3, 0, 1, 2};
1596 
1597     for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1598     {
1599         if (hasABGROrder)
1600             swizzledNdx = ABGRSwizzle[componentNdx];
1601         else if (hasARGBOrder)
1602             swizzledNdx = ARGBSwizzle[componentNdx];
1603         else if (hasBGROrder)
1604             swizzledNdx = BGRSwizzle[componentNdx];
1605         else
1606             swizzledNdx = componentNdx;
1607 
1608         const int32_t maxIntValue =
1609             isVertexFormatPacked(attribute.vkDescription.format) ?
1610                 (1 << (getPackedVertexFormatComponentWidth(attribute.vkDescription.format, componentNdx) - 1)) - 1 :
1611                 (1 << (getVertexFormatComponentSize(attribute.vkDescription.format) * 8 - 1)) - 1;
1612         const uint32_t maxUintValue =
1613             isVertexFormatPacked(attribute.vkDescription.format) ?
1614                 ((1 << getPackedVertexFormatComponentWidth(attribute.vkDescription.format, componentNdx)) - 1) :
1615                 (1 << (getVertexFormatComponentSize(attribute.vkDescription.format) * 8)) - 1;
1616         const int32_t minIntValue   = -maxIntValue;
1617         const uint32_t minUintValue = 0;
1618 
1619         switch (attribute.glslType)
1620         {
1621         case VertexInputTest::GLSL_TYPE_INT:
1622         case VertexInputTest::GLSL_TYPE_IVEC2:
1623         case VertexInputTest::GLSL_TYPE_IVEC3:
1624         case VertexInputTest::GLSL_TYPE_IVEC4:
1625         {
1626             if (isVertexFormatPacked(attribute.vkDescription.format))
1627                 writeVertexInputValueIntPacked(
1628                     destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1629                     deClamp32(-(int32_t)(vertexInputIndex + swizzledNdx), minIntValue, maxIntValue));
1630             else
1631                 writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx,
1632                                           -(int32_t)(vertexInputIndex + swizzledNdx));
1633 
1634             break;
1635         }
1636         case VertexInputTest::GLSL_TYPE_UINT:
1637         case VertexInputTest::GLSL_TYPE_UVEC2:
1638         case VertexInputTest::GLSL_TYPE_UVEC3:
1639         case VertexInputTest::GLSL_TYPE_UVEC4:
1640         {
1641             if (isVertexFormatPacked(attribute.vkDescription.format))
1642                 writeVertexInputValueIntPacked(destPtr, packedFormat32, componentOffset, attribute.vkDescription.format,
1643                                                componentNdx,
1644                                                deClamp32(vertexInputIndex + swizzledNdx, minUintValue, maxUintValue));
1645             else
1646                 writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx,
1647                                           vertexInputIndex + swizzledNdx);
1648 
1649             break;
1650         }
1651         case VertexInputTest::GLSL_TYPE_FLOAT:
1652         case VertexInputTest::GLSL_TYPE_VEC2:
1653         case VertexInputTest::GLSL_TYPE_VEC3:
1654         case VertexInputTest::GLSL_TYPE_VEC4:
1655         case VertexInputTest::GLSL_TYPE_MAT2:
1656         case VertexInputTest::GLSL_TYPE_MAT3:
1657         case VertexInputTest::GLSL_TYPE_MAT4:
1658         case VertexInputTest::GLSL_TYPE_F16:
1659         case VertexInputTest::GLSL_TYPE_F16VEC2:
1660         case VertexInputTest::GLSL_TYPE_F16VEC3:
1661         case VertexInputTest::GLSL_TYPE_F16VEC4:
1662         {
1663             if (isVertexFormatSfloat(attribute.vkDescription.format))
1664             {
1665                 writeVertexInputValueSfloat(destPtr, attribute.vkDescription.format, componentNdx,
1666                                             -(0.01f * (float)(vertexInputIndex + swizzledNdx)));
1667             }
1668             else if (isVertexFormatUfloat(attribute.vkDescription.format))
1669             {
1670                 writeVertexInputValueUfloat(destPtr, packedFormat32, componentOffset, attribute.vkDescription.format,
1671                                             componentNdx, 0.01f * (float)(vertexInputIndex + swizzledNdx));
1672             }
1673             else if (isVertexFormatSscaled(attribute.vkDescription.format))
1674             {
1675                 if (isVertexFormatPacked(attribute.vkDescription.format))
1676                     writeVertexInputValueIntPacked(
1677                         destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1678                         deClamp32(-(int32_t)(vertexInputIndex + swizzledNdx), minIntValue, maxIntValue));
1679                 else
1680                     writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx,
1681                                               -(int32_t)(vertexInputIndex + swizzledNdx));
1682             }
1683             else if (isVertexFormatUscaled(attribute.vkDescription.format) ||
1684                      isVertexFormatUnorm(attribute.vkDescription.format) ||
1685                      isVertexFormatSRGB(attribute.vkDescription.format))
1686             {
1687                 if (isVertexFormatPacked(attribute.vkDescription.format))
1688                     writeVertexInputValueIntPacked(
1689                         destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1690                         deClamp32(vertexInputIndex + swizzledNdx, minUintValue, maxUintValue));
1691                 else
1692                     writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx,
1693                                               vertexInputIndex + swizzledNdx);
1694             }
1695             else if (isVertexFormatSnorm(attribute.vkDescription.format))
1696             {
1697                 if (isVertexFormatPacked(attribute.vkDescription.format))
1698                     writeVertexInputValueIntPacked(
1699                         destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1700                         deClamp32(minIntValue + (vertexInputIndex + swizzledNdx), minIntValue, maxIntValue));
1701                 else
1702                     writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx,
1703                                               minIntValue + (vertexInputIndex + swizzledNdx));
1704             }
1705             else
1706                 DE_ASSERT(false);
1707             break;
1708         }
1709         case VertexInputTest::GLSL_TYPE_DOUBLE:
1710         case VertexInputTest::GLSL_TYPE_DVEC2:
1711         case VertexInputTest::GLSL_TYPE_DVEC3:
1712         case VertexInputTest::GLSL_TYPE_DVEC4:
1713         case VertexInputTest::GLSL_TYPE_DMAT2:
1714         case VertexInputTest::GLSL_TYPE_DMAT3:
1715         case VertexInputTest::GLSL_TYPE_DMAT4:
1716             *(reinterpret_cast<double *>(destPtr) + componentNdx) = -0.01 * (vertexInputIndex + swizzledNdx);
1717 
1718             break;
1719 
1720         default:
1721             DE_ASSERT(false);
1722         }
1723     }
1724 }
1725 
iterate(void)1726 tcu::TestStatus VertexInputInstance::iterate(void)
1727 {
1728     const DeviceInterface &vk = m_context.getDeviceInterface();
1729     const VkDevice vkDevice   = m_context.getDevice();
1730     const VkQueue queue       = m_context.getUniversalQueue();
1731 
1732     submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
1733 
1734     return verifyImage();
1735 }
1736 
isCompatibleType(VkFormat format,GlslType glslType)1737 bool VertexInputTest::isCompatibleType(VkFormat format, GlslType glslType)
1738 {
1739     const GlslTypeDescription glslTypeDesc = s_glslTypeDescriptions[glslType];
1740 
1741     if ((uint32_t)s_glslTypeDescriptions[glslType].vertexInputComponentCount == getVertexFormatComponentCount(format))
1742     {
1743         switch (glslTypeDesc.basicType)
1744         {
1745         case GLSL_BASIC_TYPE_INT:
1746             return isVertexFormatSint(format);
1747 
1748         case GLSL_BASIC_TYPE_UINT:
1749             return isVertexFormatUint(format);
1750 
1751         case GLSL_BASIC_TYPE_FLOAT:
1752             return (isVertexFormatPacked(format) ? (getVertexFormatSize(format) <= 4) :
1753                                                    getVertexFormatComponentSize(format) <= 4) &&
1754                    (isVertexFormatSfloat(format) || isVertexFormatSnorm(format) || isVertexFormatUnorm(format) ||
1755                     isVertexFormatSscaled(format) || isVertexFormatUscaled(format) || isVertexFormatSRGB(format) ||
1756                     isVertexFormatUfloat(format));
1757 
1758         case GLSL_BASIC_TYPE_DOUBLE:
1759             return isVertexFormatSfloat(format) && getVertexFormatComponentSize(format) == 8;
1760 
1761         case GLSL_BASIC_TYPE_FLOAT16:
1762             return ((isVertexFormatSfloat(format) /* || isVertexFormatSnorm(format) || isVertexFormatUnorm(format)*/) &&
1763                     getVertexFormatComponentSize(format) == 2);
1764 
1765         default:
1766             DE_ASSERT(false);
1767             return false;
1768         }
1769     }
1770     else
1771         return false;
1772 }
1773 
verifyImage(void)1774 tcu::TestStatus VertexInputInstance::verifyImage(void)
1775 {
1776     bool compareOk                          = false;
1777     const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
1778     tcu::TextureLevel reference(tcuColorFormat, m_renderSize.x(), m_renderSize.y());
1779     const tcu::PixelBufferAccess refRedSubregion(tcu::getSubregion(
1780         reference.getAccess(), deRoundFloatToInt32((float)m_renderSize.x() * 0.0f),
1781         deRoundFloatToInt32((float)m_renderSize.y() * 0.0f), deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
1782         deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
1783     const tcu::PixelBufferAccess refBlueSubregion(tcu::getSubregion(
1784         reference.getAccess(), deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
1785         deRoundFloatToInt32((float)m_renderSize.y() * 0.0f), deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
1786         deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
1787 
1788     // Create reference image
1789     tcu::clear(reference.getAccess(), defaultClearColor(tcuColorFormat));
1790     tcu::clear(refRedSubregion, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
1791     tcu::clear(refBlueSubregion, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
1792 
1793     // Compare result with reference image
1794     {
1795         const DeviceInterface &vk       = m_context.getDeviceInterface();
1796         const VkDevice vkDevice         = m_context.getDevice();
1797         const VkQueue queue             = m_context.getUniversalQueue();
1798         const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1799         SimpleAllocator allocator(
1800             vk, vkDevice,
1801             getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
1802         de::MovePtr<tcu::TextureLevel> result = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator,
1803                                                                     *m_colorImage, m_colorFormat, m_renderSize);
1804 
1805         compareOk = tcu::intThresholdPositionDeviationCompare(
1806             m_context.getTestContext().getLog(), "IntImageCompare", "Image comparison", reference.getAccess(),
1807             result->getAccess(), tcu::UVec4(2, 2, 2, 2), tcu::IVec3(1, 1, 0), true, tcu::COMPARE_LOG_RESULT);
1808     }
1809 
1810     if (compareOk)
1811         return tcu::TestStatus::pass("Result image matches reference");
1812     else
1813         return tcu::TestStatus::fail("Image mismatch");
1814 }
1815 
getAttributeInfoCaseName(const VertexInputTest::AttributeInfo & attributeInfo)1816 std::string getAttributeInfoCaseName(const VertexInputTest::AttributeInfo &attributeInfo)
1817 {
1818     std::ostringstream caseName;
1819     const std::string formatName = getFormatName(attributeInfo.vkType);
1820 
1821     caseName << "as_" << de::toLower(formatName.substr(10)) << "_rate_";
1822 
1823     if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
1824         caseName << "vertex";
1825     else
1826         caseName << "instance";
1827 
1828     return caseName.str();
1829 }
1830 
1831 struct CompatibleFormats
1832 {
1833     VertexInputTest::GlslType glslType;
1834     std::vector<VkFormat> compatibleVkFormats;
1835 };
1836 
createSingleAttributeCases(tcu::TestCaseGroup * singleAttributeTests,PipelineConstructionType pipelineConstructionType,VertexInputTest::GlslType glslType)1837 void createSingleAttributeCases(tcu::TestCaseGroup *singleAttributeTests,
1838                                 PipelineConstructionType pipelineConstructionType, VertexInputTest::GlslType glslType)
1839 {
1840     const VkFormat vertexFormats[] = {
1841         // Required, unpacked
1842         VK_FORMAT_R8_UNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_R8_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8G8_UNORM,
1843         VK_FORMAT_R8G8_SNORM, VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8B8A8_UNORM,
1844         VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_SINT, VK_FORMAT_B8G8R8A8_UNORM,
1845         VK_FORMAT_R16_UNORM, VK_FORMAT_R16_SNORM, VK_FORMAT_R16_UINT, VK_FORMAT_R16_SINT, VK_FORMAT_R16_SFLOAT,
1846         VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16_SINT,
1847         VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16B16_UNORM, VK_FORMAT_R16G16B16_SNORM, VK_FORMAT_R16G16B16_UINT,
1848         VK_FORMAT_R16G16B16_SINT, VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R16G16B16A16_UNORM,
1849         VK_FORMAT_R16G16B16A16_SNORM, VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT,
1850         VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, VK_FORMAT_R32_SFLOAT,
1851         VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_UINT,
1852         VK_FORMAT_R32G32B32_SINT, VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT,
1853         VK_FORMAT_R32G32B32A32_SFLOAT,
1854 
1855         // Scaled formats
1856         VK_FORMAT_R8G8_USCALED, VK_FORMAT_R8G8_SSCALED, VK_FORMAT_R16_USCALED, VK_FORMAT_R16_SSCALED,
1857         VK_FORMAT_R8G8B8_USCALED, VK_FORMAT_R8G8B8_SSCALED, VK_FORMAT_B8G8R8_USCALED, VK_FORMAT_B8G8R8_SSCALED,
1858         VK_FORMAT_R8G8B8A8_USCALED, VK_FORMAT_R8G8B8A8_SSCALED, VK_FORMAT_B8G8R8A8_USCALED, VK_FORMAT_B8G8R8A8_SSCALED,
1859         VK_FORMAT_R16G16_USCALED, VK_FORMAT_R16G16_SSCALED, VK_FORMAT_R16G16B16_USCALED, VK_FORMAT_R16G16B16_SSCALED,
1860         VK_FORMAT_R16G16B16A16_USCALED, VK_FORMAT_R16G16B16A16_SSCALED,
1861 
1862         // SRGB formats
1863         VK_FORMAT_R8_SRGB, VK_FORMAT_R8G8_SRGB, VK_FORMAT_R8G8B8_SRGB, VK_FORMAT_B8G8R8_SRGB, VK_FORMAT_R8G8B8A8_SRGB,
1864         VK_FORMAT_B8G8R8A8_SRGB,
1865 
1866         // Double formats
1867         VK_FORMAT_R64_SFLOAT, VK_FORMAT_R64G64_SFLOAT, VK_FORMAT_R64G64B64_SFLOAT, VK_FORMAT_R64G64B64A64_SFLOAT,
1868 
1869         // Packed formats
1870         VK_FORMAT_A2R10G10B10_USCALED_PACK32, VK_FORMAT_A2R10G10B10_SSCALED_PACK32, VK_FORMAT_A2R10G10B10_UINT_PACK32,
1871         VK_FORMAT_A2R10G10B10_SINT_PACK32, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1872         VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_FORMAT_A2R10G10B10_SNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1873         VK_FORMAT_A2B10G10R10_SNORM_PACK32, VK_FORMAT_B10G11R11_UFLOAT_PACK32};
1874 
1875     for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
1876     {
1877         if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], glslType))
1878         {
1879             {
1880                 // Create test case for RATE_VERTEX
1881                 VertexInputTest::AttributeInfo attributeInfo;
1882                 attributeInfo.vkType    = vertexFormats[formatNdx];
1883                 attributeInfo.glslType  = glslType;
1884                 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1885 
1886                 singleAttributeTests->addChild(new VertexInputTest(
1887                     singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo),
1888                     pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1889                     VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
1890 
1891                 // Create test case for RATE_INSTANCE
1892                 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
1893 
1894                 singleAttributeTests->addChild(new VertexInputTest(
1895                     singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo),
1896                     pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1897                     VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
1898             }
1899 
1900             // Test accessing missing components to verify "Converstion to RGBA" is correctly applied.
1901             const auto &typeInfo = VertexInputTest::s_glslTypeDescriptions[glslType];
1902             if (typeInfo.vertexInputComponentCount < kMaxComponents &&
1903                 typeInfo.basicType != VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
1904             {
1905                 // Create test case for RATE_VERTEX
1906                 VertexInputTest::AttributeInfo attributeInfo;
1907                 attributeInfo.vkType    = vertexFormats[formatNdx];
1908                 attributeInfo.glslType  = glslType;
1909                 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1910                 const auto nameSuffix   = "_missing_components";
1911 
1912                 singleAttributeTests->addChild(new VertexInputTest(
1913                     singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo) + nameSuffix,
1914                     pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1915                     VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED,
1916                     VertexInputTest::LAYOUT_SKIP_DISABLED, VertexInputTest::LAYOUT_ORDER_IN_ORDER, true));
1917 
1918                 // Create test case for RATE_INSTANCE
1919                 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
1920 
1921                 singleAttributeTests->addChild(new VertexInputTest(
1922                     singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo) + nameSuffix,
1923                     pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1924                     VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED,
1925                     VertexInputTest::LAYOUT_SKIP_DISABLED, VertexInputTest::LAYOUT_ORDER_IN_ORDER, true));
1926             }
1927         }
1928     }
1929 }
1930 
createSingleAttributeTests(tcu::TestCaseGroup * singleAttributeTests,PipelineConstructionType pipelineConstructionType)1931 void createSingleAttributeTests(tcu::TestCaseGroup *singleAttributeTests,
1932                                 PipelineConstructionType pipelineConstructionType)
1933 {
1934     for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
1935     {
1936         VertexInputTest::GlslType glslType = (VertexInputTest::GlslType)glslTypeNdx;
1937         addTestGroup(singleAttributeTests, VertexInputTest::s_glslTypeDescriptions[glslType].name,
1938                      createSingleAttributeCases, pipelineConstructionType, glslType);
1939     }
1940 }
1941 
1942 // Create all unique GlslType combinations recursively
createMultipleAttributeCases(PipelineConstructionType pipelineConstructionType,uint32_t depth,uint32_t firstNdx,CompatibleFormats * compatibleFormats,de::Random & randomFunc,tcu::TestCaseGroup & testGroup,VertexInputTest::BindingMapping bindingMapping,VertexInputTest::AttributeLayout attributeLayout,VertexInputTest::LayoutSkip layoutSkip,VertexInputTest::LayoutOrder layoutOrder,const std::vector<VertexInputTest::AttributeInfo> & attributeInfos=std::vector<VertexInputTest::AttributeInfo> (0))1943 void createMultipleAttributeCases(
1944     PipelineConstructionType pipelineConstructionType, uint32_t depth, uint32_t firstNdx,
1945     CompatibleFormats *compatibleFormats, de::Random &randomFunc, tcu::TestCaseGroup &testGroup,
1946     VertexInputTest::BindingMapping bindingMapping, VertexInputTest::AttributeLayout attributeLayout,
1947     VertexInputTest::LayoutSkip layoutSkip, VertexInputTest::LayoutOrder layoutOrder,
1948     const std::vector<VertexInputTest::AttributeInfo> &attributeInfos = std::vector<VertexInputTest::AttributeInfo>(0))
1949 {
1950     tcu::TestContext &testCtx = testGroup.getTestContext();
1951 
1952     // Exclude double values, which are not included in vertexFormats
1953     for (uint32_t currentNdx = firstNdx; currentNdx < VertexInputTest::GLSL_TYPE_DOUBLE - depth; currentNdx++)
1954     {
1955         std::vector<VertexInputTest::AttributeInfo> newAttributeInfos = attributeInfos;
1956 
1957         {
1958             VertexInputTest::AttributeInfo attributeInfo;
1959             attributeInfo.glslType  = (VertexInputTest::GlslType)currentNdx;
1960             attributeInfo.inputRate = (depth % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
1961             attributeInfo.vkType    = VK_FORMAT_UNDEFINED;
1962 
1963             newAttributeInfos.push_back(attributeInfo);
1964         }
1965 
1966         // Add test case
1967         if (depth == 0)
1968         {
1969             // Select a random compatible format for each attribute
1970             for (size_t i = 0; i < newAttributeInfos.size(); i++)
1971             {
1972                 const std::vector<VkFormat> &formats =
1973                     compatibleFormats[newAttributeInfos[i].glslType].compatibleVkFormats;
1974                 newAttributeInfos[i].vkType = formats[randomFunc.getUint32() % formats.size()];
1975             }
1976 
1977             const std::string caseName = VertexInputTest::s_glslTypeDescriptions[currentNdx].name;
1978 
1979             testGroup.addChild(new VertexInputTest(testCtx, caseName, pipelineConstructionType, newAttributeInfos,
1980                                                    bindingMapping, attributeLayout, layoutSkip, layoutOrder));
1981         }
1982         // Add test group
1983         else
1984         {
1985             const std::string name = VertexInputTest::s_glslTypeDescriptions[currentNdx].name;
1986             de::MovePtr<tcu::TestCaseGroup> newTestGroup(new tcu::TestCaseGroup(testCtx, name.c_str()));
1987 
1988             createMultipleAttributeCases(pipelineConstructionType, depth - 1u, currentNdx + 1u, compatibleFormats,
1989                                          randomFunc, *newTestGroup, bindingMapping, attributeLayout, layoutSkip,
1990                                          layoutOrder, newAttributeInfos);
1991             testGroup.addChild(newTestGroup.release());
1992         }
1993     }
1994 }
1995 
createMultipleAttributeTests(tcu::TestCaseGroup * multipleAttributeTests,PipelineConstructionType pipelineConstructionType)1996 void createMultipleAttributeTests(tcu::TestCaseGroup *multipleAttributeTests,
1997                                   PipelineConstructionType pipelineConstructionType)
1998 {
1999     // Required vertex formats, unpacked
2000     const VkFormat vertexFormats[] = {
2001         VK_FORMAT_R8_UNORM,          VK_FORMAT_R8_SNORM,           VK_FORMAT_R8_UINT,
2002         VK_FORMAT_R8_SINT,           VK_FORMAT_R8G8_UNORM,         VK_FORMAT_R8G8_SNORM,
2003         VK_FORMAT_R8G8_UINT,         VK_FORMAT_R8G8_SINT,          VK_FORMAT_R8G8B8A8_UNORM,
2004         VK_FORMAT_R8G8B8A8_SNORM,    VK_FORMAT_R8G8B8A8_UINT,      VK_FORMAT_R8G8B8A8_SINT,
2005         VK_FORMAT_B8G8R8A8_UNORM,    VK_FORMAT_R16_UNORM,          VK_FORMAT_R16_SNORM,
2006         VK_FORMAT_R16_UINT,          VK_FORMAT_R16_SINT,           VK_FORMAT_R16_SFLOAT,
2007         VK_FORMAT_R16G16_UNORM,      VK_FORMAT_R16G16_SNORM,       VK_FORMAT_R16G16_UINT,
2008         VK_FORMAT_R16G16_SINT,       VK_FORMAT_R16G16_SFLOAT,      VK_FORMAT_R16G16B16_UNORM,
2009         VK_FORMAT_R16G16B16_SNORM,   VK_FORMAT_R16G16B16_UINT,     VK_FORMAT_R16G16B16_SINT,
2010         VK_FORMAT_R16G16B16_SFLOAT,  VK_FORMAT_R16G16B16A16_UNORM, VK_FORMAT_R16G16B16A16_SNORM,
2011         VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT,  VK_FORMAT_R16G16B16A16_SFLOAT,
2012         VK_FORMAT_R32_UINT,          VK_FORMAT_R32_SINT,           VK_FORMAT_R32_SFLOAT,
2013         VK_FORMAT_R32G32_UINT,       VK_FORMAT_R32G32_SINT,        VK_FORMAT_R32G32_SFLOAT,
2014         VK_FORMAT_R32G32B32_UINT,    VK_FORMAT_R32G32B32_SINT,     VK_FORMAT_R32G32B32_SFLOAT,
2015         VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT,  VK_FORMAT_R32G32B32A32_SFLOAT};
2016 
2017     const VertexInputTest::LayoutSkip layoutSkips[] = {VertexInputTest::LAYOUT_SKIP_DISABLED,
2018                                                        VertexInputTest::LAYOUT_SKIP_ENABLED};
2019 
2020     const VertexInputTest::LayoutOrder layoutOrders[] = {VertexInputTest::LAYOUT_ORDER_IN_ORDER,
2021                                                          VertexInputTest::LAYOUT_ORDER_OUT_OF_ORDER};
2022 
2023     // Find compatible VK formats for each GLSL vertex type
2024     CompatibleFormats compatibleFormats[VertexInputTest::GLSL_TYPE_COUNT];
2025     {
2026         for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
2027         {
2028             for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
2029             {
2030                 if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
2031                     compatibleFormats[glslTypeNdx].compatibleVkFormats.push_back(vertexFormats[formatNdx]);
2032             }
2033         }
2034     }
2035 
2036     de::Random randomFunc(102030);
2037     tcu::TestContext &testCtx = multipleAttributeTests->getTestContext();
2038 
2039     for (uint32_t layoutSkipNdx = 0; layoutSkipNdx < DE_LENGTH_OF_ARRAY(layoutSkips); layoutSkipNdx++)
2040         for (uint32_t layoutOrderNdx = 0; layoutOrderNdx < DE_LENGTH_OF_ARRAY(layoutOrders); layoutOrderNdx++)
2041         {
2042             const VertexInputTest::LayoutSkip layoutSkip   = layoutSkips[layoutSkipNdx];
2043             const VertexInputTest::LayoutOrder layoutOrder = layoutOrders[layoutOrderNdx];
2044             de::MovePtr<tcu::TestCaseGroup> oneToOneAttributeTests(new tcu::TestCaseGroup(testCtx, "attributes"));
2045             de::MovePtr<tcu::TestCaseGroup> oneToManyAttributeTests(new tcu::TestCaseGroup(testCtx, "attributes"));
2046             de::MovePtr<tcu::TestCaseGroup> oneToManySequentialAttributeTests(
2047                 new tcu::TestCaseGroup(testCtx, "attributes_sequential"));
2048 
2049             if (layoutSkip == VertexInputTest::LAYOUT_SKIP_ENABLED &&
2050                 layoutOrder == VertexInputTest::LAYOUT_ORDER_OUT_OF_ORDER)
2051                 continue;
2052 
2053             createMultipleAttributeCases(pipelineConstructionType, 2u, 0u, compatibleFormats, randomFunc,
2054                                          *oneToOneAttributeTests, VertexInputTest::BINDING_MAPPING_ONE_TO_ONE,
2055                                          VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED, layoutSkip, layoutOrder);
2056             createMultipleAttributeCases(pipelineConstructionType, 2u, 0u, compatibleFormats, randomFunc,
2057                                          *oneToManyAttributeTests, VertexInputTest::BINDING_MAPPING_ONE_TO_MANY,
2058                                          VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED, layoutSkip, layoutOrder);
2059             createMultipleAttributeCases(pipelineConstructionType, 2u, 0u, compatibleFormats, randomFunc,
2060                                          *oneToManySequentialAttributeTests,
2061                                          VertexInputTest::BINDING_MAPPING_ONE_TO_MANY,
2062                                          VertexInputTest::ATTRIBUTE_LAYOUT_SEQUENTIAL, layoutSkip, layoutOrder);
2063 
2064             if (layoutSkip == VertexInputTest::LAYOUT_SKIP_ENABLED)
2065             {
2066                 // Skip one layout after each attribute
2067                 de::MovePtr<tcu::TestCaseGroup> layoutSkipTests(new tcu::TestCaseGroup(testCtx, "layout_skip"));
2068 
2069                 // Each attribute uses a unique binding
2070                 de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(
2071                     new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2072                 bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
2073                 layoutSkipTests->addChild(bindingOneToOneTests.release());
2074 
2075                 de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(
2076                     new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2077                 bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
2078                 bindingOneToManyTests->addChild(oneToManySequentialAttributeTests.release());
2079                 layoutSkipTests->addChild(bindingOneToManyTests.release());
2080                 multipleAttributeTests->addChild(layoutSkipTests.release());
2081             }
2082             else if (layoutOrder == VertexInputTest::LAYOUT_ORDER_OUT_OF_ORDER)
2083             {
2084                 de::MovePtr<tcu::TestCaseGroup> layoutOutOfOrderTests(new tcu::TestCaseGroup(testCtx, "out_of_order"));
2085 
2086                 de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(
2087                     new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2088                 bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
2089                 layoutOutOfOrderTests->addChild(bindingOneToOneTests.release());
2090 
2091                 de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(
2092                     new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2093                 bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
2094                 bindingOneToManyTests->addChild(oneToManySequentialAttributeTests.release());
2095                 layoutOutOfOrderTests->addChild(bindingOneToManyTests.release());
2096                 multipleAttributeTests->addChild(layoutOutOfOrderTests.release());
2097             }
2098             else
2099             {
2100                 de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(
2101                     new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2102                 bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
2103                 multipleAttributeTests->addChild(bindingOneToOneTests.release());
2104 
2105                 de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(
2106                     new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2107                 bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
2108                 bindingOneToManyTests->addChild(oneToManySequentialAttributeTests.release());
2109                 multipleAttributeTests->addChild(bindingOneToManyTests.release());
2110             }
2111         }
2112 }
2113 
createMaxAttributeTests(tcu::TestCaseGroup * maxAttributeTests,PipelineConstructionType pipelineConstructionType)2114 void createMaxAttributeTests(tcu::TestCaseGroup *maxAttributeTests, PipelineConstructionType pipelineConstructionType)
2115 {
2116     // Required vertex formats, unpacked
2117     const VkFormat vertexFormats[] = {
2118         VK_FORMAT_R8_UNORM,          VK_FORMAT_R8_SNORM,           VK_FORMAT_R8_UINT,
2119         VK_FORMAT_R8_SINT,           VK_FORMAT_R8G8_UNORM,         VK_FORMAT_R8G8_SNORM,
2120         VK_FORMAT_R8G8_UINT,         VK_FORMAT_R8G8_SINT,          VK_FORMAT_R8G8B8A8_UNORM,
2121         VK_FORMAT_R8G8B8A8_SNORM,    VK_FORMAT_R8G8B8A8_UINT,      VK_FORMAT_R8G8B8A8_SINT,
2122         VK_FORMAT_B8G8R8A8_UNORM,    VK_FORMAT_R16_UNORM,          VK_FORMAT_R16_SNORM,
2123         VK_FORMAT_R16_UINT,          VK_FORMAT_R16_SINT,           VK_FORMAT_R16_SFLOAT,
2124         VK_FORMAT_R16G16_UNORM,      VK_FORMAT_R16G16_SNORM,       VK_FORMAT_R16G16_UINT,
2125         VK_FORMAT_R16G16_SINT,       VK_FORMAT_R16G16_SFLOAT,      VK_FORMAT_R16G16B16_UNORM,
2126         VK_FORMAT_R16G16B16_SNORM,   VK_FORMAT_R16G16B16_UINT,     VK_FORMAT_R16G16B16_SINT,
2127         VK_FORMAT_R16G16B16_SFLOAT,  VK_FORMAT_R16G16B16A16_UNORM, VK_FORMAT_R16G16B16A16_SNORM,
2128         VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT,  VK_FORMAT_R16G16B16A16_SFLOAT,
2129         VK_FORMAT_R32_UINT,          VK_FORMAT_R32_SINT,           VK_FORMAT_R32_SFLOAT,
2130         VK_FORMAT_R32G32_UINT,       VK_FORMAT_R32G32_SINT,        VK_FORMAT_R32G32_SFLOAT,
2131         VK_FORMAT_R32G32B32_UINT,    VK_FORMAT_R32G32B32_SINT,     VK_FORMAT_R32G32B32_SFLOAT,
2132         VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT,  VK_FORMAT_R32G32B32A32_SFLOAT};
2133 
2134     // VkPhysicalDeviceLimits::maxVertexInputAttributes is used when attributeCount is 0
2135     const uint32_t attributeCount[] = {16, 32, 64, 128, 0};
2136     tcu::TestContext &testCtx(maxAttributeTests->getTestContext());
2137     de::Random randomFunc(132030);
2138 
2139     // Find compatible VK formats for each GLSL vertex type
2140     CompatibleFormats compatibleFormats[VertexInputTest::GLSL_TYPE_COUNT];
2141     {
2142         for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
2143         {
2144             for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
2145             {
2146                 if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
2147                     compatibleFormats[glslTypeNdx].compatibleVkFormats.push_back(vertexFormats[formatNdx]);
2148             }
2149         }
2150     }
2151 
2152     for (uint32_t attributeCountNdx = 0; attributeCountNdx < DE_LENGTH_OF_ARRAY(attributeCount); attributeCountNdx++)
2153     {
2154         const std::string groupName =
2155             (attributeCount[attributeCountNdx] == 0 ? "query_max" : de::toString(attributeCount[attributeCountNdx])) +
2156             "_attributes";
2157         const std::string groupDesc = de::toString(attributeCount[attributeCountNdx]) + " vertex input attributes";
2158 
2159         de::MovePtr<tcu::TestCaseGroup> numAttributeTests(new tcu::TestCaseGroup(testCtx, groupName.c_str()));
2160         de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2161         de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2162 
2163         std::vector<VertexInputTest::AttributeInfo> attributeInfos(attributeCount[attributeCountNdx]);
2164 
2165         for (uint32_t attributeNdx = 0; attributeNdx < attributeCount[attributeCountNdx]; attributeNdx++)
2166         {
2167             // Use random glslTypes, each consuming one attribute location
2168             const VertexInputTest::GlslType glslType =
2169                 (VertexInputTest::GlslType)(randomFunc.getUint32() % VertexInputTest::GLSL_TYPE_MAT2);
2170             const std::vector<VkFormat> &formats = compatibleFormats[glslType].compatibleVkFormats;
2171             const VkFormat format                = formats[randomFunc.getUint32() % formats.size()];
2172 
2173             attributeInfos[attributeNdx].glslType  = glslType;
2174             attributeInfos[attributeNdx].inputRate = ((attributeCountNdx + attributeNdx) % 2 == 0) ?
2175                                                          VK_VERTEX_INPUT_RATE_VERTEX :
2176                                                          VK_VERTEX_INPUT_RATE_INSTANCE;
2177             attributeInfos[attributeNdx].vkType    = format;
2178         }
2179 
2180         // Interleaved attribute layout
2181         bindingOneToOneTests->addChild(new VertexInputTest(testCtx, "interleaved", pipelineConstructionType,
2182                                                            attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_ONE,
2183                                                            VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
2184         // Interleaved attribute layout
2185         bindingOneToManyTests->addChild(new VertexInputTest(
2186             testCtx, "interleaved", pipelineConstructionType, attributeInfos,
2187             VertexInputTest::BINDING_MAPPING_ONE_TO_MANY, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
2188         // Sequential attribute layout
2189         bindingOneToManyTests->addChild(new VertexInputTest(
2190             testCtx, "sequential", pipelineConstructionType, attributeInfos,
2191             VertexInputTest::BINDING_MAPPING_ONE_TO_MANY, VertexInputTest::ATTRIBUTE_LAYOUT_SEQUENTIAL));
2192 
2193         numAttributeTests->addChild(bindingOneToOneTests.release());
2194         numAttributeTests->addChild(bindingOneToManyTests.release());
2195         maxAttributeTests->addChild(numAttributeTests.release());
2196     }
2197 }
2198 
2199 // The goal of the stride change tests are checking a sequence like the following one:
2200 //
2201 // CmdBindVertexBuffers()
2202 // CmdBindPipeline(VS+FS)
2203 // CmdDraw()
2204 // CmdBindPipeline(VS+GS+FS)
2205 // CmdDraw()
2206 //
2207 // Where the second pipeline bind needs different vertex buffer info (like binding stride) that doesn't require a new
2208 // CmdBindVertexBuffers.
2209 //
2210 // We will draw a full screen quad with two triangles, and use one triangle per draw call. The vertex buffer will be set up such
2211 // that the vertices for the first triangle will be contiguous in memory, but the ones for the second triangle will use two extra
2212 // vertices for padding, so it looks like:
2213 //
2214 // FIRST0, FIRST1, FIRST2, SECOND0, PADDING, PADDING, SECOND1, PADDING, PADDING, SECOND2, PADDING, PADDING
2215 //
2216 // The stride in the first pipeline will be sizeof(vec4) and, for the second one, sizeof(vec4)*3.
2217 // Draw calls parameters will be:
2218 // 1. vkCmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
2219 // 2. vkCmdDraw(cmdBuffer, 3u, 1u, 1u, 0u); // firstVertex == 1u so that FIRST0, FIRST1, FIRST2 are skipped with the new stride.
2220 //
2221 struct StrideChangeParams
2222 {
2223     PipelineConstructionType pipelineConstructionType;
2224     bool useTessellation; // In the second bind.
2225     bool useGeometry;     // In the second bind.
2226 };
2227 
2228 class StrideChangeTest : public vkt::TestInstance
2229 {
2230 public:
StrideChangeTest(Context & context,const StrideChangeParams & params)2231     StrideChangeTest(Context &context, const StrideChangeParams &params) : vkt::TestInstance(context), m_params(params)
2232     {
2233     }
~StrideChangeTest(void)2234     virtual ~StrideChangeTest(void)
2235     {
2236     }
2237 
2238     tcu::TestStatus iterate(void) override;
2239 
2240 protected:
2241     const StrideChangeParams m_params;
2242 };
2243 
2244 class StrideChangeCase : public vkt::TestCase
2245 {
2246 public:
StrideChangeCase(tcu::TestContext & testCtx,const std::string & name,const StrideChangeParams & params)2247     StrideChangeCase(tcu::TestContext &testCtx, const std::string &name, const StrideChangeParams &params)
2248         : vkt::TestCase(testCtx, name)
2249         , m_params(params)
2250     {
2251     }
~StrideChangeCase(void)2252     virtual ~StrideChangeCase(void)
2253     {
2254     }
2255 
2256     void initPrograms(vk::SourceCollections &programCollection) const override;
2257     TestInstance *createInstance(Context &context) const override;
2258     void checkSupport(Context &context) const override;
2259 
2260 protected:
2261     const StrideChangeParams m_params;
2262 };
2263 
initPrograms(SourceCollections & dst) const2264 void StrideChangeCase::initPrograms(SourceCollections &dst) const
2265 {
2266     std::ostringstream vert;
2267     vert << "#version 460\n"
2268          << "layout (location=0) in vec4 inPos;\n"
2269          << "out gl_PerVertex\n"
2270          << "{\n"
2271          << "    vec4 gl_Position;\n"
2272          << "};\n"
2273          << "void main (void) {\n"
2274          << "    gl_Position = inPos;\n"
2275          << "}\n";
2276     dst.glslSources.add("vert") << glu::VertexSource(vert.str());
2277 
2278     if (m_params.useTessellation)
2279     {
2280         std::ostringstream tesc;
2281         tesc << "#version 460\n"
2282              << "layout (vertices=3) out;\n"
2283              << "in gl_PerVertex\n"
2284              << "{\n"
2285              << "    vec4 gl_Position;\n"
2286              << "} gl_in[gl_MaxPatchVertices];\n"
2287              << "out gl_PerVertex\n"
2288              << "{\n"
2289              << "    vec4 gl_Position;\n"
2290              << "} gl_out[];\n"
2291              << "void main (void)\n"
2292              << "{\n"
2293              << "    gl_TessLevelInner[0] = 1.0;\n"
2294              << "    gl_TessLevelInner[1] = 1.0;\n"
2295              << "    gl_TessLevelOuter[0] = 1.0;\n"
2296              << "    gl_TessLevelOuter[1] = 1.0;\n"
2297              << "    gl_TessLevelOuter[2] = 1.0;\n"
2298              << "    gl_TessLevelOuter[3] = 1.0;\n"
2299              << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2300              << "}\n";
2301         dst.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
2302 
2303         std::ostringstream tese;
2304         tese << "#version 460\n"
2305              << "layout (triangles, fractional_odd_spacing, cw) in;\n"
2306              << "in gl_PerVertex\n"
2307              << "{\n"
2308              << "    vec4 gl_Position;\n"
2309              << "} gl_in[gl_MaxPatchVertices];\n"
2310              << "out gl_PerVertex\n"
2311              << "{\n"
2312              << "    vec4 gl_Position;\n"
2313              << "};\n"
2314              << "void main (void)\n"
2315              << "{\n"
2316              << "    gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
2317              << "                  (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
2318              << "                  (gl_TessCoord.z * gl_in[2].gl_Position);\n"
2319              << "}\n";
2320         dst.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
2321     }
2322 
2323     if (m_params.useGeometry)
2324     {
2325         std::ostringstream geom;
2326         geom << "#version 460\n"
2327              << "layout (triangles) in;\n"
2328              << "layout (triangle_strip, max_vertices=3) out;\n"
2329              << "in gl_PerVertex\n"
2330              << "{\n"
2331              << "    vec4 gl_Position;\n"
2332              << "} gl_in[3];\n"
2333              << "out gl_PerVertex\n"
2334              << "{\n"
2335              << "    vec4 gl_Position;\n"
2336              << "};\n"
2337              << "void main ()\n"
2338              << "{\n"
2339              << "    gl_Position = gl_in[0].gl_Position; EmitVertex();\n"
2340              << "    gl_Position = gl_in[1].gl_Position; EmitVertex();\n"
2341              << "    gl_Position = gl_in[2].gl_Position; EmitVertex();\n"
2342              << "}\n";
2343         dst.glslSources.add("geom") << glu::GeometrySource(geom.str());
2344     }
2345 
2346     std::ostringstream frag;
2347     frag << "#version 460\n"
2348          << "layout (location=0) out vec4 outColor;\n"
2349          << "void main (void) {\n"
2350          << "    outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
2351          << "}\n";
2352     dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
2353 }
2354 
createInstance(Context & context) const2355 TestInstance *StrideChangeCase::createInstance(Context &context) const
2356 {
2357     return new StrideChangeTest(context, m_params);
2358 }
2359 
checkSupport(Context & context) const2360 void StrideChangeCase::checkSupport(Context &context) const
2361 {
2362     const auto &vki           = context.getInstanceInterface();
2363     const auto physicalDevice = context.getPhysicalDevice();
2364 
2365     checkPipelineConstructionRequirements(vki, physicalDevice, m_params.pipelineConstructionType);
2366 
2367     if (m_params.useTessellation)
2368         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
2369 
2370     if (m_params.useGeometry)
2371         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
2372 }
2373 
iterate(void)2374 tcu::TestStatus StrideChangeTest::iterate(void)
2375 {
2376     const auto &ctx = m_context.getContextCommonData();
2377     const tcu::IVec3 fbExtent(4, 4, 1);
2378     const auto vkExtent  = makeExtent3D(fbExtent);
2379     const auto fbFormat  = VK_FORMAT_R8G8B8A8_UNORM;
2380     const auto tcuFormat = mapVkFormat(fbFormat);
2381     const auto fbUsage   = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2382     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2383     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader.
2384     const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
2385     const auto kTriVtx = 3u;                           // 3 vertices per triangle.
2386 
2387     // Color buffer with verification buffer.
2388     ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage, VK_IMAGE_TYPE_2D);
2389 
2390     // Vertices. See the test description above about padding and real vertices.
2391     const std::vector<tcu::Vec4> vertices{
2392         tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), // First triangle, vertex 0.
2393         tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),  // First triangle, vertex 1.
2394         tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),  // First triangle, vertex 2.
2395 
2396         tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), // Second triangle, vertex 0.  |
2397         tcu::Vec4(-1.0f, -1.0f, 0.0f,
2398                   1.0f), // Padding.                    | Padding such that it's the first triangle again.
2399         tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // Padding.                    |
2400 
2401         tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // Second triangle, vertex 1.  |
2402         tcu::Vec4(1.0f, -1.0f, 0.0f,
2403                   1.0f), // Padding.                    | Padding such that it's the first triangle again.
2404         tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), // Padding.                    |
2405 
2406         tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // Second triangle, vertex 2.  |
2407         tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // Padding.                    | Padding such that it's a zero-area triangle.
2408         tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // Padding.                    |
2409     };
2410 
2411     // Vertex buffer
2412     const auto vbSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
2413     const auto vbInfo = makeBufferCreateInfo(vbSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
2414     BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, MemoryRequirement::HostVisible);
2415     const auto vbAlloc  = vertexBuffer.getAllocation();
2416     void *vbData        = vbAlloc.getHostPtr();
2417     const auto vbOffset = static_cast<VkDeviceSize>(0);
2418 
2419     deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
2420     flushAlloc(ctx.vkd, ctx.device, vbAlloc); // strictly speaking, not needed.
2421 
2422     const auto pipelineLayout = PipelineLayoutWrapper(m_params.pipelineConstructionType, ctx.vkd, ctx.device);
2423     auto renderPass           = RenderPassWrapper(m_params.pipelineConstructionType, ctx.vkd, ctx.device, fbFormat);
2424     renderPass.createFramebuffer(ctx.vkd, ctx.device, colorBuffer.getImage(), colorBuffer.getImageView(),
2425                                  vkExtent.width, vkExtent.height);
2426 
2427     // Modules.
2428     const auto &binaries  = m_context.getBinaryCollection();
2429     const auto nullModule = ShaderWrapper();
2430     const auto vertModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("vert"));
2431     const auto tescModule =
2432         (m_params.useTessellation ? ShaderWrapper(ctx.vkd, ctx.device, binaries.get("tesc")) : nullModule);
2433     const auto teseModule =
2434         (m_params.useTessellation ? ShaderWrapper(ctx.vkd, ctx.device, binaries.get("tese")) : nullModule);
2435     const auto geomModule =
2436         (m_params.useGeometry ? ShaderWrapper(ctx.vkd, ctx.device, binaries.get("geom")) : nullModule);
2437     const auto fragModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("frag"));
2438 
2439     const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
2440     const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
2441 
2442     const std::vector<uint32_t> vertexStrides{
2443         static_cast<uint32_t>(sizeof(tcu::Vec4)),           // Short stride for the first draw.
2444         static_cast<uint32_t>(sizeof(tcu::Vec4) * kTriVtx), // Long stride for the second draw.
2445     };
2446 
2447     const std::vector<uint32_t> firstVertices{0u, 1u}; // First vertices for the vkCmdDraw() calls, see comment above.
2448 
2449     const std::vector<bool> useTessellation{false, m_params.useTessellation};
2450     const std::vector<bool> useGeometry{false, m_params.useGeometry};
2451 
2452     using PipelinePtr = std::unique_ptr<GraphicsPipelineWrapper>;
2453     std::vector<PipelinePtr> pipelines;
2454 
2455     const auto inputAttribute = makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
2456 
2457     DE_ASSERT(vertexStrides.size() == useTessellation.size());
2458     DE_ASSERT(vertexStrides.size() == useGeometry.size());
2459 
2460     for (size_t i = 0u; i < vertexStrides.size(); ++i)
2461     {
2462         const auto vtxStride    = vertexStrides.at(i);
2463         const auto useTess      = useTessellation.at(i);
2464         const auto useGeom      = useGeometry.at(i);
2465         const auto topology     = (useTess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
2466         const auto inputBinding = makeVertexInputBindingDescription(0u, vtxStride, VK_VERTEX_INPUT_RATE_VERTEX);
2467 
2468         const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
2469             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
2470             nullptr,                                                   // const void* pNext;
2471             0u,                                                        // VkPipelineVertexInputStateCreateFlags flags;
2472             1u,                                                        // uint32_t vertexBindingDescriptionCount;
2473             &inputBinding,   // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
2474             1u,              // uint32_t vertexAttributeDescriptionCount;
2475             &inputAttribute, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
2476         };
2477 
2478         pipelines.emplace_back(new GraphicsPipelineWrapper(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
2479                                                            m_context.getDeviceExtensions(),
2480                                                            m_params.pipelineConstructionType));
2481         auto &pipeline = *pipelines.back();
2482         pipeline.setDefaultTopology(topology)
2483             .setDefaultRasterizationState()
2484             .setDefaultDepthStencilState()
2485             .setDefaultMultisampleState()
2486             .setDefaultColorBlendState()
2487             .setupVertexInputState(&vertexInputStateCreateInfo)
2488             .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u, vertModule, nullptr,
2489                                               (useTess ? tescModule : nullModule), (useTess ? teseModule : nullModule),
2490                                               (useGeom ? geomModule : nullModule))
2491             .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragModule)
2492             .setupFragmentOutputState(*renderPass)
2493             .setMonolithicPipelineLayout(pipelineLayout)
2494             .buildPipeline();
2495         ;
2496     }
2497 
2498     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
2499     const auto cmdBuffer = *cmd.cmdBuffer;
2500 
2501     beginCommandBuffer(ctx.vkd, cmdBuffer);
2502     renderPass.begin(ctx.vkd, cmdBuffer, scissors.at(0u), clearColor);
2503     ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
2504     DE_ASSERT(pipelines.size() == firstVertices.size());
2505     for (size_t i = 0; i < pipelines.size(); ++i)
2506     {
2507         pipelines.at(i)->bind(cmdBuffer);
2508         ctx.vkd.cmdDraw(cmdBuffer, kTriVtx, 1u, firstVertices.at(i), 0u);
2509     }
2510     renderPass.end(ctx.vkd, cmdBuffer);
2511     copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1),
2512                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
2513                       VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
2514                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2515     endCommandBuffer(ctx.vkd, cmdBuffer);
2516     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
2517 
2518     // Verify color output.
2519     invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
2520     tcu::PixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
2521 
2522     tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
2523     auto referenceAccess = referenceLevel.getAccess();
2524     tcu::clear(referenceAccess, geomColor);
2525 
2526     auto &log = m_context.getTestContext().getLog();
2527     if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
2528                                     tcu::COMPARE_LOG_ON_ERROR))
2529         return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
2530 
2531     return tcu::TestStatus::pass("Pass");
2532 }
2533 
createMiscVertexInputTests(tcu::TestCaseGroup * miscTests,PipelineConstructionType pipelineConstructionType)2534 void createMiscVertexInputTests(tcu::TestCaseGroup *miscTests, PipelineConstructionType pipelineConstructionType)
2535 {
2536     auto &testCtx = miscTests->getTestContext();
2537 
2538     for (const auto useTess : {false, true})
2539         for (const auto useGeom : {false, true})
2540         {
2541             const StrideChangeParams params{
2542                 pipelineConstructionType,
2543                 useTess,
2544                 useGeom,
2545             };
2546             const auto testName =
2547                 std::string("stride_change_vert") + (useTess ? "_tess" : "") + (useGeom ? "_geom" : "") + "_frag";
2548             miscTests->addChild(new StrideChangeCase(testCtx, testName, params));
2549         }
2550 }
2551 
2552 } // namespace
2553 
createVertexInputTests(tcu::TestCaseGroup * vertexInputTests,PipelineConstructionType pipelineConstructionType)2554 void createVertexInputTests(tcu::TestCaseGroup *vertexInputTests, PipelineConstructionType pipelineConstructionType)
2555 {
2556     // Uses one attribute
2557     addTestGroup(vertexInputTests, "single_attribute", createSingleAttributeTests, pipelineConstructionType);
2558     // Uses more than one attribute
2559     addTestGroup(vertexInputTests, "multiple_attributes", createMultipleAttributeTests, pipelineConstructionType);
2560     // Implementations can use as many vertex input attributes as they advertise
2561     addTestGroup(vertexInputTests, "max_attributes", createMaxAttributeTests, pipelineConstructionType);
2562 
2563     // Miscellaneous tests.
2564     addTestGroup(vertexInputTests, "misc", createMiscVertexInputTests, pipelineConstructionType);
2565 }
2566 
2567 } // namespace pipeline
2568 } // namespace vkt
2569