xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawVertexAttribDivisorTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 LunarG, Inc.
6  * Copyright (c) 2023 Google LLC
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Vertex attribute divisor Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawVertexAttribDivisorTests.hpp"
26 
27 #include <climits>
28 
29 #include "vktDrawCreateInfoUtil.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vktDrawImageObjectUtil.hpp"
32 #include "vktDrawBufferObjectUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "tcuTextureUtil.hpp"
35 #include "tcuRGBA.hpp"
36 #include "rrShaders.hpp"
37 #include "rrRenderer.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "shader_object/vktShaderObjectCreateUtil.hpp"
40 
41 namespace vkt
42 {
43 namespace Draw
44 {
45 namespace
46 {
47 
48 enum Extension
49 {
50     EXT = 0,
51     KHR,
52 };
53 
54 enum PipelineType
55 {
56     STATIC_PIPELINE = 0,
57     DYNAMIC_PIPELINE,
58     SHADER_OBJECTS,
59 };
60 
61 enum DrawFunction
62 {
63     DRAW = 0,
64     DRAW_INDEXED,
65     DRAW_INDIRECT,
66     DRAW_INDEXED_INDIRECT,
67     DRAW_MULTI_EXT,
68     DRAW_MULTI_INDEXED_EXT,
69     DRAW_INDIRECT_BYTE_COUNT_EXT,
70     DRAW_INDIRECT_COUNT,
71     DRAW_INDEXED_INDIRECT_COUNT,
72 
73     FUNTION_LAST
74 };
75 
isIndirectDraw(DrawFunction drawFunction)76 bool isIndirectDraw(DrawFunction drawFunction)
77 {
78     switch (drawFunction)
79     {
80     case DRAW_INDIRECT:
81     case DRAW_INDEXED_INDIRECT:
82     case DRAW_INDIRECT_BYTE_COUNT_EXT:
83     case DRAW_INDIRECT_COUNT:
84     case DRAW_INDEXED_INDIRECT_COUNT:
85         return true;
86     default:
87         break;
88     }
89     return false;
90 }
91 
isIndexedDraw(DrawFunction drawFunction)92 bool isIndexedDraw(DrawFunction drawFunction)
93 {
94     switch (drawFunction)
95     {
96     case DRAW_INDEXED:
97     case DRAW_INDEXED_INDIRECT:
98     case DRAW_MULTI_INDEXED_EXT:
99     case DRAW_INDEXED_INDIRECT_COUNT:
100         return true;
101     default:
102         break;
103     }
104     return false;
105 }
106 
isCountDraw(DrawFunction drawFunction)107 bool isCountDraw(DrawFunction drawFunction)
108 {
109     switch (drawFunction)
110     {
111     case DRAW_INDIRECT_COUNT:
112     case DRAW_INDEXED_INDIRECT_COUNT:
113         return true;
114     default:
115         break;
116     }
117     return false;
118 }
119 
120 struct TestParams
121 {
122     Extension extension;
123     PipelineType pipelineType;
124     DrawFunction function;
125     SharedGroupParams groupParams;
126     bool firstInstanceZero;
127     uint32_t attribDivisor;
128 };
129 
130 struct VertexPositionAndColor
131 {
VertexPositionAndColorvkt::Draw::__anonb1eb50cc0111::VertexPositionAndColor132     VertexPositionAndColor(tcu::Vec4 position_, tcu::Vec4 color_) : position(position_), color(color_)
133     {
134     }
135 
136     tcu::Vec4 position;
137     tcu::Vec4 color;
138 };
139 
140 template <typename T>
createAndUploadBuffer(const std::vector<T> data,const vk::DeviceInterface & vk,const Context & context,vk::VkBufferUsageFlags usage)141 de::SharedPtr<Buffer> createAndUploadBuffer(const std::vector<T> data, const vk::DeviceInterface &vk,
142                                             const Context &context, vk::VkBufferUsageFlags usage)
143 {
144     const vk::VkDeviceSize dataSize = data.size() * sizeof(T);
145     de::SharedPtr<Buffer> buffer =
146         Buffer::createAndAlloc(vk, context.getDevice(), BufferCreateInfo(dataSize, usage),
147                                context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
148 
149     uint8_t *ptr = reinterpret_cast<uint8_t *>(buffer->getBoundMemory().getHostPtr());
150     deMemcpy(ptr, &data[0], static_cast<size_t>(dataSize));
151     vk::flushAlloc(vk, context.getDevice(), buffer->getBoundMemory());
152 
153     return buffer;
154 }
155 
156 class TestVertShader : public rr::VertexShader
157 {
158 public:
TestVertShader(int numInstances,int firstInstance)159     TestVertShader(int numInstances, int firstInstance)
160         : rr::VertexShader(2, 1)
161         , m_numInstances(numInstances)
162         , m_firstInstance(firstInstance)
163     {
164         m_inputs[0].type  = rr::GENERICVECTYPE_FLOAT;
165         m_inputs[1].type  = rr::GENERICVECTYPE_FLOAT;
166         m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
167     }
168 
~TestVertShader()169     virtual ~TestVertShader()
170     {
171     }
172 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const173     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
174     {
175         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
176         {
177             const int instanceNdx    = packets[packetNdx]->instanceNdx + m_firstInstance;
178             const tcu::Vec4 position = rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx,
179                                                                  packets[packetNdx]->vertexNdx, m_firstInstance);
180             const tcu::Vec4 color    = rr::readVertexAttribFloat(inputs[1], packets[packetNdx]->instanceNdx,
181                                                                  packets[packetNdx]->vertexNdx, m_firstInstance);
182             const tcu::Vec4 color2   = rr::readVertexAttribFloat(inputs[2], packets[packetNdx]->instanceNdx,
183                                                                  packets[packetNdx]->vertexNdx, m_firstInstance);
184             packets[packetNdx]->position =
185                 position + tcu::Vec4((float)(packets[packetNdx]->instanceNdx * 2.0 / m_numInstances), 0.0, 0.0, 0.0);
186             packets[packetNdx]->outputs[0] =
187                 color + tcu::Vec4((float)instanceNdx / (float)m_numInstances, 0.0, 0.0, 1.0) + color2;
188         }
189     }
190 
191 private:
192     const int m_numInstances;
193     const int m_firstInstance;
194 };
195 
196 class TestFragShader : public rr::FragmentShader
197 {
198 public:
TestFragShader(void)199     TestFragShader(void) : rr::FragmentShader(1, 1)
200     {
201         m_inputs[0].type  = rr::GENERICVECTYPE_FLOAT;
202         m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
203     }
204 
~TestFragShader()205     virtual ~TestFragShader()
206     {
207     }
208 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const209     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
210                         const rr::FragmentShadingContext &context) const
211     {
212         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
213         {
214             rr::FragmentPacket &packet = packets[packetNdx];
215             for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
216             {
217                 const tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
218                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
219             }
220         }
221     }
222 };
223 
224 class VertexAttributeDivisorInstance : public TestInstance
225 {
226 public:
227     VertexAttributeDivisorInstance(Context &context, TestParams params);
228     virtual tcu::TestStatus iterate(void);
229 
230 private:
231     void prepareVertexData(int instanceCount, int firstInstance, int instanceDivisor);
232     void preRenderCommands(const vk::VkClearValue &clearColor);
233     void draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer vertexBuffer, vk::VkBuffer instancedVertexBuffer,
234               de::SharedPtr<Buffer> indexBuffer, de::SharedPtr<Buffer> indirectBuffer,
235               de::SharedPtr<Buffer> countBuffer, uint32_t firstInstance, uint32_t instanceCount);
236 
237 #ifndef CTS_USES_VULKANSC
238     void beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags = 0u);
239 #endif // CTS_USES_VULKANSC
240 
241 private:
242     vk::VkFormat m_colorAttachmentFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
243     const uint32_t m_width               = 128u;
244     const uint32_t m_height              = 128u;
245     const uint32_t m_quadGridSize        = 8u;
246 
247     const TestParams m_params;
248     const vk::DeviceInterface &m_vk;
249 
250 #ifndef CTS_USES_VULKANSC
251     vk::Move<vk::VkShaderEXT> m_vertexShader;
252     vk::Move<vk::VkShaderEXT> m_fragmentShader;
253 #endif
254     vk::Move<vk::VkPipeline> m_pipeline;
255     vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
256 
257     de::SharedPtr<Image> m_colorTargetImage;
258     vk::Move<vk::VkImageView> m_colorTargetView;
259 
260     PipelineCreateInfo::VertexInputState m_vertexInputState;
261 
262     vk::Move<vk::VkCommandPool> m_cmdPool;
263     vk::Move<vk::VkCommandBuffer> m_cmdBuffer;
264     vk::Move<vk::VkCommandBuffer> m_secCmdBuffer;
265 
266     vk::Move<vk::VkFramebuffer> m_framebuffer;
267     vk::Move<vk::VkRenderPass> m_renderPass;
268 
269     // Vertex data
270     std::vector<VertexPositionAndColor> m_data;
271     std::vector<uint32_t> m_indexes;
272     std::vector<tcu::Vec4> m_instancedColor;
273 };
274 
VertexAttributeDivisorInstance(Context & context,TestParams params)275 VertexAttributeDivisorInstance::VertexAttributeDivisorInstance(Context &context, TestParams params)
276     : TestInstance(context)
277     , m_params(params)
278     , m_vk(context.getDeviceInterface())
279 {
280     const vk::VkDevice device       = m_context.getDevice();
281     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
282 
283     const vk::VkPushConstantRange pushConstantRange = {
284         vk::VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlags    stageFlags;
285         0u,                             // uint32_t              offset;
286         (uint32_t)sizeof(float) * 2,    // uint32_t              size;
287     };
288 
289     const PipelineLayoutCreateInfo pipelineLayoutCreateInfo(0, DE_NULL, 1, &pushConstantRange);
290     m_pipelineLayout = vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
291 
292     const vk::VkExtent3D targetImageExtent = {m_width, m_height, 1};
293     const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1u,
294                                                 1u, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
295                                                 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
296                                                     vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
297                                                     vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
298 
299     m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
300                                                m_context.getUniversalQueueFamilyIndex());
301 
302     ImageSubresourceRange subresourceRange = ImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
303 
304     const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D,
305                                                   m_colorAttachmentFormat, subresourceRange);
306     m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo);
307 
308     if (!m_params.groupParams->useDynamicRendering)
309     {
310         RenderPassCreateInfo renderPassCreateInfo;
311         renderPassCreateInfo.addAttachment(AttachmentDescription(
312             m_colorAttachmentFormat, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
313             vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_STORE,
314             vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_GENERAL));
315 
316         const vk::VkAttachmentReference colorAttachmentReference = {0, vk::VK_IMAGE_LAYOUT_GENERAL};
317 
318         renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1,
319                                                            &colorAttachmentReference, DE_NULL, AttachmentReference(), 0,
320                                                            DE_NULL));
321 
322         m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
323 
324         // create framebuffer
325         std::vector<vk::VkImageView> colorAttachments{*m_colorTargetView};
326         const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, m_width, m_height, 1);
327         m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
328     }
329 
330     const vk::VkVertexInputBindingDescription vertexInputBindingDescription[2] = {
331         {
332             0u,
333             (uint32_t)sizeof(VertexPositionAndColor),
334             vk::VK_VERTEX_INPUT_RATE_VERTEX,
335         },
336         {
337             1u,
338             (uint32_t)sizeof(tcu::Vec4),
339             vk::VK_VERTEX_INPUT_RATE_INSTANCE,
340         },
341     };
342 
343     const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
344         {0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
345         {
346             1u,
347             0u,
348             vk::VK_FORMAT_R32G32B32A32_SFLOAT,
349             (uint32_t)sizeof(tcu::Vec4),
350         },
351         {
352             2u,
353             1u,
354             vk::VK_FORMAT_R32G32B32A32_SFLOAT,
355             0,
356         }};
357 
358     m_vertexInputState = PipelineCreateInfo::VertexInputState(2, vertexInputBindingDescription,
359                                                               DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),
360                                                               vertexInputAttributeDescriptions);
361 
362     const vk::VkVertexInputBindingDivisorDescriptionEXT vertexInputBindingDivisorDescription = {
363         1u,
364         m_params.attribDivisor,
365     };
366 
367     m_vertexInputState.addDivisors(1, &vertexInputBindingDivisorDescription);
368 
369     const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
370     m_cmdPool   = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
371     m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
372     if (m_params.groupParams->useSecondaryCmdBuffer)
373         m_secCmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
374 
375     if (m_params.pipelineType == SHADER_OBJECTS)
376     {
377 #ifndef CTS_USES_VULKANSC
378         const auto &vertSrc                              = m_context.getBinaryCollection().get("vert");
379         const vk::VkShaderCreateInfoEXT vertexCreateInfo = {
380             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
381             DE_NULL,                                      // const void* pNext;
382             0u,                                           // VkShaderCreateFlagsEXT flags;
383             vk::VK_SHADER_STAGE_VERTEX_BIT,               // VkShaderStageFlagBits stage;
384             vk::VK_SHADER_STAGE_FRAGMENT_BIT,             // VkShaderStageFlags nextStage;
385             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,            // VkShaderCodeTypeEXT codeType;
386             vertSrc.getSize(),                            // size_t codeSize;
387             vertSrc.getBinary(),                          // const void* pCode;
388             "main",                                       // const char* pName;
389             0u,                                           // uint32_t setLayoutCount;
390             DE_NULL,                                      // const VkDescriptorSetLayout* pSetLayouts;
391             1u,                                           // uint32_t pushConstantRangeCount;
392             &pushConstantRange,                           // const VkPushConstantRange* pPushConstantRanges;
393             DE_NULL,                                      // const VkSpecializationInfo* pSpecializationInfo;
394         };
395         m_vertexShader = vk::createShader(m_vk, device, vertexCreateInfo);
396 
397         const auto &fragSrc                                = m_context.getBinaryCollection().get("frag");
398         const vk::VkShaderCreateInfoEXT fragmentCreateInfo = {
399             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
400             DE_NULL,                                      // const void* pNext;
401             0u,                                           // VkShaderCreateFlagsEXT flags;
402             vk::VK_SHADER_STAGE_FRAGMENT_BIT,             // VkShaderStageFlagBits stage;
403             0u,                                           // VkShaderStageFlags nextStage;
404             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,            // VkShaderCodeTypeEXT codeType;
405             fragSrc.getSize(),                            // size_t codeSize;
406             fragSrc.getBinary(),                          // const void* pCode;
407             "main",                                       // const char* pName;
408             0u,                                           // uint32_t setLayoutCount;
409             DE_NULL,                                      // const VkDescriptorSetLayout* pSetLayouts;
410             1u,                                           // uint32_t pushConstantRangeCount;
411             &pushConstantRange,                           // const VkPushConstantRange* pPushConstantRanges;
412             DE_NULL,                                      // const VkSpecializationInfo* pSpecializationInfo;
413         };
414         m_fragmentShader = vk::createShader(m_vk, device, fragmentCreateInfo);
415 #endif
416     }
417     else
418     {
419         const vk::Unique<vk::VkShaderModule> vs(
420             createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
421         const vk::Unique<vk::VkShaderModule> fs(
422             createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
423 
424         const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
425 
426         vk::VkViewport viewport = vk::makeViewport(m_width, m_height);
427         vk::VkRect2D scissor    = vk::makeRect2D(m_width, m_height);
428 
429         PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
430         pipelineCreateInfo.addShader(
431             PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
432         pipelineCreateInfo.addShader(
433             PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
434         pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP));
435         pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
436         pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport),
437                                                                       std::vector<vk::VkRect2D>(1, scissor)));
438         pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
439         pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
440         pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
441 
442         if (m_params.pipelineType == DYNAMIC_PIPELINE)
443         {
444             vk::VkDynamicState dynStates[] = {vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT};
445             vk::VkPipelineDynamicStateCreateInfo dynamicState{vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
446                                                               DE_NULL, 0u, 1u, dynStates};
447             pipelineCreateInfo.addState(dynamicState);
448         }
449         else
450         {
451             pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
452         }
453 
454 #ifndef CTS_USES_VULKANSC
455         vk::VkPipelineRenderingCreateInfoKHR renderingFormatCreateInfo{
456             vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
457             DE_NULL,
458             0u,
459             1u,
460             &m_colorAttachmentFormat,
461             vk::VK_FORMAT_UNDEFINED,
462             vk::VK_FORMAT_UNDEFINED};
463 
464         if (m_params.groupParams->useDynamicRendering)
465         {
466             pipelineCreateInfo.pNext = &renderingFormatCreateInfo;
467         }
468 #endif // CTS_USES_VULKANSC
469 
470         m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
471     }
472 }
473 
iterate()474 tcu::TestStatus VertexAttributeDivisorInstance::iterate()
475 {
476     const vk::VkQueue queue                = m_context.getUniversalQueue();
477     const vk::VkDevice device              = m_context.getDevice();
478     tcu::TestLog &log                      = m_context.getTestContext().getLog();
479     static const uint32_t instanceCounts[] = {0u, 1u, 2u, 4u, 20u};
480     const vk::VkRect2D renderArea          = vk::makeRect2D(m_width, m_height);
481     qpTestResult res                       = QP_TEST_RESULT_PASS;
482 
483     std::vector<uint32_t> firstInstanceIndices;
484     if (m_params.firstInstanceZero)
485         firstInstanceIndices = {0u};
486     else
487         firstInstanceIndices = {1u, 3u, 4u, 20u};
488 
489     const vk::VkClearValue clearColor = vk::makeClearValueColor({0.0f, 0.0f, 0.0f, 1.0f});
490 
491     for (int instanceCountNdx = 0; instanceCountNdx < DE_LENGTH_OF_ARRAY(instanceCounts); instanceCountNdx++)
492     {
493         const uint32_t instanceCount = instanceCounts[instanceCountNdx];
494         for (size_t firstInstanceIndexNdx = 0u; firstInstanceIndexNdx < firstInstanceIndices.size();
495              firstInstanceIndexNdx++)
496         {
497             // Prepare vertex data for at least one instance
498             const uint32_t prepareCount  = de::max(instanceCount, 1u);
499             const uint32_t firstInstance = firstInstanceIndices[firstInstanceIndexNdx];
500 
501             prepareVertexData(prepareCount, firstInstance, m_params.attribDivisor);
502             const de::SharedPtr<Buffer> vertexBuffer =
503                 createAndUploadBuffer(m_data, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
504             const de::SharedPtr<Buffer> instancedVertexBuffer =
505                 createAndUploadBuffer(m_instancedColor, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
506 
507             de::SharedPtr<Buffer> indexBuffer;
508             if (isIndexedDraw(m_params.function))
509                 indexBuffer = createAndUploadBuffer(m_indexes, m_vk, m_context, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
510 
511             de::SharedPtr<Buffer> indirectBuffer;
512             if (isIndirectDraw(m_params.function))
513             {
514                 if (!isIndexedDraw(m_params.function))
515                 {
516                     std::vector<vk::VkDrawIndirectCommand> drawCommands;
517                     drawCommands.push_back({
518                         (uint32_t)m_data.size(), // uint32_t vertexCount;
519                         instanceCount,           // uint32_t instanceCount;
520                         0u,                      // uint32_t firstVertex;
521                         firstInstance            // uint32_t firstInstance;
522                     });
523                     indirectBuffer =
524                         createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
525                 }
526                 else
527                 {
528                     std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands;
529                     drawCommands.push_back({
530                         (uint32_t)m_indexes.size(), // uint32_t indexCount;
531                         instanceCount,              // uint32_t instanceCount;
532                         0u,                         // uint32_t firstIndex;
533                         0,                          // int32_t vertexOffset;
534                         firstInstance               // uint32_t firstInstance;
535                     });
536                     indirectBuffer =
537                         createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
538                 }
539             }
540             de::SharedPtr<Buffer> countBuffer;
541             if (isCountDraw(m_params.function))
542             {
543                 std::vector<uint32_t> count = {1};
544                 countBuffer = createAndUploadBuffer(count, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
545             }
546             else if (m_params.function == DRAW_INDIRECT_BYTE_COUNT_EXT)
547             {
548                 std::vector<uint32_t> count = {(uint32_t)m_data.size()};
549                 countBuffer = createAndUploadBuffer(count, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
550             }
551 
552 #ifndef CTS_USES_VULKANSC
553             if (m_params.groupParams->useSecondaryCmdBuffer)
554             {
555                 // record secondary command buffer
556                 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
557                 {
558                     beginSecondaryCmdBuffer(vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
559                     beginRendering(m_vk, *m_secCmdBuffer, *m_colorTargetView, renderArea, clearColor,
560                                    vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD, 0u, 1u, 0x0);
561                 }
562                 else
563                     beginSecondaryCmdBuffer();
564 
565                 draw(*m_secCmdBuffer, vertexBuffer->object(), instancedVertexBuffer->object(), indexBuffer,
566                      indirectBuffer, countBuffer, firstInstance, instanceCount);
567 
568                 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
569                     endRendering(m_vk, *m_secCmdBuffer);
570 
571                 endCommandBuffer(m_vk, *m_secCmdBuffer);
572 
573                 // record primary command buffer
574                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
575 
576                 preRenderCommands(clearColor);
577 
578                 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
579                 {
580                     beginRendering(m_vk, *m_cmdBuffer, *m_colorTargetView, renderArea, clearColor,
581                                    vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
582                                    vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR, 1u, 0x0);
583                 }
584 
585                 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
586 
587                 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
588                     endRendering(m_vk, *m_cmdBuffer);
589 
590                 endCommandBuffer(m_vk, *m_cmdBuffer);
591             }
592             else if (m_params.groupParams->useDynamicRendering)
593             {
594                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
595                 preRenderCommands(clearColor);
596 
597                 beginRendering(m_vk, *m_cmdBuffer, *m_colorTargetView, renderArea, clearColor,
598                                vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD, 0u, 1u, 0x0);
599                 draw(*m_cmdBuffer, vertexBuffer->object(), instancedVertexBuffer->object(), indexBuffer, indirectBuffer,
600                      countBuffer, firstInstance, instanceCount);
601                 endRendering(m_vk, *m_cmdBuffer);
602 
603                 endCommandBuffer(m_vk, *m_cmdBuffer);
604             }
605 #endif // CTS_USES_VULKANSC
606 
607             if (!m_params.groupParams->useDynamicRendering)
608             {
609                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
610                 preRenderCommands(clearColor);
611 
612                 beginRenderPass(m_vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, renderArea);
613                 draw(*m_cmdBuffer, vertexBuffer->object(), instancedVertexBuffer->object(), indexBuffer, indirectBuffer,
614                      countBuffer, firstInstance, instanceCount);
615                 endRenderPass(m_vk, *m_cmdBuffer);
616 
617                 endCommandBuffer(m_vk, *m_cmdBuffer);
618             }
619 
620             submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
621             m_context.resetCommandPoolForVKSC(device, *m_cmdPool);
622 
623             // Reference rendering
624             std::vector<tcu::Vec4> vertices;
625             std::vector<tcu::Vec4> colors;
626 
627             for (std::vector<VertexPositionAndColor>::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
628             {
629                 vertices.push_back(it->position);
630                 colors.push_back(it->color);
631             }
632 
633             tcu::TextureLevel refImage(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + m_width),
634                                        (int)(0.5 + m_height));
635 
636             tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
637 
638             const TestVertShader vertShader(instanceCount, firstInstance);
639             const TestFragShader fragShader;
640             const rr::Program program(&vertShader, &fragShader);
641             const rr::MultisamplePixelBufferAccess colorBuffer =
642                 rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refImage.getAccess());
643             const rr::RenderTarget renderTarget(colorBuffer);
644             const rr::RenderState renderState((rr::ViewportState(colorBuffer)),
645                                               m_context.getDeviceProperties().limits.subPixelPrecisionBits);
646             const rr::Renderer renderer;
647 
648             const rr::VertexAttrib vertexAttribs[] = {
649                 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
650                 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0]),
651                 // The reference renderer treats a divisor of 0 as meaning per-vertex.  Use INT_MAX instead; it should work just as well.
652                 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4),
653                                  m_params.attribDivisor == 0 ? INT_MAX : m_params.attribDivisor, &m_instancedColor[0])};
654 
655             if (!isIndexedDraw(m_params.function))
656             {
657                 const rr::PrimitiveList primitives =
658                     rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLE_STRIP, (int)vertices.size(), 0);
659                 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
660                                               &vertexAttribs[0], primitives);
661                 renderer.drawInstanced(command, instanceCount);
662             }
663             else
664             {
665                 const rr::DrawIndices indicies(m_indexes.data());
666 
667                 const rr::PrimitiveList primitives =
668                     rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLE_STRIP, (int)m_indexes.size(), indicies);
669                 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
670                                               &vertexAttribs[0], primitives);
671                 renderer.drawInstanced(command, instanceCount);
672             }
673 
674             const vk::VkOffset3D zeroOffset = {0, 0, 0};
675             const tcu::ConstPixelBufferAccess renderedFrame =
676                 m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
677                                                 zeroOffset, m_width, m_height, vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u);
678 
679             std::ostringstream resultDesc;
680             resultDesc << "Instance count: " << instanceCount << " first instance index: " << firstInstance;
681 
682             if (!tcu::fuzzyCompare(log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame, 0.05f,
683                                    tcu::COMPARE_LOG_RESULT))
684                 res = QP_TEST_RESULT_FAIL;
685         }
686     }
687     return tcu::TestStatus(res, qpGetTestResultName(res));
688 }
689 
prepareVertexData(int instanceCount,int firstInstance,int instanceDivisor)690 void VertexAttributeDivisorInstance::prepareVertexData(int instanceCount, int firstInstance, int instanceDivisor)
691 {
692     m_data.clear();
693     m_indexes.clear();
694     m_instancedColor.clear();
695 
696     if (!isIndexedDraw(m_params.function))
697     {
698         for (uint32_t y = 0; y < m_quadGridSize; ++y)
699         {
700             for (uint32_t x = 0; x < m_quadGridSize; ++x)
701             {
702                 const float fx0 = -1.0f + (float)(x + 0) / (float)m_quadGridSize * 2.0f / (float)instanceCount;
703                 const float fx1 = -1.0f + (float)(x + 1) / (float)m_quadGridSize * 2.0f / (float)instanceCount;
704                 const float fy0 = -1.0f + (float)(y + 0) / (float)m_quadGridSize * 2.0f;
705                 const float fy1 = -1.0f + (float)(y + 1) / (float)m_quadGridSize * 2.0f;
706 
707                 // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1)
708                 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
709                 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
710                 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
711 
712                 // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0)
713                 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
714                 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
715                 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
716             }
717         }
718     }
719     else
720     {
721         for (uint32_t y = 0; y < m_quadGridSize + 1; ++y)
722         {
723             for (uint32_t x = 0; x < m_quadGridSize + 1; ++x)
724             {
725                 const float fx = -1.0f + (float)x / (float)m_quadGridSize * 2.0f / (float)instanceCount;
726                 const float fy = -1.0f + (float)y / (float)m_quadGridSize * 2.0f;
727 
728                 m_data.push_back(VertexPositionAndColor(
729                     tcu::Vec4(fx, fy, 1.0f, 1.0f), (y % 2 ? tcu::RGBA::blue().toVec() : tcu::RGBA::green().toVec())));
730             }
731         }
732 
733         for (uint32_t y = 0; y < m_quadGridSize; ++y)
734         {
735             for (uint32_t x = 0; x < m_quadGridSize; ++x)
736             {
737                 const int ndx00 = y * (m_quadGridSize + 1) + x;
738                 const int ndx10 = y * (m_quadGridSize + 1) + x + 1;
739                 const int ndx01 = (y + 1) * (m_quadGridSize + 1) + x;
740                 const int ndx11 = (y + 1) * (m_quadGridSize + 1) + x + 1;
741 
742                 // Lower-left triangle of a quad.
743                 m_indexes.push_back((uint16_t)ndx00);
744                 m_indexes.push_back((uint16_t)ndx10);
745                 m_indexes.push_back((uint16_t)ndx01);
746 
747                 // Upper-right triangle of a quad.
748                 m_indexes.push_back((uint16_t)ndx11);
749                 m_indexes.push_back((uint16_t)ndx01);
750                 m_indexes.push_back((uint16_t)ndx10);
751             }
752         }
753     }
754 
755     const int colorCount =
756         instanceDivisor == 0 ? 1 : (instanceCount + firstInstance + instanceDivisor - 1) / instanceDivisor;
757     for (int i = 0; i < instanceCount + firstInstance; i++)
758     {
759         m_instancedColor.push_back(tcu::Vec4(0.0, (float)(1.0 - i * 1.0 / colorCount) / 2, 0.0, 1.0));
760     }
761 }
762 
preRenderCommands(const vk::VkClearValue & clearColor)763 void VertexAttributeDivisorInstance::preRenderCommands(const vk::VkClearValue &clearColor)
764 {
765     const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
766 
767     initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
768                                   vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
769 
770     m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor.color,
771                             1, &subresourceRange);
772 
773     const vk::VkMemoryBarrier memBarrier{
774         vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, vk::VK_ACCESS_TRANSFER_WRITE_BIT,
775         vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT};
776 
777     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
778                             vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0,
779                             DE_NULL);
780 }
781 
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer vertexBuffer,vk::VkBuffer instancedVertexBuffer,de::SharedPtr<Buffer> indexBuffer,de::SharedPtr<Buffer> indirectBuffer,de::SharedPtr<Buffer> countBuffer,uint32_t firstInstance,uint32_t instanceCount)782 void VertexAttributeDivisorInstance::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer vertexBuffer,
783                                           vk::VkBuffer instancedVertexBuffer, de::SharedPtr<Buffer> indexBuffer,
784                                           de::SharedPtr<Buffer> indirectBuffer, de::SharedPtr<Buffer> countBuffer,
785                                           uint32_t firstInstance, uint32_t instanceCount)
786 {
787     if (m_params.pipelineType != PipelineType::SHADER_OBJECTS)
788     {
789         m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
790     }
791     else
792     {
793 #ifndef CTS_USES_VULKANSC
794         vk::bindGraphicsShaders(m_vk, cmdBuffer, m_vertexShader.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE,
795                                 m_fragmentShader.get(), m_context.getMeshShaderFeatures().taskShader,
796                                 m_context.getMeshShaderFeatures().meshShader);
797         vk::setDefaultShaderObjectDynamicStates(m_vk, cmdBuffer, m_context.getDeviceExtensions());
798         vk::bindNullTaskMeshShaders(m_vk, cmdBuffer, m_context.getMeshShaderFeaturesEXT());
799 
800         vk::VkViewport viewport = vk::makeViewport(m_width, m_height);
801         vk::VkRect2D scissor    = vk::makeRect2D(m_width, m_height);
802         m_vk.cmdSetViewportWithCount(cmdBuffer, 1u, &viewport);
803         m_vk.cmdSetScissorWithCount(cmdBuffer, 1u, &scissor);
804 #endif
805     }
806 
807     if (isIndexedDraw(m_params.function))
808         m_vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer->object(), 0, vk::VK_INDEX_TYPE_UINT32);
809 
810     const vk::VkBuffer vertexBuffers[]{vertexBuffer, instancedVertexBuffer};
811     const vk::VkDeviceSize vertexBufferOffsets[]{0, 0};
812 
813     m_vk.cmdBindVertexBuffers(cmdBuffer, 0, DE_LENGTH_OF_ARRAY(vertexBuffers), vertexBuffers, vertexBufferOffsets);
814 
815     const float pushConstants[] = {(float)firstInstance, (float)instanceCount};
816     m_vk.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u,
817                           (uint32_t)sizeof(pushConstants), pushConstants);
818 
819     if (m_params.pipelineType != PipelineType::STATIC_PIPELINE)
820     {
821         vk::VkVertexInputBindingDescription2EXT vertexBindingDescription[2]{
822             {vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT, DE_NULL, 0u,
823              (uint32_t)sizeof(VertexPositionAndColor), vk::VK_VERTEX_INPUT_RATE_VERTEX, 1u},
824             {vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT, DE_NULL, 1u, (uint32_t)sizeof(tcu::Vec4),
825              vk::VK_VERTEX_INPUT_RATE_INSTANCE, m_params.attribDivisor},
826 
827         };
828         vk::VkVertexInputAttributeDescription2EXT vertexAttributeDescription[3]{
829             {vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, DE_NULL, 0u, 0u,
830              vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
831             {
832                 vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
833                 DE_NULL,
834                 1u,
835                 0u,
836                 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
837                 (uint32_t)sizeof(tcu::Vec4),
838             },
839             {
840                 vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
841                 DE_NULL,
842                 2u,
843                 1u,
844                 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
845                 0u,
846             }};
847 
848         m_vk.cmdSetVertexInputEXT(cmdBuffer, 2u, vertexBindingDescription, 3u, vertexAttributeDescription);
849     }
850 
851 #ifndef CTS_USES_VULKANSC
852     vk::VkMultiDrawInfoEXT multiDrawInfo;
853     multiDrawInfo.firstVertex = 0u;
854     multiDrawInfo.vertexCount = (uint32_t)m_data.size();
855     vk::VkMultiDrawIndexedInfoEXT multiDrawIndexedInfo;
856     multiDrawIndexedInfo.firstIndex   = 0u;
857     multiDrawIndexedInfo.indexCount   = (uint32_t)m_indexes.size();
858     multiDrawIndexedInfo.vertexOffset = 0u;
859     int32_t vertexOffset              = 0u;
860 #endif
861 
862     switch (m_params.function)
863     {
864     case DrawFunction::DRAW:
865         m_vk.cmdDraw(cmdBuffer, (uint32_t)m_data.size(), instanceCount, 0u, firstInstance);
866         break;
867     case DrawFunction::DRAW_INDEXED:
868         m_vk.cmdDrawIndexed(cmdBuffer, (uint32_t)m_indexes.size(), instanceCount, 0u, 0u, firstInstance);
869         break;
870     case DrawFunction::DRAW_INDEXED_INDIRECT:
871         m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
872         break;
873     case DrawFunction::DRAW_INDEXED_INDIRECT_COUNT:
874         m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, indirectBuffer->object(), 0, countBuffer->object(), 0u, 1u,
875                                          sizeof(vk::VkDrawIndexedIndirectCommand));
876         break;
877     case DrawFunction::DRAW_INDIRECT:
878         m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
879         break;
880     case DrawFunction::DRAW_INDIRECT_COUNT:
881         m_vk.cmdDrawIndirectCount(cmdBuffer, indirectBuffer->object(), 0, countBuffer->object(), 0u, 1u,
882                                   sizeof(vk::VkDrawIndirectCommand));
883         break;
884 #ifndef CTS_USES_VULKANSC
885     case DrawFunction::DRAW_INDIRECT_BYTE_COUNT_EXT:
886         m_vk.cmdDrawIndirectByteCountEXT(cmdBuffer, instanceCount, firstInstance, countBuffer->object(), 0u, 0u, 1u);
887         break;
888     case DrawFunction::DRAW_MULTI_EXT:
889         m_vk.cmdDrawMultiEXT(cmdBuffer, 1u, &multiDrawInfo, instanceCount, firstInstance,
890                              sizeof(vk::VkMultiDrawInfoEXT));
891         break;
892     case DrawFunction::DRAW_MULTI_INDEXED_EXT:
893         m_vk.cmdDrawMultiIndexedEXT(cmdBuffer, 1u, &multiDrawIndexedInfo, instanceCount, firstInstance,
894                                     sizeof(vk::VkMultiDrawIndexedInfoEXT), &vertexOffset);
895         break;
896 #endif
897     default:
898         DE_ASSERT(false);
899     }
900 }
901 
902 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)903 void VertexAttributeDivisorInstance::beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)
904 {
905     const vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
906         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
907         DE_NULL,                                                             // const void* pNext;
908         renderingFlags,                                                      // VkRenderingFlagsKHR flags;
909         0u,                                                                  // uint32_t viewMask;
910         1u,                                                                  // uint32_t colorAttachmentCount;
911         &m_colorAttachmentFormat,                                            // const VkFormat* pColorAttachmentFormats;
912         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat depthAttachmentFormat;
913         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
914         vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
915     };
916 
917     const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo{
918         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
919         &inheritanceRenderingInfo,                             // const void* pNext;
920         DE_NULL,                                               // VkRenderPass renderPass;
921         0u,                                                    // uint32_t subpass;
922         DE_NULL,                                               // VkFramebuffer framebuffer;
923         VK_FALSE,                                              // VkBool32 occlusionQueryEnable;
924         (vk::VkQueryControlFlags)0u,                           // VkQueryControlFlags queryFlags;
925         (vk::VkQueryPipelineStatisticFlags)0u                  // VkQueryPipelineStatisticFlags pipelineStatistics;
926     };
927 
928     vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
929     if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
930         usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
931 
932     const vk::VkCommandBufferBeginInfo commandBufBeginParams{
933         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
934         DE_NULL,                                         // const void* pNext;
935         usageFlags,                                      // VkCommandBufferUsageFlags flags;
936         &bufferInheritanceInfo};
937 
938     VK_CHECK(m_vk.beginCommandBuffer(*m_secCmdBuffer, &commandBufBeginParams));
939 }
940 #endif // CTS_USES_VULKANSC
941 
942 class VertexAttributeDivisorCase : public TestCase
943 {
944 public:
VertexAttributeDivisorCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)945     VertexAttributeDivisorCase(tcu::TestContext &testCtx, const std::string &name, const TestParams &params)
946         : TestCase(testCtx, name)
947         , m_params(params)
948     {
949     }
950 
951     virtual void checkSupport(Context &context) const override;
952     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const953     TestInstance *createInstance(Context &context) const override
954     {
955         return new VertexAttributeDivisorInstance(context, m_params);
956     }
957 
958 private:
959     const TestParams m_params;
960 };
961 
checkSupport(Context & context) const962 void VertexAttributeDivisorCase::checkSupport(Context &context) const
963 {
964     const auto attributeDivisorFeatures = context.getVertexAttributeDivisorFeatures();
965     if (m_params.extension == Extension::EXT)
966     {
967         context.requireDeviceFunctionality("VK_EXT_vertex_attribute_divisor");
968     }
969     else if (m_params.extension == Extension::KHR)
970     {
971         context.requireDeviceFunctionality("VK_KHR_vertex_attribute_divisor");
972 #ifndef CTS_USES_VULKANSC
973         const vk::VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR &vertexAttributeDivisorProperties =
974             context.getVertexAttributeDivisorProperties();
975         if (!m_params.firstInstanceZero && !vertexAttributeDivisorProperties.supportsNonZeroFirstInstance)
976             TCU_THROW(NotSupportedError, "supportsNonZeroFirstInstance not supported");
977 #endif
978     }
979     if (!m_params.firstInstanceZero && isIndirectDraw(m_params.function) &&
980         !context.getDeviceFeatures().drawIndirectFirstInstance)
981     {
982         TCU_THROW(NotSupportedError, "drawIndirectFirstInstancenot supported");
983     }
984     if (m_params.attribDivisor == 1u && !attributeDivisorFeatures.vertexAttributeInstanceRateDivisor)
985         TCU_THROW(NotSupportedError, "vertexAttributeInstanceRateDivisor not supported");
986     if (m_params.attribDivisor == 0u && !attributeDivisorFeatures.vertexAttributeInstanceRateZeroDivisor)
987         TCU_THROW(NotSupportedError, "vertexAttributeInstanceRateZeroDivisor not supported");
988 
989     if (m_params.pipelineType == PipelineType::DYNAMIC_PIPELINE)
990         context.requireDeviceFunctionality("VK_EXT_vertex_input_dynamic_state");
991     else if (m_params.pipelineType == PipelineType::SHADER_OBJECTS)
992         context.requireDeviceFunctionality("VK_EXT_shader_object");
993 
994     if (m_params.function == DrawFunction::DRAW_MULTI_EXT || m_params.function == DrawFunction::DRAW_MULTI_INDEXED_EXT)
995         context.requireDeviceFunctionality("VK_EXT_multi_draw");
996     if (isIndirectDraw(m_params.function))
997         context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
998     if (m_params.function == DrawFunction::DRAW_INDIRECT_BYTE_COUNT_EXT)
999         context.requireDeviceFunctionality("VK_EXT_transform_feedback");
1000 
1001     if (m_params.groupParams->useDynamicRendering)
1002         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
1003 }
1004 
initPrograms(vk::SourceCollections & programCollection) const1005 void VertexAttributeDivisorCase::initPrograms(vk::SourceCollections &programCollection) const
1006 {
1007     std::string vertSrc = "#version 430\n"
1008                           "layout(location = 0) in vec4 in_position;\n"
1009                           "layout(location = 1) in vec4 in_color;\n"
1010                           "layout(location = 2) in vec4 in_color_2;\n"
1011                           "layout(push_constant) uniform TestParams {\n"
1012                           "    float firstInstance;\n"
1013                           "    float instanceCount;\n"
1014                           "} params;\n"
1015                           "layout(location = 0) out vec4 out_color;\n"
1016                           "out gl_PerVertex {\n"
1017                           "    vec4  gl_Position;\n"
1018                           "    float gl_PointSize;\n"
1019                           "};\n"
1020                           "void main() {\n"
1021                           "    gl_PointSize = 1.0;\n"
1022                           "    gl_Position  = in_position + vec4(float(gl_InstanceIndex - params.firstInstance) * 2.0 "
1023                           "/ params.instanceCount, 0.0, 0.0, 0.0);\n"
1024                           "    out_color    = in_color + vec4(float(gl_InstanceIndex) / params.instanceCount, 0.0, "
1025                           "0.0, 1.0) + in_color_2;\n"
1026                           "}\n";
1027 
1028     std::string fragSrc = "#version 430\n"
1029                           "layout(location = 0) in vec4 in_color;\n"
1030                           "layout(location = 0) out vec4 out_color;\n"
1031                           "void main()\n"
1032                           "{\n"
1033                           "    out_color = in_color;\n"
1034                           "}\n";
1035 
1036     programCollection.glslSources.add("vert") << glu::VertexSource(vertSrc);
1037     programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc);
1038 }
1039 
1040 } // namespace
1041 
createVertexAttributeDivisorTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1042 tcu::TestCaseGroup *createVertexAttributeDivisorTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
1043 {
1044     de::MovePtr<tcu::TestCaseGroup> vertexAttributeDivisorGroup(
1045         new tcu::TestCaseGroup(testCtx, "vertex_attribute_divisor", ""));
1046 
1047     const struct
1048     {
1049         Extension extension;
1050         const char *name;
1051         const char *description;
1052     } extensionTests[] = {
1053         {EXT, "ext", "Test VK_EXT_vertex_attribute_divisor"},
1054         {KHR, "khr", "Test VK_KHR_vertex_attribute_divisor"},
1055     };
1056 
1057     const struct
1058     {
1059         PipelineType pipelineType;
1060         const char *name;
1061         const char *description;
1062     } pipelineTests[] = {
1063         {STATIC_PIPELINE, "static_pipeline", "Use a pipeline without dynamic state"},
1064         {DYNAMIC_PIPELINE, "dynamic_pipeline", "Use a pipeline with dynamic state"},
1065         {SHADER_OBJECTS, "shader_objects", "Use shader objects"},
1066     };
1067 
1068     const struct
1069     {
1070         DrawFunction drawFunction;
1071         const char *name;
1072         const char *description;
1073     } drawTests[] = {
1074         {DRAW, "draw", "Test vkCmdDraw"},
1075         {DRAW_INDEXED, "draw_indexed", "Test vkCmdDrawIndexed"},
1076         {DRAW_INDIRECT, "draw_indirect", "Test vkCmdDrawIndirect"},
1077         {DRAW_INDEXED_INDIRECT, "draw_indexed_indirect", "Test vkCmdDrawIndexedIndirect"},
1078         {DRAW_MULTI_EXT, "draw_multi_ext", "Test vkCmdDrawMultiEXT"},
1079         {DRAW_MULTI_INDEXED_EXT, "draw_multi_indexed_ext", "Test vkCmdDrawMultiIndexedEXT"},
1080         {DRAW_INDIRECT_COUNT, "draw_indirect_count", "Test vkCmdDrawIndirectCount"},
1081         {DRAW_INDEXED_INDIRECT_COUNT, "draw_indexed_indirect_count", "Test vkCmdDrawIndexedIndirectCount"},
1082     };
1083 
1084     const struct
1085     {
1086         bool firstInstanceZero;
1087         const char *name;
1088         const char *description;
1089     } firstInstanceTests[] = {
1090         {true, "zero", "First instance 0"},
1091         {false, "non_zero", "First instance not 0"},
1092     };
1093 
1094     const struct
1095     {
1096         uint32_t attribDivisor;
1097         const char *name;
1098     } vertexAttributeDivisorTests[] = {
1099         {
1100             0u,
1101             "0",
1102         },
1103         {
1104             1u,
1105             "1",
1106         },
1107         {
1108             2u,
1109             "2",
1110         },
1111         {
1112             16u,
1113             "16",
1114         },
1115     };
1116 
1117     for (const auto &extensionTest : extensionTests)
1118     {
1119         de::MovePtr<tcu::TestCaseGroup> extensionGroup(
1120             new tcu::TestCaseGroup(testCtx, extensionTest.name, extensionTest.description));
1121 
1122         for (const auto &pipelineTest : pipelineTests)
1123         {
1124             if (pipelineTest.pipelineType == PipelineType::SHADER_OBJECTS && !groupParams->useDynamicRendering)
1125                 continue;
1126 
1127             de::MovePtr<tcu::TestCaseGroup> pipelineGroup(
1128                 new tcu::TestCaseGroup(testCtx, pipelineTest.name, pipelineTest.description));
1129 
1130             for (const auto &drawTest : drawTests)
1131             {
1132                 de::MovePtr<tcu::TestCaseGroup> drawGroup(
1133                     new tcu::TestCaseGroup(testCtx, drawTest.name, drawTest.description));
1134 
1135                 for (const auto &firstInstanceTest : firstInstanceTests)
1136                 {
1137                     de::MovePtr<tcu::TestCaseGroup> firstInstanceGroup(
1138                         new tcu::TestCaseGroup(testCtx, firstInstanceTest.name, firstInstanceTest.description));
1139 
1140                     for (const auto &vertexAttributeDivisorTest : vertexAttributeDivisorTests)
1141                     {
1142                         const TestParams params = {
1143                             extensionTest.extension,                  // Extension extension;
1144                             pipelineTest.pipelineType,                // PipelineType pipelineType;
1145                             drawTest.drawFunction,                    // DrawFunction drawFunction;
1146                             groupParams,                              // const SharedGroupParams groupParams;
1147                             firstInstanceTest.firstInstanceZero,      // bool firstInstanceZero;
1148                             vertexAttributeDivisorTest.attribDivisor, // uint32_t attribDivisor;
1149                         };
1150 
1151                         firstInstanceGroup->addChild(
1152                             new VertexAttributeDivisorCase(testCtx, vertexAttributeDivisorTest.name, params));
1153                     }
1154 
1155                     drawGroup->addChild(firstInstanceGroup.release());
1156                 }
1157 
1158                 pipelineGroup->addChild(drawGroup.release());
1159             }
1160 
1161             extensionGroup->addChild(pipelineGroup.release());
1162         }
1163 
1164         vertexAttributeDivisorGroup->addChild(extensionGroup.release());
1165     }
1166 
1167     return vertexAttributeDivisorGroup.release();
1168 }
1169 
1170 } // namespace Draw
1171 } // namespace vkt
1172