Add test for maxVertexInputAttributes
authorPaavo Pessi <paavo.pessi@siru.fi>
Mon, 3 Jul 2017 09:34:48 +0000 (12:34 +0300)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Thu, 20 Jul 2017 18:28:51 +0000 (14:28 -0400)
Tests were added to verify that implementations can use as many vertex
input attributes as they advertise.

Existing vertex input tests were modified to never consume more than
one vertex input binding per vertex input attribute.

New tests:

dEQP-VK.pipeline.vertex_input.max_attributes.*

Affects:

dEQP-VK.pipeline.vertex_input.single_attribute.*
dEQP-VK.pipeline.vertex_input.multiple_attributes.*

Components: Vulkan

VK-GL-CTS issue: 261

Change-Id: I3a481618e700ccda8caa4ea00426be14867a58e5

android/cts/master/vk-master.txt
external/vulkancts/modules/vulkan/pipeline/vktPipelineVertexInputTests.cpp
external/vulkancts/mustpass/1.0.3/vk-default.txt

index ffee8d197141747f96040636341dbe654fa536d8..09ffbe39fc6748e8cee357a1989327c4becd52d8 100644 (file)
@@ -138302,6 +138302,21 @@ dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes
 dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes_sequential.vec4.mat2.mat4
 dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes_sequential.vec4.mat3.mat4
 dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes_sequential.mat2.mat3.mat4
+dEQP-VK.pipeline.vertex_input.max_attributes.16_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.16_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.16_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.32_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.32_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.32_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.64_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.64_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.64_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.128_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.128_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.128_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.query_max_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.query_max_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.query_max_attributes.binding_one_to_many.sequential
 dEQP-VK.pipeline.input_assembly.primitive_topology.point_list
 dEQP-VK.pipeline.input_assembly.primitive_topology.line_list
 dEQP-VK.pipeline.input_assembly.primitive_topology.line_strip
index dcef8c54e78665d80597c818e8660561aa210bf7..1b4d8dfa0fc2086b4ac5b19b95326f256e234caf 100644 (file)
@@ -176,15 +176,19 @@ public:
        static bool                                                             isCompatibleType                        (VkFormat format, GlslType glslType);
 
 private:
+       AttributeInfo                                                   getAttributeInfo                        (size_t attributeNdx) const;
+       size_t                                                                  getNumAttributes                        (void) const;
        std::string                                                             getGlslInputDeclarations        (void) const;
        std::string                                                             getGlslVertexCheck                      (void) const;
-       std::string                                                             getGlslAttributeConditions      (const AttributeInfo& attributeInfo, deUint32 attributeIndex) const;
+       std::string                                                             getGlslAttributeConditions      (const AttributeInfo& attributeInfo, const std::string attributeIndex) const;
        static tcu::Vec4                                                getFormatThreshold                      (VkFormat format);
 
        const std::vector<AttributeInfo>                m_attributeInfos;
        const BindingMapping                                    m_bindingMapping;
        const AttributeLayout                                   m_attributeLayout;
+       const bool                                                              m_queryMaxAttributes;
        bool                                                                    m_usesDoubleType;
+       mutable size_t                                                  m_maxAttributes;
 };
 
 class VertexInputInstance : public vkt::TestInstance
@@ -281,6 +285,8 @@ VertexInputTest::VertexInputTest (tcu::TestContext&                                         testContext,
        , m_attributeInfos              (attributeInfos)
        , m_bindingMapping              (bindingMapping)
        , m_attributeLayout             (attributeLayout)
+       , m_queryMaxAttributes  (attributeInfos.size() == 0)
+       , m_maxAttributes               (16)
 {
        DE_ASSERT(m_attributeLayout == ATTRIBUTE_LAYOUT_INTERLEAVED || m_bindingMapping == BINDING_MAPPING_ONE_TO_MANY);
 
@@ -296,21 +302,17 @@ VertexInputTest::VertexInputTest (tcu::TestContext&                                               testContext,
        }
 }
 
-deUint32 getAttributeBinding (const VertexInputTest::BindingMapping bindingMapping, const VkVertexInputRate inputRate, const deUint32 attributeNdx)
+deUint32 getAttributeBinding (const VertexInputTest::BindingMapping bindingMapping, const VkVertexInputRate firstInputRate, const VkVertexInputRate inputRate, const deUint32 attributeNdx)
 {
        if (bindingMapping == VertexInputTest::BINDING_MAPPING_ONE_TO_ONE)
        {
-               if (inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
-                       return attributeNdx * 2;                // Even binding number
-               else // inputRate == VK_VERTEX_INPUT_STEP_RATE_INSTANCE
-                       return attributeNdx * 2 + 1;    // Odd binding number
+               // Each attribute uses a unique binding
+               return attributeNdx;
        }
        else // bindingMapping == BINDING_MAPPING_ONE_TO_MANY
        {
-               if (inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
-                       return 0u;
-               else // inputRate == VK_VERTEX_INPUT_STEP_RATE_INSTANCE
-                       return 1u;
+               // Alternate between two bindings
+               return deUint32(firstInputRate + inputRate) % 2u;
        }
 }
 
@@ -328,18 +330,67 @@ deUint32 getConsumedLocations (const VertexInputTest::AttributeInfo& attributeIn
                return 1u;
 }
 
+VertexInputTest::AttributeInfo VertexInputTest::getAttributeInfo (size_t attributeNdx) const
+{
+       if (m_queryMaxAttributes)
+       {
+               AttributeInfo attributeInfo =
+               {
+                       GLSL_TYPE_VEC4,
+                       VK_FORMAT_R8G8B8A8_SNORM,
+                       (attributeNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
+               };
+
+               return attributeInfo;
+       }
+       else
+       {
+               return m_attributeInfos.at(attributeNdx);
+       }
+}
+
+size_t VertexInputTest::getNumAttributes (void) const
+{
+       if (m_queryMaxAttributes)
+               return m_maxAttributes;
+       else
+               return m_attributeInfos.size();
+}
+
 TestInstance* VertexInputTest::createInstance (Context& context) const
 {
        typedef VertexInputInstance::VertexInputAttributeDescription VertexInputAttributeDescription;
 
+       // Check upfront for maximum number of vertex input attributes
+       {
+               const InstanceInterface&                vki                             = context.getInstanceInterface();
+               const VkPhysicalDevice                  physDevice              = context.getPhysicalDevice();
+               const VkPhysicalDeviceLimits    limits                  = getPhysicalDeviceProperties(vki, physDevice).limits;
+
+               const deUint32                                  maxAttributes   = limits.maxVertexInputAttributes;
+
+               if (m_attributeInfos.size() > maxAttributes)
+               {
+                       const std::string notSupportedStr = "Unsupported number of vertex input attributes, maxVertexInputAttributes: " + de::toString(maxAttributes);
+                       TCU_THROW(NotSupportedError, notSupportedStr.c_str());
+               }
+
+               // Use VkPhysicalDeviceLimits::maxVertexInputAttributes
+               if (m_queryMaxAttributes)
+                       m_maxAttributes = maxAttributes;
+       }
+
        // Create enough binding descriptions with random offsets
        std::vector<VkVertexInputBindingDescription>    bindingDescriptions;
        std::vector<VkDeviceSize>                                               bindingOffsets;
+       const size_t                                                                    numAttributes           = getNumAttributes();
+       const size_t                                                                    numBindings                     = (m_bindingMapping == BINDING_MAPPING_ONE_TO_ONE) ? numAttributes : ((numAttributes > 1) ? 2 : 1);
+       const VkVertexInputRate                                                 firstInputrate          = getAttributeInfo(0).inputRate;
 
-       for (size_t bindingNdx = 0; bindingNdx < m_attributeInfos.size() * 2; ++bindingNdx)
+       for (size_t bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
        {
-               // Use STEP_RATE_VERTEX in even bindings and STEP_RATE_INSTANCE in odd bindings
-               const VkVertexInputRate                                         inputRate                       = (bindingNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
+               // Bindings alternate between STEP_RATE_VERTEX and STEP_RATE_INSTANCE
+               const VkVertexInputRate                                         inputRate                       = ((firstInputrate + bindingNdx) % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
 
                // Stride will be updated when creating the attribute descriptions
                const VkVertexInputBindingDescription           bindingDescription      =
@@ -360,22 +411,22 @@ TestInstance* VertexInputTest::createInstance (Context& context) const
 
        // To place the attributes sequentially we need to know the largest attribute and use its size in stride and offset calculations.
        if (m_attributeLayout == ATTRIBUTE_LAYOUT_SEQUENTIAL)
-               for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); ++attributeNdx)
+               for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
                {
-                       const AttributeInfo&    attributeInfo                   = m_attributeInfos[attributeNdx];
-                       const deUint32                  attributeBinding                = getAttributeBinding(m_bindingMapping, attributeInfo.inputRate, static_cast<deUint32>(attributeNdx));
+                       const AttributeInfo&    attributeInfo                   = getAttributeInfo(attributeNdx);
+                       const deUint32                  attributeBinding                = getAttributeBinding(m_bindingMapping, firstInputrate, attributeInfo.inputRate, static_cast<deUint32>(attributeNdx));
                        const deUint32                  inputSize                               = getVertexFormatSize(attributeInfo.vkType);
 
                        attributeMaxSizes[attributeBinding]                             = de::max(attributeMaxSizes[attributeBinding], inputSize);
                }
 
        // Create attribute descriptions, assign them to bindings and update stride.
-       for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); ++attributeNdx)
+       for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
        {
-               const AttributeInfo&            attributeInfo                   = m_attributeInfos[attributeNdx];
+               const AttributeInfo&            attributeInfo                   = getAttributeInfo(attributeNdx);
                const GlslTypeDescription&      glslTypeDescription             = s_glslTypeDescriptions[attributeInfo.glslType];
                const deUint32                          inputSize                               = getVertexFormatSize(attributeInfo.vkType);
-               const deUint32                          attributeBinding                = getAttributeBinding(m_bindingMapping, attributeInfo.inputRate, static_cast<deUint32>(attributeNdx));
+               const deUint32                          attributeBinding                = getAttributeBinding(m_bindingMapping, firstInputrate, attributeInfo.inputRate, static_cast<deUint32>(attributeNdx));
                const deUint32                          vertexCount                             = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? (4 * 2) : 2;
 
                VertexInputAttributeDescription attributeDescription =
@@ -431,6 +482,21 @@ TestInstance* VertexInputTest::createInstance (Context& context) const
                        bindingDescriptions[bindingNdx].stride += getNextMultipleOffset(attributeMaxSizes[bindingNdx], bindingDescriptions[bindingNdx].stride);
        }
 
+       // Check upfront for maximum number of vertex input bindings
+       {
+               const InstanceInterface&                vki                             = context.getInstanceInterface();
+               const VkPhysicalDevice                  physDevice              = context.getPhysicalDevice();
+               const VkPhysicalDeviceLimits    limits                  = getPhysicalDeviceProperties(vki, physDevice).limits;
+
+               const deUint32                                  maxBindings             = limits.maxVertexInputBindings;
+
+               if (bindingDescriptions.size() > maxBindings)
+               {
+                       const std::string notSupportedStr = "Unsupported number of vertex input bindings, maxVertexInputBindings: " + de::toString(maxBindings);
+                       TCU_THROW(NotSupportedError, notSupportedStr.c_str());
+               }
+       }
+
        return new VertexInputInstance(context, attributeDescriptions, bindingDescriptions, bindingOffsets);
 }
 
@@ -439,6 +505,7 @@ void VertexInputTest::initPrograms (SourceCollections& programCollection) const
        std::ostringstream vertexSrc;
 
        vertexSrc << "#version 440\n"
+                         << "layout(constant_id = 0) const int numAttributes = " << m_maxAttributes << ";\n"
                          << getGlslInputDeclarations()
                          << "layout(location = 0) out highp vec4 vtxColor;\n"
                          << "out gl_PerVertex {\n"
@@ -471,12 +538,20 @@ std::string VertexInputTest::getGlslInputDeclarations (void) const
        std::ostringstream      glslInputs;
        deUint32                        location = 0;
 
-       for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+       if (m_queryMaxAttributes)
        {
-               const GlslTypeDescription& glslTypeDesc = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType];
+               const GlslTypeDescription& glslTypeDesc = s_glslTypeDescriptions[GLSL_TYPE_VEC4];
+               glslInputs << "layout(location = 0) in " << glslTypeDesc.name << " attr[numAttributes];\n";
+       }
+       else
+       {
+               for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+               {
+                       const GlslTypeDescription& glslTypeDesc = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType];
 
-               glslInputs << "layout(location = " << location << ") in " << glslTypeDesc.name << " attr" << attributeNdx << ";\n";
-               location += glslTypeDesc.vertexInputCount;
+                       glslInputs << "layout(location = " << location << ") in " << glslTypeDesc.name << " attr" << attributeNdx << ";\n";
+                       location += glslTypeDesc.vertexInputCount;
+               }
        }
 
        return glslInputs.str();
@@ -487,61 +562,112 @@ std::string VertexInputTest::getGlslVertexCheck (void) const
        std::ostringstream      glslCode;
        int                                     totalInputComponentCount        = 0;
 
-
        glslCode << "   int okCount = 0;\n";
 
-       for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+       if (m_queryMaxAttributes)
        {
-               glslCode << getGlslAttributeConditions(m_attributeInfos[attributeNdx], (deUint32)attributeNdx);
-
-               const int vertexInputCount      = VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputCount;
-               totalInputComponentCount        += vertexInputCount * VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputComponentCount;
+               const AttributeInfo attributeInfo = getAttributeInfo(0);
+
+               glslCode << "   for (int checkNdx = 0; checkNdx < numAttributes; checkNdx++)\n"
+                                <<     "       {\n"
+                                << "           uint index = (checkNdx % 2 == 0) ? gl_VertexIndex : gl_InstanceIndex;\n";
+
+               glslCode << getGlslAttributeConditions(attributeInfo, "checkNdx")
+                                << "   }\n";
+
+                       const int vertexInputCount      = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
+                       totalInputComponentCount        += vertexInputCount * VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
+
+               glslCode <<
+                       "       if (okCount == " << totalInputComponentCount << " * numAttributes)\n"
+                       "       {\n"
+                       "               if (gl_InstanceIndex == 0)\n"
+                       "                       vtxColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
+                       "               else\n"
+                       "                       vtxColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+                       "       }\n"
+                       "       else\n"
+                       "       {\n"
+                       "               vtxColor = vec4(okCount / float(" << totalInputComponentCount << " * numAttributes), 0.0f, 0.0f, 1.0);\n" <<
+                       "       }\n\n"
+                       "       if (gl_InstanceIndex == 0)\n"
+                       "       {\n"
+                       "               if (gl_VertexIndex == 0) gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 1) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 2) gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 3) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+                       "               else gl_Position = vec4(0.0);\n"
+                       "       }\n"
+                       "       else\n"
+                       "       {\n"
+                       "               if (gl_VertexIndex == 0) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 1) gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 2) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 3) gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
+                       "               else gl_Position = vec4(0.0);\n"
+                       "       }\n";
        }
+       else
+       {
+               for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
+               {
+                       glslCode << getGlslAttributeConditions(m_attributeInfos[attributeNdx], de::toString(attributeNdx));
 
-       glslCode <<
-               "       if (okCount == " << totalInputComponentCount << ")\n"
-               "       {\n"
-               "               if (gl_InstanceIndex == 0)\n"
-               "                       vtxColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
-               "               else\n"
-               "                       vtxColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
-               "       }\n"
-               "       else\n"
-               "       {\n"
-               "               vtxColor = vec4(okCount / float(" << totalInputComponentCount << "), 0.0f, 0.0f, 1.0);\n" <<
-               "       }\n\n"
-               "       if (gl_InstanceIndex == 0)\n"
-               "       {\n"
-               "               if (gl_VertexIndex == 0) gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
-               "               else if (gl_VertexIndex == 1) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
-               "               else if (gl_VertexIndex == 2) gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
-               "               else if (gl_VertexIndex == 3) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
-               "               else gl_Position = vec4(0.0);\n"
-               "       }\n"
-               "       else\n"
-               "       {\n"
-               "               if (gl_VertexIndex == 0) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
-               "               else if (gl_VertexIndex == 1) gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
-               "               else if (gl_VertexIndex == 2) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
-               "               else if (gl_VertexIndex == 3) gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
-               "               else gl_Position = vec4(0.0);\n"
-               "       }\n";
+                       const int vertexInputCount      = VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputCount;
+                       totalInputComponentCount        += vertexInputCount * VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputComponentCount;
+               }
 
+               glslCode <<
+                       "       if (okCount == " << totalInputComponentCount << ")\n"
+                       "       {\n"
+                       "               if (gl_InstanceIndex == 0)\n"
+                       "                       vtxColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
+                       "               else\n"
+                       "                       vtxColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+                       "       }\n"
+                       "       else\n"
+                       "       {\n"
+                       "               vtxColor = vec4(okCount / float(" << totalInputComponentCount << "), 0.0f, 0.0f, 1.0);\n" <<
+                       "       }\n\n"
+                       "       if (gl_InstanceIndex == 0)\n"
+                       "       {\n"
+                       "               if (gl_VertexIndex == 0) gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 1) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 2) gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 3) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+                       "               else gl_Position = vec4(0.0);\n"
+                       "       }\n"
+                       "       else\n"
+                       "       {\n"
+                       "               if (gl_VertexIndex == 0) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 1) gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 2) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
+                       "               else if (gl_VertexIndex == 3) gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
+                       "               else gl_Position = vec4(0.0);\n"
+                       "       }\n";
+       }
        return glslCode.str();
 }
 
-std::string VertexInputTest::getGlslAttributeConditions (const AttributeInfo& attributeInfo, deUint32 attributeIndex) const
+std::string VertexInputTest::getGlslAttributeConditions (const AttributeInfo& attributeInfo, const std::string attributeIndex) const
 {
        std::ostringstream      glslCode;
        std::ostringstream      attributeVar;
-       const std::string       indexId                         = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? "gl_VertexIndex" : "gl_InstanceIndex";
        const int                       componentCount          = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
        const int                       vertexInputCount        = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
        const deUint32          totalComponentCount     = componentCount * vertexInputCount;
        const tcu::Vec4         threshold                       = getFormatThreshold(attributeInfo.vkType);
        deUint32                        componentIndex          = 0;
+       const std::string       indexStr                        = m_queryMaxAttributes ? "[" + attributeIndex + "]" : attributeIndex;
+       const std::string       indentStr                       = m_queryMaxAttributes ? "\t\t" : "\t";
+       std::string                     indexId;
+
+       if (m_queryMaxAttributes)
+               indexId = "index";
+       else
+               indexId = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? "gl_VertexIndex" : "gl_InstanceIndex";
 
-       attributeVar << "attr" << attributeIndex;
+       attributeVar << "attr" << indexStr;
 
        glslCode << std::fixed;
 
@@ -570,49 +696,49 @@ std::string VertexInputTest::getGlslAttributeConditions (const AttributeInfo& at
 
                        if (isVertexFormatSint(attributeInfo.vkType))
                        {
-                               glslCode << "\tif (" << accessStr << " == -(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
+                               glslCode << indentStr <<  "if (" << accessStr << " == -(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
                        }
                        else if (isVertexFormatUint(attributeInfo.vkType))
                        {
-                               glslCode << "\tif (" << accessStr << " == uint(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
+                               glslCode << indentStr << "if (" << accessStr << " == uint(" << totalComponentCount << " * " << indexId << " + " << componentIndex << "))\n";
                        }
                        else if (isVertexFormatSfloat(attributeInfo.vkType))
                        {
                                if (VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType == VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
                                {
-                                       glslCode << "\tif (abs(" << accessStr << " + double(0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double(" << threshold[rowNdx] << "))\n";
+                                       glslCode << indentStr << "if (abs(" << accessStr << " + double(0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double(" << threshold[rowNdx] << "))\n";
                                }
                                else
                                {
-                                       glslCode << "\tif (abs(" << accessStr << " + (0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+                                       glslCode << indentStr << "if (abs(" << accessStr << " + (0.01 * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
                                }
                        }
                        else if (isVertexFormatSscaled(attributeInfo.vkType))
                        {
-                               glslCode << "\tif (abs(" << accessStr << " + (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
+                               glslCode << indentStr << "if (abs(" << accessStr << " + (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
                        }
                        else if (isVertexFormatUscaled(attributeInfo.vkType))
                        {
-                               glslCode << "\t if (abs(" << accessStr << " - (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
+                               glslCode << indentStr << "if (abs(" << accessStr << " - (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < " << threshold[rowNdx] << ")\n";
                        }
                        else if (isVertexFormatSnorm(attributeInfo.vkType))
                        {
                                const float representableDiff = getRepresentableDifferenceSnorm(attributeInfo.vkType);
 
-                               glslCode << "\tif (abs(" << accessStr << " - (-1.0 + " << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+                               glslCode << indentStr << "if (abs(" << accessStr << " - (-1.0 + " << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
                        }
                        else if (isVertexFormatUnorm(attributeInfo.vkType) || isVertexFormatSRGB(attributeInfo.vkType))
                        {
                                const float representableDiff = getRepresentableDifferenceUnorm(attributeInfo.vkType);
 
-                               glslCode << "\tif (abs(" << accessStr << " - " << "(" << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
+                               glslCode << indentStr << "if (abs(" << accessStr << " - " << "(" << representableDiff << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
                        }
                        else
                        {
                                DE_ASSERT(false);
                        }
 
-                       glslCode << "\t\tokCount++;\n\n";
+                       glslCode << indentStr << "\tokCount++;\n\n";
 
                        componentIndex++;
                }
@@ -811,6 +937,23 @@ VertexInputInstance::VertexInputInstance (Context&                                                                                         context,
        m_vertexShaderModule    = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_vert"), 0);
        m_fragmentShaderModule  = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_frag"), 0);
 
+       // Create specialization constant
+       deUint32 specializationData = static_cast<deUint32>(attributeDescriptions.size());
+
+       const VkSpecializationMapEntry specializationMapEntry =
+       {
+               0,                                                                                                              // uint32_t                                                     constantID
+               0,                                                                                                              // uint32_t                                                     offset
+               sizeof(specializationData),                                                             // uint32_t                                                     size
+       };
+
+       const VkSpecializationInfo specializationInfo =
+       {
+               1,                                                                                                              // uint32_t                                                     mapEntryCount
+               &specializationMapEntry,                                                                // const void*                                          pMapEntries
+               sizeof(specializationData),                                                             // size_t                                                       dataSize
+               &specializationData                                                                             // const void*                                          pData
+       };
 
        // Create pipeline
        {
@@ -823,7 +966,7 @@ VertexInputInstance::VertexInputInstance (Context&                                                                                          context,
                                VK_SHADER_STAGE_VERTEX_BIT,                                                                     // VkShaderStageFlagBits                                stage;
                                *m_vertexShaderModule,                                                                          // VkShaderModule                                               module;
                                "main",                                                                                                         // const char*                                                  pName;
-                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                               &specializationInfo                                                                                     // const VkSpecializationInfo*                  pSpecializationInfo;
                        },
                        {
                                VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
@@ -1700,12 +1843,111 @@ void createMultipleAttributeTests (tcu::TestCaseGroup* multipleAttributeTests)
        multipleAttributeTests->addChild(bindingOneToManyTests.release());
 }
 
+void createMaxAttributeTests (tcu::TestCaseGroup* maxAttributeTests)
+{
+       // Required vertex formats, unpacked
+       const VkFormat                                  vertexFormats[]         =
+       {
+               VK_FORMAT_R8_UNORM,
+               VK_FORMAT_R8_SNORM,
+               VK_FORMAT_R8_UINT,
+               VK_FORMAT_R8_SINT,
+               VK_FORMAT_R8G8_UNORM,
+               VK_FORMAT_R8G8_SNORM,
+               VK_FORMAT_R8G8_UINT,
+               VK_FORMAT_R8G8_SINT,
+               VK_FORMAT_R8G8B8A8_UNORM,
+               VK_FORMAT_R8G8B8A8_SNORM,
+               VK_FORMAT_R8G8B8A8_UINT,
+               VK_FORMAT_R8G8B8A8_SINT,
+               VK_FORMAT_B8G8R8A8_UNORM,
+               VK_FORMAT_R16_UNORM,
+               VK_FORMAT_R16_SNORM,
+               VK_FORMAT_R16_UINT,
+               VK_FORMAT_R16_SINT,
+               VK_FORMAT_R16_SFLOAT,
+               VK_FORMAT_R16G16_UNORM,
+               VK_FORMAT_R16G16_SNORM,
+               VK_FORMAT_R16G16_UINT,
+               VK_FORMAT_R16G16_SINT,
+               VK_FORMAT_R16G16_SFLOAT,
+               VK_FORMAT_R16G16B16A16_UNORM,
+               VK_FORMAT_R16G16B16A16_SNORM,
+               VK_FORMAT_R16G16B16A16_UINT,
+               VK_FORMAT_R16G16B16A16_SINT,
+               VK_FORMAT_R16G16B16A16_SFLOAT,
+               VK_FORMAT_R32_UINT,
+               VK_FORMAT_R32_SINT,
+               VK_FORMAT_R32_SFLOAT,
+               VK_FORMAT_R32G32_UINT,
+               VK_FORMAT_R32G32_SINT,
+               VK_FORMAT_R32G32_SFLOAT,
+               VK_FORMAT_R32G32B32_UINT,
+               VK_FORMAT_R32G32B32_SINT,
+               VK_FORMAT_R32G32B32_SFLOAT,
+               VK_FORMAT_R32G32B32A32_UINT,
+               VK_FORMAT_R32G32B32A32_SINT,
+               VK_FORMAT_R32G32B32A32_SFLOAT
+       };
+
+       // VkPhysicalDeviceLimits::maxVertexInputAttributes is used when attributeCount is 0
+       const deUint32                                  attributeCount[]        = { 16, 32, 64, 128, 0 };
+       tcu::TestContext&                               testCtx                         (maxAttributeTests->getTestContext());
+       de::Random                                              randomFunc                      (132030);
+
+       // Find compatible VK formats for each GLSL vertex type
+       CompatibleFormats compatibleFormats[VertexInputTest::GLSL_TYPE_COUNT];
+       {
+               for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
+               {
+                       for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
+                       {
+                               if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
+                                       compatibleFormats[glslTypeNdx].compatibleVkFormats.push_back(vertexFormats[formatNdx]);
+                       }
+               }
+       }
+
+       for (deUint32 attributeCountNdx = 0; attributeCountNdx < DE_LENGTH_OF_ARRAY(attributeCount); attributeCountNdx++)
+       {
+               const std::string                                                       groupName = (attributeCount[attributeCountNdx] == 0 ? "query_max" : de::toString(attributeCount[attributeCountNdx])) + "_attributes";
+               const std::string                                                       groupDesc = de::toString(attributeCount[attributeCountNdx]) + " vertex input attributes";
+
+               de::MovePtr<tcu::TestCaseGroup>                         numAttributeTests(new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupDesc.c_str()));
+               de::MovePtr<tcu::TestCaseGroup>                         bindingOneToOneTests(new tcu::TestCaseGroup(testCtx, "binding_one_to_one", "Each attribute uses a unique binding"));
+               de::MovePtr<tcu::TestCaseGroup>                         bindingOneToManyTests(new tcu::TestCaseGroup(testCtx, "binding_one_to_many", "Attributes share the same binding"));
+
+               std::vector<VertexInputTest::AttributeInfo>     attributeInfos(attributeCount[attributeCountNdx]);
+
+               for (deUint32 attributeNdx = 0; attributeNdx < attributeCount[attributeCountNdx]; attributeNdx++)
+               {
+                       // Use random glslTypes, each consuming one attribute location
+                       const VertexInputTest::GlslType glslType        = (VertexInputTest::GlslType)(randomFunc.getUint32() % VertexInputTest::GLSL_TYPE_MAT2);
+                       const std::vector<VkFormat>&    formats         = compatibleFormats[glslType].compatibleVkFormats;
+                       const VkFormat                                  format          = formats[randomFunc.getUint32() % formats.size()];
+
+                       attributeInfos[attributeNdx].glslType           = glslType;
+                       attributeInfos[attributeNdx].inputRate          = ((attributeCountNdx + attributeNdx) % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
+                       attributeInfos[attributeNdx].vkType                     = format;
+               }
+
+               bindingOneToOneTests->addChild(new VertexInputTest(testCtx, "interleaved", "Interleaved attribute layout", attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
+               bindingOneToManyTests->addChild(new VertexInputTest(testCtx, "interleaved", "Interleaved attribute layout", attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_MANY, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
+               bindingOneToManyTests->addChild(new VertexInputTest(testCtx, "sequential", "Sequential attribute layout", attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_MANY, VertexInputTest::ATTRIBUTE_LAYOUT_SEQUENTIAL));
+
+               numAttributeTests->addChild(bindingOneToOneTests.release());
+               numAttributeTests->addChild(bindingOneToManyTests.release());
+               maxAttributeTests->addChild(numAttributeTests.release());
+       }
+}
+
 } // anonymous
 
 void createVertexInputTests (tcu::TestCaseGroup* vertexInputTests)
 {
        addTestGroup(vertexInputTests, "single_attribute", "Uses one attribute", createSingleAttributeTests);
        addTestGroup(vertexInputTests, "multiple_attributes", "Uses more than one attribute", createMultipleAttributeTests);
+       addTestGroup(vertexInputTests, "max_attributes", "Implementations can use as many vertex input attributes as they advertise", createMaxAttributeTests);
 }
 
 } // pipeline
index ba1abddf850c541b0579952384373d7b1c5fff4b..310f2481031535ac85edfff1ad802e0bfcec82c3 100644 (file)
@@ -138307,6 +138307,21 @@ dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes
 dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes_sequential.vec4.mat2.mat4
 dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes_sequential.vec4.mat3.mat4
 dEQP-VK.pipeline.vertex_input.multiple_attributes.binding_one_to_many.attributes_sequential.mat2.mat3.mat4
+dEQP-VK.pipeline.vertex_input.max_attributes.16_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.16_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.16_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.32_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.32_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.32_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.64_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.64_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.64_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.128_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.128_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.128_attributes.binding_one_to_many.sequential
+dEQP-VK.pipeline.vertex_input.max_attributes.query_max_attributes.binding_one_to_one.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.query_max_attributes.binding_one_to_many.interleaved
+dEQP-VK.pipeline.vertex_input.max_attributes.query_max_attributes.binding_one_to_many.sequential
 dEQP-VK.pipeline.input_assembly.primitive_topology.point_list
 dEQP-VK.pipeline.input_assembly.primitive_topology.line_list
 dEQP-VK.pipeline.input_assembly.primitive_topology.line_strip