• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  * Copyright (c) 2023 Google Inc.
7  * Copyright (c) 2023 LunarG, Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Dynamic vertex attribute tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineDynamicVertexAttributeTests.hpp"
27 #include "vktPipelineClearUtil.hpp"
28 #include "vktPipelineExtendedDynamicStateTests.hpp"
29 
30 #include "vktCustomInstancesDevices.hpp"
31 #include "vktTestCase.hpp"
32 
33 #include "vkImageUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38 
39 #include "tcuCommandLine.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuTextureUtil.hpp"
43 
44 #include <array>
45 #include <set>
46 
47 namespace vkt
48 {
49 namespace pipeline
50 {
51 
52 namespace
53 {
54 
makeVertexInputAttributeDescription2EXT(uint32_t location,uint32_t binding,vk::VkFormat format,uint32_t offset)55 vk::VkVertexInputAttributeDescription2EXT makeVertexInputAttributeDescription2EXT(uint32_t location, uint32_t binding,
56                                                                                   vk::VkFormat format, uint32_t offset)
57 {
58     vk::VkVertexInputAttributeDescription2EXT desc = vk::initVulkanStructure();
59 
60     desc.location = location;
61     desc.binding  = binding;
62     desc.format   = format;
63     desc.offset   = offset;
64 
65     return desc;
66 }
67 
makeVertexInputBindingDescription2EXT(uint32_t binding,uint32_t stride,vk::VkVertexInputRate inputRate)68 vk::VkVertexInputBindingDescription2EXT makeVertexInputBindingDescription2EXT(uint32_t binding, uint32_t stride,
69                                                                               vk::VkVertexInputRate inputRate)
70 {
71     vk::VkVertexInputBindingDescription2EXT desc = vk::initVulkanStructure();
72 
73     desc.binding   = binding;
74     desc.stride    = stride;
75     desc.inputRate = inputRate;
76     desc.divisor   = 1u;
77 
78     return desc;
79 }
80 
makeImageCreateInfo(const tcu::IVec2 & size,const vk::VkFormat format,const vk::VkImageUsageFlags usage)81 vk::VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const vk::VkFormat format,
82                                           const vk::VkImageUsageFlags usage)
83 {
84     const vk::VkImageCreateInfo imageParams = {
85         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
86         nullptr,                                 // const void* pNext;
87         (vk::VkImageCreateFlags)0u,              // VkImageCreateFlags flags;
88         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
89         format,                                  // VkFormat format;
90         vk::makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
91         1u,                                      // uint32_t mipLevels;
92         1u,                                      // uint32_t arrayLayers;
93         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
94         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
95         usage,                                   // VkImageUsageFlags usage;
96         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
97         0u,                                      // uint32_t queueFamilyIndexCount;
98         nullptr,                                 // const uint32_t* pQueueFamilyIndices;
99         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
100     };
101 
102     return imageParams;
103 }
104 
createDynamicVertexStateDevice(Context & context,const uint32_t testQueueFamilyIndex,const vk::PipelineConstructionType pipelineConstructionType,std::vector<std::string> & deviceExtensions)105 vk::Move<vk::VkDevice> createDynamicVertexStateDevice(Context &context, const uint32_t testQueueFamilyIndex,
106                                                       const vk::PipelineConstructionType pipelineConstructionType,
107                                                       std::vector<std::string> &deviceExtensions)
108 {
109     DE_UNREF(pipelineConstructionType);
110 
111     void *pNext = nullptr;
112 
113 #ifndef CTS_USES_VULKANSC
114     vk::VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT graphicsPipelineFeatures{
115         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT, // VkStructureType sType;
116         pNext,                                                                        // void* pNext;
117         VK_TRUE, // VkBool32 graphicsPipelineLibrary;
118     };
119 
120     if (vk::isConstructionTypeLibrary(pipelineConstructionType))
121     {
122         pNext = &graphicsPipelineFeatures;
123         deviceExtensions.push_back("VK_KHR_pipeline_library");
124         deviceExtensions.push_back("VK_EXT_graphics_pipeline_library");
125     }
126     vk::VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeatures{
127         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR, // VkStructureType sType;
128         pNext,                                                                // void* pNext;
129         VK_TRUE,                                                              // VkBool32 dynamicRendering;
130     };
131     vk::VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures{
132         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, // VkStructureType sType;
133         &dynamicRenderingFeatures,                                        // void* pNext;
134         VK_TRUE,                                                          // VkBool32 shaderObject;
135     };
136 
137     if (vk::isConstructionTypeShaderObject(pipelineConstructionType))
138     {
139         pNext = &shaderObjectFeatures;
140         if (!vk::isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_dynamic_rendering"))
141         {
142             deviceExtensions.push_back("VK_KHR_dynamic_rendering");
143             if (!vk::isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_create_renderpass2"))
144                 deviceExtensions.push_back("VK_KHR_create_renderpass2");
145             if (!vk::isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_depth_stencil_resolve"))
146                 deviceExtensions.push_back("VK_KHR_depth_stencil_resolve");
147             if (!vk::isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_maintenance2"))
148                 deviceExtensions.push_back("VK_KHR_maintenance2");
149         }
150         deviceExtensions.push_back("VK_EXT_shader_object");
151     }
152 #endif
153 
154     vk::VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT dynamicVertexState{
155         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT, // VkStructureType sType;
156         pNext,                                                                         // void* pNext;
157         VK_TRUE, // VkBool32 vertexInputDynamicState;
158     };
159 
160     deviceExtensions.push_back("VK_EXT_vertex_input_dynamic_state");
161 
162     vk::VkPhysicalDeviceFeatures2 physDeviceFeats2 = context.getDeviceFeatures2();
163 
164     physDeviceFeats2.features = context.getDeviceFeatures();
165     physDeviceFeats2.pNext    = &dynamicVertexState;
166 
167     const float queuePriority = 1.0f;
168 
169     const vk::VkDeviceQueueCreateInfo queueParams = {
170         vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
171         nullptr,                                        // const void* pNext;
172         0u,                                             // VkDeviceQueueCreateFlags flags;
173         testQueueFamilyIndex,                           // uint32_t queueFamilyIndex;
174         1u,                                             // uint32_t queueCount;
175         &queuePriority                                  // const float* pQueuePriorities;
176     };
177 
178     std::vector<const char *> extensionPtrs;
179     for (const auto &ext : deviceExtensions)
180         extensionPtrs.push_back(ext.c_str());
181 
182     const vk::VkDeviceCreateInfo deviceInfo = {
183         vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
184         &physDeviceFeats2,                        // const void* pNext;
185         0u,                                       // VkDeviceCreateFlags flags;
186         1u,                                       // uint32_t queueCreateInfoCount;
187         &queueParams,                             // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
188         0u,                                       // uint32_t enabledLayerCount;
189         nullptr,                                  // const char* const* ppEnabledLayerNames;
190         (uint32_t)extensionPtrs.size(),           // uint32_t enabledExtensionCount;
191         extensionPtrs.data(),                     // const char* const* ppEnabledExtensionNames;
192         NULL                                      // const VkPhysicalDeviceFeatures* pEnabledFeatures;
193     };
194 
195     return createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
196                               context.getPlatformInterface(), context.getInstance(), context.getInstanceInterface(),
197                               context.getPhysicalDevice(), &deviceInfo);
198 }
199 
200 class NonSequentialInstance : public TestInstance
201 {
202 public:
NonSequentialInstance(Context & context,const vk::PipelineConstructionType pipelineConstructionType,const uint32_t numInstances,const std::vector<uint32_t> attributeLocations)203     NonSequentialInstance(Context &context, const vk::PipelineConstructionType pipelineConstructionType,
204                           const uint32_t numInstances, const std::vector<uint32_t> attributeLocations)
205         : TestInstance(context)
206         , m_pipelineConstructionType(pipelineConstructionType)
207         , m_numInstances(numInstances)
208         , m_attributeLocations(attributeLocations)
209     {
210     }
211 
~NonSequentialInstance()212     ~NonSequentialInstance()
213     {
214     }
215 
216     virtual tcu::TestStatus iterate(void);
217 
218 private:
219     struct VertexInfo
220     {
221         tcu::Vec4 position;
222         tcu::Vec4 color;
223     };
224 
225     const vk::PipelineConstructionType m_pipelineConstructionType;
226     const uint32_t m_numInstances;
227     const std::vector<uint32_t> m_attributeLocations;
228 };
229 
iterate(void)230 tcu::TestStatus NonSequentialInstance::iterate(void)
231 {
232     tcu::TestLog &log                              = m_context.getTestContext().getLog();
233     const vk::PlatformInterface &vkp               = m_context.getPlatformInterface();
234     const vk::VkInstance vki                       = m_context.getInstance();
235     const vk::InstanceInterface &instanceInterface = m_context.getInstanceInterface();
236     const uint32_t queueFamilyIndex                = m_context.getUniversalQueueFamilyIndex();
237     const vk::VkPhysicalDevice physicalDevice      = m_context.getPhysicalDevice();
238     std::vector<std::string> deviceExtensions;
239     const vk::Move<vk::VkDevice> device =
240         createDynamicVertexStateDevice(m_context, queueFamilyIndex, m_pipelineConstructionType, deviceExtensions);
241     const vk::DeviceDriver vk(vkp, vki, *device, m_context.getUsedApiVersion(),
242                               m_context.getTestContext().getCommandLine());
243     vk::SimpleAllocator allocator(
244         vk, *device,
245         getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
246     const vk::VkQueue queue = getDeviceQueue(vk, *device, queueFamilyIndex, 0u);
247 
248     // Create shaders
249     const std::array<vk::ShaderWrapper, 2> vertexShaderModules = {
250         vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_0")),
251         vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_1"))};
252 
253     const vk::ShaderWrapper fragmentShaderModule =
254         vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("frag"));
255 
256     const uint32_t vertexBufferBindIndex = 0u;
257 
258     // Vertex input state and binding
259     const vk::VkVertexInputBindingDescription2EXT bindingDescription2EXT = makeVertexInputBindingDescription2EXT(
260         vertexBufferBindIndex, sizeof(VertexInfo), vk::VK_VERTEX_INPUT_RATE_VERTEX);
261 
262     const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXTGreens{
263         makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
264         makeVertexInputAttributeDescription2EXT(m_attributeLocations[0], vertexBufferBindIndex,
265                                                 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
266 
267     const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXT2Reds{
268         makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
269         makeVertexInputAttributeDescription2EXT(m_attributeLocations[1], vertexBufferBindIndex,
270                                                 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
271 
272     const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
273         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
274         nullptr,                                                       // const void* pNext;
275         (vk::VkPipelineVertexInputStateCreateFlags)0u,                 // VkPipelineVertexInputStateCreateFlags flags;
276         0u,                                                            // uint32_t vertexBindingDescriptionCount;
277         nullptr, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
278         0u,      // uint32_t vertexAttributeDescriptionCount;
279         nullptr  // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
280     };
281 
282     vk::Move<vk::VkImage> colorImage =
283         (makeImage(vk, *device,
284                    makeImageCreateInfo(tcu::IVec2(32, 32), vk::VK_FORMAT_R8G8B8A8_UNORM,
285                                        vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
286 
287     // Allocate and bind color image memory
288     const vk::VkImageSubresourceRange colorSubresourceRange =
289         vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
290     const de::UniquePtr<vk::Allocation> colorImageAlloc(
291         bindImage(vk, *device, allocator, *colorImage, vk::MemoryRequirement::Any));
292     vk::Move<vk::VkImageView> colorImageView = (makeImageView(vk, *device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D,
293                                                               vk::VK_FORMAT_R8G8B8A8_UNORM, colorSubresourceRange));
294 
295     // Create renderpass
296     const vk::VkAttachmentDescription attachmentDescription = {
297         (vk::VkAttachmentDescriptionFlags)0u,        // VkAttachmentDescriptionFlags    flags
298         vk::VK_FORMAT_R8G8B8A8_UNORM,                // VkFormat                        format
299         vk::VK_SAMPLE_COUNT_1_BIT,                   // VkSampleCountFlagBits        samples
300         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,             // VkAttachmentLoadOp            loadOp
301         vk::VK_ATTACHMENT_STORE_OP_STORE,            // VkAttachmentStoreOp            storeOp
302         vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,         // VkAttachmentLoadOp            stencilLoadOp
303         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,        // VkAttachmentStoreOp            stencilStoreOp
304         vk::VK_IMAGE_LAYOUT_UNDEFINED,               // VkImageLayout                initialLayout
305         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout                finalLayout
306     };
307 
308     const vk::VkAttachmentReference attachmentReference = {
309         0u,                                          // uint32_t            attachment
310         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout    layout
311     };
312 
313     const vk::VkSubpassDescription subpassDescription = {
314         (vk::VkSubpassDescriptionFlags)0u,   // VkSubpassDescriptionFlags    flags
315         vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint            pipelineBindPoint
316         0u,                                  // uint32_t                        inputAttachmentCount
317         nullptr,                             // const VkAttachmentReference*    pInputAttachments
318         1u,                                  // uint32_t                        colorAttachmentCount
319         &attachmentReference,                // const VkAttachmentReference*    pColorAttachments
320         nullptr,                             // const VkAttachmentReference*    pResolveAttachments
321         nullptr,                             // const VkAttachmentReference*    pDepthStencilAttachment
322         0u,                                  // uint32_t                        preserveAttachmentCount
323         nullptr                              // const uint32_t*                pPreserveAttachments
324     };
325 
326     const vk::VkRenderPassCreateInfo renderPassInfo = {
327         vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureTypei                    sType
328         nullptr,                                       // const void*                        pNext
329         (vk::VkRenderPassCreateFlags)0u,               // VkRenderPassCreateFlags            flags
330         1u,                                            // uint32_t                            attachmentCount
331         &attachmentDescription,                        // const VkAttachmentDescription*    pAttachments
332         1u,                                            // uint32_t                            subpassCount
333         &subpassDescription,                           // const VkSubpassDescription*        pSubpasses
334         0u,                                            // uint32_t                            dependencyCount
335         nullptr                                        // const VkSubpassDependency*        pDependencies
336     };
337 
338     vk::RenderPassWrapper renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, vk, *device, &renderPassInfo);
339 
340     // Create framebuffer
341     const vk::VkImageView attachmentBindInfos[] = {*colorImageView};
342 
343     const vk::VkFramebufferCreateInfo framebufferCreateInfo = {
344         vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
345         nullptr,                                       // const void* pNext;
346         vk::VkFramebufferCreateFlags(0),               // VkFramebufferCreateFlags flags;
347         *renderPass,                                   // VkRenderPass renderPass;
348         1u,                                            // uint32_t attachmentCount;
349         attachmentBindInfos,                           // const VkImageView* pAttachments;
350         32u,                                           // uint32_t width;
351         32u,                                           // uint32_t height;
352         1u                                             // uint32_t layers;
353     };
354 
355     renderPass.createFramebuffer(vk, *device, &framebufferCreateInfo, {*colorImage});
356 
357     std::array<vk::VkDynamicState, 1> dynamicStates{
358         vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT,
359     };
360 
361     vk::VkPipelineDynamicStateCreateInfo pipelineDynamicStateNfo{
362         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
363         nullptr,                                                  // const void* pNext;
364         (vk::VkPipelineDynamicStateCreateFlags)0u,                // VkPipelineDynamicStateCreateFlags flags;
365         static_cast<uint32_t>(dynamicStates.size()),              // uint32_t dynamicStateCount;
366         dynamicStates.data()                                      // const VkDynamicState* pDynamicStates;
367     };
368 
369     // Create pipeline layout
370     const vk::VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
371         vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
372         nullptr,                                           // const void* pNext;
373         0u,                                                // VkPipelineLayoutCreateFlags flags;
374         0u,                                                // uint32_t descriptorSetCount;
375         nullptr,                                           // const VkDescriptorSetLayout* pSetLayouts;
376         0u,                                                // uint32_t pushConstantRangeCount;
377         nullptr                                            // const VkPushDescriptorRange* pPushDescriptorRanges;
378     };
379 
380     vk::PipelineLayoutWrapper pipelineLayout(m_pipelineConstructionType, vk, *device, &pipelineLayoutInfo);
381 
382     // Create graphics pipeline
383     vk::GraphicsPipelineWrapper graphicsPipelines[2]{
384         {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType},
385         {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType}};
386 
387     const vk::VkExtent2D extent = {32, 32};
388     const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(extent));
389     const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(extent));
390 
391     for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
392     {
393         graphicsPipelines[i]
394             .setDefaultDepthStencilState()
395             .setDefaultColorBlendState()
396             .setMonolithicPipelineLayout(pipelineLayout)
397             .setDynamicState(&pipelineDynamicStateNfo)
398             .setDefaultMultisampleState()
399             .setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
400             .setDefaultRasterizationState()
401             .setupVertexInputState(&vertexInputStateCreateInfo)
402             .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u,
403                                               vertexShaderModules[i])
404             .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragmentShaderModule, nullptr, nullptr)
405             .setupFragmentOutputState(*renderPass)
406             .setMonolithicPipelineLayout(pipelineLayout)
407             .buildPipeline();
408     }
409 
410     // Create vertex buffer
411     const uint32_t numVertices                   = 6;
412     const vk::VkDeviceSize vertexBufferSizeBytes = 256;
413 
414     const std::array<vk::Move<vk::VkBuffer>, 2> vertexBuffers = {
415         (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)),
416         (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))};
417 
418     const std::array<de::MovePtr<vk::Allocation>, 2> vertexBufferAllocs = {
419         (bindBuffer(vk, *device, allocator, *vertexBuffers[0], vk::MemoryRequirement::HostVisible)),
420         (bindBuffer(vk, *device, allocator, *vertexBuffers[1], vk::MemoryRequirement::HostVisible))};
421 
422     const uint32_t instanceSize = (uint32_t)sqrt(m_numInstances);
423     const float posIncrement    = 1.0f / (float)m_numInstances * (float)instanceSize;
424 
425     for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
426     {
427         tcu::Vec4 vertexColor       = (i == 0u ? tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f) : tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f));
428         VertexInfo *const pVertices = static_cast<VertexInfo *>(vertexBufferAllocs[i]->getHostPtr());
429 
430         pVertices[0] = {tcu::Vec4(posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
431         pVertices[1] = {tcu::Vec4(-posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
432         pVertices[2] = {tcu::Vec4(-posIncrement, posIncrement, 0.0f, 1.0f), vertexColor};
433         pVertices[3] = {tcu::Vec4(-posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
434         pVertices[4] = {tcu::Vec4(posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
435         pVertices[5] = {tcu::Vec4(posIncrement, -posIncrement, 1.0f, 1.0f), vertexColor};
436 
437         flushAlloc(vk, *device, *vertexBufferAllocs[i]);
438     }
439 
440     // Command buffer
441     const vk::Unique<vk::VkCommandPool> cmdPool(
442         createCommandPool(vk, *device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
443     const vk::Unique<vk::VkCommandBuffer> cmdBuffer(
444         allocateCommandBuffer(vk, *device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
445 
446     const vk::VkDeviceSize vertexBufferOffset = 0u;
447 
448     // Render result buffer
449     const vk::VkDeviceSize colorBufferSizeBytes =
450         static_cast<vk::VkDeviceSize>(tcu::getPixelSize(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)) * 32 * 32);
451     const vk::Unique<vk::VkBuffer> colorBuffer(
452         makeBuffer(vk, *device, colorBufferSizeBytes, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
453     const de::UniquePtr<vk::Allocation> colorBufferAlloc(
454         bindBuffer(vk, *device, allocator, *colorBuffer, vk::MemoryRequirement::HostVisible));
455 
456     const vk::VkClearValue clearColorValue = defaultClearValue(vk::VK_FORMAT_R8G8B8A8_UNORM);
457 
458     beginCommandBuffer(vk, *cmdBuffer);
459 
460     renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, 32u, 32u), clearColorValue);
461 
462     graphicsPipelines[0].bind(*cmdBuffer);
463     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[0].get(), &vertexBufferOffset);
464     vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
465                             static_cast<uint32_t>(vertexInputAttributeDesc2EXTGreens.size()),
466                             vertexInputAttributeDesc2EXTGreens.data());
467     vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
468 
469     graphicsPipelines[1].bind(*cmdBuffer);
470     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[1].get(), &vertexBufferOffset);
471     vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
472                             static_cast<uint32_t>(vertexInputAttributeDesc2EXT2Reds.size()),
473                             vertexInputAttributeDesc2EXT2Reds.data());
474     vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
475 
476     renderPass.end(vk, *cmdBuffer);
477     copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, tcu::IVec2(32, 32),
478                       vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
479 
480     endCommandBuffer(vk, *cmdBuffer);
481 
482     submitCommandsAndWait(vk, *device, queue, *cmdBuffer);
483 
484     // Check result image
485     {
486         tcu::TextureLevel referenceTexture(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM), 32, 32);
487         const tcu::PixelBufferAccess referenceAccess = referenceTexture.getAccess();
488         const int segmentSize                        = static_cast<int32_t>(32u / instanceSize);
489         const int segmentLoc                         = (32 - segmentSize) / 2;
490 
491         tcu::clear(referenceTexture.getAccess(), clearColorValue.color.float32);
492 
493         // Create reference image
494         for (int y = 0; y < segmentSize; ++y)
495         {
496             for (int x = 0; x < segmentSize; ++x)
497             {
498                 // While running test for all offsets, we create a nice gradient-like color for the pixels.
499                 referenceAccess.setPixel(tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), segmentLoc + x, segmentLoc + y);
500             }
501         }
502 
503         invalidateAlloc(vk, *device, *colorBufferAlloc);
504 
505         const tcu::ConstPixelBufferAccess resultPixelAccess(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM),
506                                                             (int)extent.width, (int)extent.height, 1,
507                                                             colorBufferAlloc->getHostPtr());
508 
509         if (!tcu::floatThresholdCompare(log, "color", "Image compare", referenceAccess, resultPixelAccess,
510                                         tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT))
511             return tcu::TestStatus::fail("Rendered image is not correct");
512     }
513 
514     return tcu::TestStatus::pass("Success");
515 }
516 
517 class NonSequentialCase : public vkt::TestCase
518 {
519 public:
NonSequentialCase(tcu::TestContext & testContext,const std::string & name,const vk::PipelineConstructionType pipelineConstructionType,const uint32_t numInstances,const std::vector<uint32_t> attributeLocations)520     NonSequentialCase(tcu::TestContext &testContext, const std::string &name,
521                       const vk::PipelineConstructionType pipelineConstructionType, const uint32_t numInstances,
522                       const std::vector<uint32_t> attributeLocations)
523         : vkt::TestCase(testContext, name)
524         , m_pipelineConstructionType(pipelineConstructionType)
525         , m_numInstances(numInstances)
526         , m_attributeLocations(attributeLocations)
527     {
528     }
529 
~NonSequentialCase(void)530     ~NonSequentialCase(void)
531     {
532     }
533 
534     virtual void checkSupport(Context &context) const override;
535     virtual void initPrograms(vk::SourceCollections &sourceCollections) const override;
536     virtual TestInstance *createInstance(Context &context) const override;
537 
538 private:
539     const vk::PipelineConstructionType m_pipelineConstructionType;
540     const uint32_t m_numInstances;
541     const std::vector<uint32_t> m_attributeLocations;
542 };
543 
checkSupport(Context & context) const544 void NonSequentialCase::checkSupport(Context &context) const
545 {
546     const vk::InstanceInterface &vki      = context.getInstanceInterface();
547     const vk::VkPhysicalDevice physDevice = context.getPhysicalDevice();
548 
549     std::array<std::string, 3> extensions = {"VK_EXT_extended_dynamic_state", "VK_EXT_vertex_input_dynamic_state",
550                                              "VK_EXT_extended_dynamic_state2"};
551 
552     // Check extension support.
553     for (const auto &extension : extensions)
554         context.requireDeviceFunctionality(extension);
555 
556     vk::checkPipelineConstructionRequirements(vki, physDevice, m_pipelineConstructionType);
557 }
558 
initPrograms(vk::SourceCollections & sourceCollections) const559 void NonSequentialCase::initPrograms(vk::SourceCollections &sourceCollections) const
560 {
561     // Vertex
562     {
563         for (size_t i = 0; i < m_attributeLocations.size(); ++i)
564         {
565             std::ostringstream src;
566 
567             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
568                 << "\n"
569                 << "layout(location = 0) in vec4 inPosition;\n"
570                 << "layout(location = " << m_attributeLocations[i] << ") in vec4 inColor;\n"
571                 << "layout(location = 0) out vec4 outColor;\n"
572                 << "\n"
573                 << "void main (void)\n"
574                 << "{\n"
575                 << "    gl_Position = inPosition;\n"
576                 << "    outColor = inColor;\n"
577                 << "}\n";
578 
579             sourceCollections.glslSources.add("vert_" + std::to_string(i)) << glu::VertexSource(src.str());
580         }
581     }
582 
583     // Fragment
584     {
585         std::ostringstream src;
586 
587         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
588             << "\n"
589             << "layout(location = 0) in vec4 inColor;\n"
590             << "layout(location = 0) out vec4 outColor;\n"
591             << "\n"
592             << "void main (void)\n"
593             << "{\n"
594             << "    outColor = inColor;\n"
595             << "}\n";
596 
597         sourceCollections.glslSources.add("frag") << glu::FragmentSource(src.str());
598     }
599 }
600 
createInstance(Context & context) const601 TestInstance *NonSequentialCase::createInstance(Context &context) const
602 {
603     return new NonSequentialInstance(context, m_pipelineConstructionType, m_numInstances, m_attributeLocations);
604 }
605 
606 } // namespace
607 
createDynamicVertexAttributeTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)608 tcu::TestCaseGroup *createDynamicVertexAttributeTests(tcu::TestContext &testCtx,
609                                                       vk::PipelineConstructionType pipelineConstructionType)
610 {
611     de::MovePtr<tcu::TestCaseGroup> nonSequentialTestsGroup(
612         new tcu::TestCaseGroup(testCtx, "dynamic_vertex_attribute"));
613 
614     nonSequentialTestsGroup->addChild(
615         new NonSequentialCase(testCtx, "nonsequential", pipelineConstructionType, 16u, {1u, 7u}));
616 
617     return nonSequentialTestsGroup.release();
618 }
619 
620 } // namespace pipeline
621 } // namespace vkt
622