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