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 ¶ms)
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