• 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         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::DeviceInterface &vk                  = m_context.getDeviceInterface();
236     const vk::PlatformInterface &vkp               = m_context.getPlatformInterface();
237     const vk::VkInstance vki                       = m_context.getInstance();
238     const vk::InstanceInterface &instanceInterface = m_context.getInstanceInterface();
239     const uint32_t queueFamilyIndex                = m_context.getUniversalQueueFamilyIndex();
240     const vk::VkPhysicalDevice physicalDevice      = m_context.getPhysicalDevice();
241     const vk::Move<vk::VkDevice> device =
242         createDynamicVertexStateDevice(m_context, queueFamilyIndex, m_pipelineConstructionType);
243     vk::SimpleAllocator allocator(
244         vk, *device,
245         getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
246     const vk::DeviceDriver deviceDriver(vkp, vki, *device, m_context.getUsedApiVersion(),
247                                         m_context.getTestContext().getCommandLine());
248     const vk::VkQueue queue      = getDeviceQueue(deviceDriver, *device, queueFamilyIndex, 0u);
249     const auto &deviceExtensions = m_context.getDeviceExtensions();
250 
251     // Create shaders
252     const std::array<vk::ShaderWrapper, 2> vertexShaderModules = {
253         vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_0")),
254         vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("vert_1"))};
255 
256     const vk::ShaderWrapper fragmentShaderModule =
257         vk::ShaderWrapper(vk, *device, m_context.getBinaryCollection().get("frag"));
258 
259     const uint32_t vertexBufferBindIndex = 0u;
260 
261     // Vertex input state and binding
262     const vk::VkVertexInputBindingDescription2EXT bindingDescription2EXT = makeVertexInputBindingDescription2EXT(
263         vertexBufferBindIndex, sizeof(VertexInfo), vk::VK_VERTEX_INPUT_RATE_VERTEX);
264 
265     const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXTGreens{
266         makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
267         makeVertexInputAttributeDescription2EXT(m_attributeLocations[0], vertexBufferBindIndex,
268                                                 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
269 
270     const std::array<vk::VkVertexInputAttributeDescription2EXT, 2> vertexInputAttributeDesc2EXT2Reds{
271         makeVertexInputAttributeDescription2EXT(0, vertexBufferBindIndex, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
272         makeVertexInputAttributeDescription2EXT(m_attributeLocations[1], vertexBufferBindIndex,
273                                                 vk::VK_FORMAT_R32G32B32A32_SFLOAT, uint32_t(sizeof(float)) * 4u)};
274 
275     const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
276         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
277         DE_NULL,                                                       // const void* pNext;
278         (vk::VkPipelineVertexInputStateCreateFlags)0u,                 // VkPipelineVertexInputStateCreateFlags flags;
279         0u,                                                            // uint32_t vertexBindingDescriptionCount;
280         DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
281         0u,      // uint32_t vertexAttributeDescriptionCount;
282         DE_NULL  // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
283     };
284 
285     vk::Move<vk::VkImage> colorImage =
286         (makeImage(vk, *device,
287                    makeImageCreateInfo(tcu::IVec2(32, 32), vk::VK_FORMAT_R8G8B8A8_UNORM,
288                                        vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
289 
290     // Allocate and bind color image memory
291     const vk::VkImageSubresourceRange colorSubresourceRange =
292         vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
293     const de::UniquePtr<vk::Allocation> colorImageAlloc(
294         bindImage(vk, *device, allocator, *colorImage, vk::MemoryRequirement::Any));
295     vk::Move<vk::VkImageView> colorImageView = (makeImageView(vk, *device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D,
296                                                               vk::VK_FORMAT_R8G8B8A8_UNORM, colorSubresourceRange));
297 
298     // Create renderpass
299     const vk::VkAttachmentDescription attachmentDescription = {
300         (vk::VkAttachmentDescriptionFlags)0u,        // VkAttachmentDescriptionFlags    flags
301         vk::VK_FORMAT_R8G8B8A8_UNORM,                // VkFormat                        format
302         vk::VK_SAMPLE_COUNT_1_BIT,                   // VkSampleCountFlagBits        samples
303         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,             // VkAttachmentLoadOp            loadOp
304         vk::VK_ATTACHMENT_STORE_OP_STORE,            // VkAttachmentStoreOp            storeOp
305         vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,         // VkAttachmentLoadOp            stencilLoadOp
306         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,        // VkAttachmentStoreOp            stencilStoreOp
307         vk::VK_IMAGE_LAYOUT_UNDEFINED,               // VkImageLayout                initialLayout
308         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout                finalLayout
309     };
310 
311     const vk::VkAttachmentReference attachmentReference = {
312         0u,                                          // uint32_t            attachment
313         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout    layout
314     };
315 
316     const vk::VkSubpassDescription subpassDescription = {
317         (vk::VkSubpassDescriptionFlags)0u,   // VkSubpassDescriptionFlags    flags
318         vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint            pipelineBindPoint
319         0u,                                  // uint32_t                        inputAttachmentCount
320         DE_NULL,                             // const VkAttachmentReference*    pInputAttachments
321         1u,                                  // uint32_t                        colorAttachmentCount
322         &attachmentReference,                // const VkAttachmentReference*    pColorAttachments
323         DE_NULL,                             // const VkAttachmentReference*    pResolveAttachments
324         DE_NULL,                             // const VkAttachmentReference*    pDepthStencilAttachment
325         0u,                                  // uint32_t                        preserveAttachmentCount
326         DE_NULL                              // const uint32_t*                pPreserveAttachments
327     };
328 
329     const vk::VkRenderPassCreateInfo renderPassInfo = {
330         vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureTypei                    sType
331         DE_NULL,                                       // const void*                        pNext
332         (vk::VkRenderPassCreateFlags)0u,               // VkRenderPassCreateFlags            flags
333         1u,                                            // uint32_t                            attachmentCount
334         &attachmentDescription,                        // const VkAttachmentDescription*    pAttachments
335         1u,                                            // uint32_t                            subpassCount
336         &subpassDescription,                           // const VkSubpassDescription*        pSubpasses
337         0u,                                            // uint32_t                            dependencyCount
338         DE_NULL                                        // const VkSubpassDependency*        pDependencies
339     };
340 
341     vk::RenderPassWrapper renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, vk, *device, &renderPassInfo);
342 
343     // Create framebuffer
344     const vk::VkImageView attachmentBindInfos[] = {*colorImageView};
345 
346     const vk::VkFramebufferCreateInfo framebufferCreateInfo = {
347         vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
348         DE_NULL,                                       // const void* pNext;
349         vk::VkFramebufferCreateFlags(0),               // VkFramebufferCreateFlags flags;
350         *renderPass,                                   // VkRenderPass renderPass;
351         1u,                                            // uint32_t attachmentCount;
352         attachmentBindInfos,                           // const VkImageView* pAttachments;
353         32u,                                           // uint32_t width;
354         32u,                                           // uint32_t height;
355         1u                                             // uint32_t layers;
356     };
357 
358     renderPass.createFramebuffer(vk, *device, &framebufferCreateInfo, {*colorImage});
359 
360     std::array<vk::VkDynamicState, 1> dynamicStates{
361         vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT,
362     };
363 
364     vk::VkPipelineDynamicStateCreateInfo pipelineDynamicStateNfo{
365         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
366         DE_NULL,                                                  // const void* pNext;
367         (vk::VkPipelineDynamicStateCreateFlags)0u,                // VkPipelineDynamicStateCreateFlags flags;
368         static_cast<uint32_t>(dynamicStates.size()),              // uint32_t dynamicStateCount;
369         dynamicStates.data()                                      // const VkDynamicState* pDynamicStates;
370     };
371 
372     // Create pipeline layout
373     const vk::VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
374         vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
375         DE_NULL,                                           // const void* pNext;
376         0u,                                                // VkPipelineLayoutCreateFlags flags;
377         0u,                                                // uint32_t descriptorSetCount;
378         DE_NULL,                                           // const VkDescriptorSetLayout* pSetLayouts;
379         0u,                                                // uint32_t pushConstantRangeCount;
380         DE_NULL                                            // const VkPushDescriptorRange* pPushDescriptorRanges;
381     };
382 
383     vk::PipelineLayoutWrapper pipelineLayout(m_pipelineConstructionType, vk, *device, &pipelineLayoutInfo);
384 
385     // Create graphics pipeline
386     vk::GraphicsPipelineWrapper graphicsPipelines[2]{
387         {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType},
388         {instanceInterface, vk, physicalDevice, *device, deviceExtensions, m_pipelineConstructionType}};
389 
390     const vk::VkExtent2D extent = {32, 32};
391     const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(extent));
392     const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(extent));
393 
394     for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
395     {
396         graphicsPipelines[i]
397             .setDefaultDepthStencilState()
398             .setDefaultColorBlendState()
399             .setMonolithicPipelineLayout(pipelineLayout)
400             .setDynamicState(&pipelineDynamicStateNfo)
401             .setDefaultMultisampleState()
402             .setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
403             .setDefaultRasterizationState()
404             .setupVertexInputState(&vertexInputStateCreateInfo)
405             .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u,
406                                               vertexShaderModules[i])
407             .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragmentShaderModule, DE_NULL, DE_NULL)
408             .setupFragmentOutputState(*renderPass)
409             .setMonolithicPipelineLayout(pipelineLayout)
410             .buildPipeline();
411     }
412 
413     // Create vertex buffer
414     const uint32_t numVertices                   = 6;
415     const vk::VkDeviceSize vertexBufferSizeBytes = 256;
416 
417     const std::array<vk::Move<vk::VkBuffer>, 2> vertexBuffers = {
418         (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)),
419         (makeBuffer(vk, *device, vertexBufferSizeBytes, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))};
420 
421     const std::array<de::MovePtr<vk::Allocation>, 2> vertexBufferAllocs = {
422         (bindBuffer(vk, *device, allocator, *vertexBuffers[0], vk::MemoryRequirement::HostVisible)),
423         (bindBuffer(vk, *device, allocator, *vertexBuffers[1], vk::MemoryRequirement::HostVisible))};
424 
425     const uint32_t instanceSize = (uint32_t)sqrt(m_numInstances);
426     const float posIncrement    = 1.0f / (float)m_numInstances * (float)instanceSize;
427 
428     for (uint32_t i = 0u; i < static_cast<uint32_t>(vertexShaderModules.size()); ++i)
429     {
430         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));
431         VertexInfo *const pVertices = static_cast<VertexInfo *>(vertexBufferAllocs[i]->getHostPtr());
432 
433         pVertices[0] = {tcu::Vec4(posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
434         pVertices[1] = {tcu::Vec4(-posIncrement, -posIncrement, 0.0f, 1.0f), vertexColor};
435         pVertices[2] = {tcu::Vec4(-posIncrement, posIncrement, 0.0f, 1.0f), vertexColor};
436         pVertices[3] = {tcu::Vec4(-posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
437         pVertices[4] = {tcu::Vec4(posIncrement, posIncrement, 1.0f, 1.0f), vertexColor};
438         pVertices[5] = {tcu::Vec4(posIncrement, -posIncrement, 1.0f, 1.0f), vertexColor};
439 
440         flushAlloc(vk, *device, *vertexBufferAllocs[i]);
441     }
442 
443     // Command buffer
444     const vk::Unique<vk::VkCommandPool> cmdPool(
445         createCommandPool(vk, *device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
446     const vk::Unique<vk::VkCommandBuffer> cmdBuffer(
447         allocateCommandBuffer(vk, *device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
448 
449     const vk::VkDeviceSize vertexBufferOffset = 0u;
450 
451     // Render result buffer
452     const vk::VkDeviceSize colorBufferSizeBytes =
453         static_cast<vk::VkDeviceSize>(tcu::getPixelSize(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)) * 32 * 32);
454     const vk::Unique<vk::VkBuffer> colorBuffer(
455         makeBuffer(vk, *device, colorBufferSizeBytes, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
456     const de::UniquePtr<vk::Allocation> colorBufferAlloc(
457         bindBuffer(vk, *device, allocator, *colorBuffer, vk::MemoryRequirement::HostVisible));
458 
459     const vk::VkClearValue clearColorValue = defaultClearValue(vk::VK_FORMAT_R8G8B8A8_UNORM);
460 
461     beginCommandBuffer(vk, *cmdBuffer);
462 
463     renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, 32u, 32u), clearColorValue);
464 
465     graphicsPipelines[0].bind(*cmdBuffer);
466     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[0].get(), &vertexBufferOffset);
467     vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
468                             static_cast<uint32_t>(vertexInputAttributeDesc2EXTGreens.size()),
469                             vertexInputAttributeDesc2EXTGreens.data());
470     vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
471 
472     graphicsPipelines[1].bind(*cmdBuffer);
473     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffers[1].get(), &vertexBufferOffset);
474     vk.cmdSetVertexInputEXT(*cmdBuffer, 1u, &bindingDescription2EXT,
475                             static_cast<uint32_t>(vertexInputAttributeDesc2EXT2Reds.size()),
476                             vertexInputAttributeDesc2EXT2Reds.data());
477     vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
478 
479     renderPass.end(vk, *cmdBuffer);
480     copyImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, tcu::IVec2(32, 32),
481                       vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
482 
483     endCommandBuffer(vk, *cmdBuffer);
484 
485     submitCommandsAndWait(vk, *device, queue, *cmdBuffer);
486 
487     // Check result image
488     {
489         tcu::TextureLevel referenceTexture(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM), 32, 32);
490         const tcu::PixelBufferAccess referenceAccess = referenceTexture.getAccess();
491         const int segmentSize                        = static_cast<int32_t>(32u / instanceSize);
492         const int segmentLoc                         = (32 - segmentSize) / 2;
493 
494         tcu::clear(referenceTexture.getAccess(), clearColorValue.color.float32);
495 
496         // Create reference image
497         for (int y = 0; y < segmentSize; ++y)
498         {
499             for (int x = 0; x < segmentSize; ++x)
500             {
501                 // While running test for all offsets, we create a nice gradient-like color for the pixels.
502                 referenceAccess.setPixel(tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), segmentLoc + x, segmentLoc + y);
503             }
504         }
505 
506         invalidateAlloc(vk, *device, *colorBufferAlloc);
507 
508         const tcu::ConstPixelBufferAccess resultPixelAccess(mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM),
509                                                             (int)extent.width, (int)extent.height, 1,
510                                                             colorBufferAlloc->getHostPtr());
511 
512         if (!tcu::floatThresholdCompare(log, "color", "Image compare", referenceAccess, resultPixelAccess,
513                                         tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT))
514             return tcu::TestStatus::fail("Rendered image is not correct");
515     }
516 
517     return tcu::TestStatus::pass("Success");
518 }
519 
520 class NonSequentialCase : public vkt::TestCase
521 {
522 public:
NonSequentialCase(tcu::TestContext & testContext,const std::string & name,const vk::PipelineConstructionType pipelineConstructionType,const uint32_t numInstances,const std::vector<uint32_t> attributeLocations)523     NonSequentialCase(tcu::TestContext &testContext, const std::string &name,
524                       const vk::PipelineConstructionType pipelineConstructionType, const uint32_t numInstances,
525                       const std::vector<uint32_t> attributeLocations)
526         : vkt::TestCase(testContext, name)
527         , m_pipelineConstructionType(pipelineConstructionType)
528         , m_numInstances(numInstances)
529         , m_attributeLocations(attributeLocations)
530     {
531     }
532 
~NonSequentialCase(void)533     ~NonSequentialCase(void)
534     {
535     }
536 
537     virtual void checkSupport(Context &context) const override;
538     virtual void initPrograms(vk::SourceCollections &sourceCollections) const override;
539     virtual TestInstance *createInstance(Context &context) const override;
540 
541 private:
542     const vk::PipelineConstructionType m_pipelineConstructionType;
543     const uint32_t m_numInstances;
544     const std::vector<uint32_t> m_attributeLocations;
545 };
546 
checkSupport(Context & context) const547 void NonSequentialCase::checkSupport(Context &context) const
548 {
549     const vk::InstanceInterface &vki      = context.getInstanceInterface();
550     const vk::VkPhysicalDevice physDevice = context.getPhysicalDevice();
551 
552     std::array<std::string, 3> extensions = {"VK_EXT_extended_dynamic_state", "VK_EXT_vertex_input_dynamic_state",
553                                              "VK_EXT_extended_dynamic_state2"};
554 
555     // Check extension support.
556     for (const auto &extension : extensions)
557         context.requireDeviceFunctionality(extension);
558 
559     vk::checkPipelineConstructionRequirements(vki, physDevice, m_pipelineConstructionType);
560 }
561 
initPrograms(vk::SourceCollections & sourceCollections) const562 void NonSequentialCase::initPrograms(vk::SourceCollections &sourceCollections) const
563 {
564     // Vertex
565     {
566         for (size_t i = 0; i < m_attributeLocations.size(); ++i)
567         {
568             std::ostringstream src;
569 
570             src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
571                 << "\n"
572                 << "layout(location = 0) in vec4 inPosition;\n"
573                 << "layout(location = " << m_attributeLocations[i] << ") in vec4 inColor;\n"
574                 << "layout(location = 0) out vec4 outColor;\n"
575                 << "\n"
576                 << "void main (void)\n"
577                 << "{\n"
578                 << "    gl_Position = inPosition;\n"
579                 << "    outColor = inColor;\n"
580                 << "}\n";
581 
582             sourceCollections.glslSources.add("vert_" + std::to_string(i)) << glu::VertexSource(src.str());
583         }
584     }
585 
586     // Fragment
587     {
588         std::ostringstream src;
589 
590         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
591             << "\n"
592             << "layout(location = 0) in vec4 inColor;\n"
593             << "layout(location = 0) out vec4 outColor;\n"
594             << "\n"
595             << "void main (void)\n"
596             << "{\n"
597             << "    outColor = inColor;\n"
598             << "}\n";
599 
600         sourceCollections.glslSources.add("frag") << glu::FragmentSource(src.str());
601     }
602 }
603 
createInstance(Context & context) const604 TestInstance *NonSequentialCase::createInstance(Context &context) const
605 {
606     return new NonSequentialInstance(context, m_pipelineConstructionType, m_numInstances, m_attributeLocations);
607 }
608 
609 } // namespace
610 
createDynamicVertexAttributeTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)611 tcu::TestCaseGroup *createDynamicVertexAttributeTests(tcu::TestContext &testCtx,
612                                                       vk::PipelineConstructionType pipelineConstructionType)
613 {
614     de::MovePtr<tcu::TestCaseGroup> nonSequentialTestsGroup(
615         new tcu::TestCaseGroup(testCtx, "dynamic_vertex_attribute"));
616 
617     nonSequentialTestsGroup->addChild(
618         new NonSequentialCase(testCtx, "nonsequential", pipelineConstructionType, 16u, {1u, 7u}));
619 
620     return nonSequentialTestsGroup.release();
621 }
622 
623 } // namespace pipeline
624 } // namespace vkt
625