1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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 Instanced Draw Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktDrawInstancedTests.hpp"
26
27 #include <climits>
28
29 #include "deSharedPtr.hpp"
30 #include "rrRenderer.hpp"
31 #include "tcuImageCompare.hpp"
32 #include "tcuRGBA.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vktDrawBufferObjectUtil.hpp"
40 #include "vktDrawCreateInfoUtil.hpp"
41 #include "vktDrawImageObjectUtil.hpp"
42 #include "vktDrawTestCaseUtil.hpp"
43
44 namespace vkt
45 {
46 namespace Draw
47 {
48 namespace
49 {
50
51 static const int QUAD_GRID_SIZE = 8;
52 static const int WIDTH = 128;
53 static const int HEIGHT = 128;
54
55 enum AttributeDivisor
56 {
57 ATTRIBUTE_DIVISOR_NONE,
58 ATTRIBUTE_DIVISOR_EXT,
59 ATTRIBUTE_DIVISOR_KHR,
60 };
61
62 struct TestParams
63 {
64 enum DrawFunction
65 {
66 FUNCTION_DRAW = 0,
67 FUNCTION_DRAW_INDEXED,
68 FUNCTION_DRAW_INDIRECT,
69 FUNCTION_DRAW_INDEXED_INDIRECT,
70
71 FUNTION_LAST
72 };
73
74 DrawFunction function;
75 vk::VkPrimitiveTopology topology;
76 const SharedGroupParams groupParams;
77
78 AttributeDivisor testAttribDivisor;
79 uint32_t attribDivisor;
80
81 bool testMultiview;
82
83 bool dynamicState;
84
85 bool useMaintenance5Ext;
86
isIndirectDrawvkt::Draw::__anon5dadb2610111::TestParams87 bool isIndirectDraw(void) const
88 {
89 return (function == FUNCTION_DRAW_INDIRECT || function == FUNCTION_DRAW_INDEXED_INDIRECT);
90 }
91 };
92
93 struct VertexPositionAndColor
94 {
VertexPositionAndColorvkt::Draw::__anon5dadb2610111::VertexPositionAndColor95 VertexPositionAndColor(tcu::Vec4 position_, tcu::Vec4 color_) : position(position_), color(color_)
96 {
97 }
98
99 tcu::Vec4 position;
100 tcu::Vec4 color;
101 };
102
operator <<(std::ostream & str,TestParams const & v)103 std::ostream &operator<<(std::ostream &str, TestParams const &v)
104 {
105 std::ostringstream string;
106
107 if (v.dynamicState)
108 string << "dynamic_state_";
109
110 switch (v.function)
111 {
112 case TestParams::FUNCTION_DRAW:
113 string << "draw";
114 break;
115 case TestParams::FUNCTION_DRAW_INDEXED:
116 string << "draw_indexed";
117 break;
118 case TestParams::FUNCTION_DRAW_INDIRECT:
119 string << "draw_indirect";
120 break;
121 case TestParams::FUNCTION_DRAW_INDEXED_INDIRECT:
122 string << "draw_indexed_indirect";
123 break;
124 default:
125 DE_ASSERT(false);
126 }
127
128 string << "_" << de::toString(v.topology);
129
130 if (v.testAttribDivisor == ATTRIBUTE_DIVISOR_EXT)
131 string << "_attrib_divisor_" << v.attribDivisor;
132 else if (v.testAttribDivisor == ATTRIBUTE_DIVISOR_KHR)
133 string << "_khr_attrib_divisor_" << v.attribDivisor;
134
135 if (v.testMultiview)
136 string << "_multiview";
137
138 return str << string.str();
139 }
140
mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)141 rr::PrimitiveType mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)
142 {
143 switch (primitiveTopology)
144 {
145 case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
146 return rr::PRIMITIVETYPE_POINTS;
147 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
148 return rr::PRIMITIVETYPE_LINES;
149 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
150 return rr::PRIMITIVETYPE_LINE_STRIP;
151 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
152 return rr::PRIMITIVETYPE_TRIANGLES;
153 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
154 return rr::PRIMITIVETYPE_TRIANGLE_FAN;
155 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
156 return rr::PRIMITIVETYPE_TRIANGLE_STRIP;
157 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
158 return rr::PRIMITIVETYPE_LINES_ADJACENCY;
159 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
160 return rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY;
161 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
162 return rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY;
163 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
164 return rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY;
165 default:
166 DE_ASSERT(false);
167 }
168 return rr::PRIMITIVETYPE_LAST;
169 }
170
171 template <typename T>
createAndUploadBuffer(const std::vector<T> data,const vk::DeviceInterface & vk,const Context & context,vk::VkBufferUsageFlags usage)172 de::SharedPtr<Buffer> createAndUploadBuffer(const std::vector<T> data, const vk::DeviceInterface &vk,
173 const Context &context, vk::VkBufferUsageFlags usage)
174 {
175 const vk::VkDeviceSize dataSize = data.size() * sizeof(T);
176 de::SharedPtr<Buffer> buffer =
177 Buffer::createAndAlloc(vk, context.getDevice(), BufferCreateInfo(dataSize, usage),
178 context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
179
180 uint8_t *ptr = reinterpret_cast<uint8_t *>(buffer->getBoundMemory().getHostPtr());
181
182 deMemcpy(ptr, &data[0], static_cast<size_t>(dataSize));
183
184 vk::flushAlloc(vk, context.getDevice(), buffer->getBoundMemory());
185 return buffer;
186 }
187
188 class TestVertShader : public rr::VertexShader
189 {
190 public:
TestVertShader(int numInstances,int firstInstance)191 TestVertShader(int numInstances, int firstInstance)
192 : rr::VertexShader(3, 1)
193 , m_numInstances(numInstances)
194 , m_firstInstance(firstInstance)
195 {
196 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
197 m_inputs[1].type = rr::GENERICVECTYPE_FLOAT;
198 m_inputs[2].type = rr::GENERICVECTYPE_FLOAT;
199 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
200 }
201
~TestVertShader()202 virtual ~TestVertShader()
203 {
204 }
205
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const206 void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
207 {
208 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
209 {
210 const int instanceNdx = packets[packetNdx]->instanceNdx + m_firstInstance;
211 const tcu::Vec4 position = rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx,
212 packets[packetNdx]->vertexNdx, m_firstInstance);
213 const tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1], packets[packetNdx]->instanceNdx,
214 packets[packetNdx]->vertexNdx, m_firstInstance);
215 const tcu::Vec4 color2 = rr::readVertexAttribFloat(inputs[2], packets[packetNdx]->instanceNdx,
216 packets[packetNdx]->vertexNdx, m_firstInstance);
217 packets[packetNdx]->position =
218 position + tcu::Vec4((float)(packets[packetNdx]->instanceNdx * 2.0 / m_numInstances), 0.0, 0.0, 0.0);
219 packets[packetNdx]->outputs[0] =
220 color + tcu::Vec4((float)instanceNdx / (float)m_numInstances, 0.0, 0.0, 1.0) + color2;
221 }
222 }
223
224 private:
225 const int m_numInstances;
226 const int m_firstInstance;
227 };
228
229 class TestFragShader : public rr::FragmentShader
230 {
231 public:
TestFragShader(void)232 TestFragShader(void) : rr::FragmentShader(1, 1)
233 {
234 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
235 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
236 }
237
~TestFragShader()238 virtual ~TestFragShader()
239 {
240 }
241
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const242 void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
243 const rr::FragmentShadingContext &context) const
244 {
245 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
246 {
247 rr::FragmentPacket &packet = packets[packetNdx];
248 for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
249 {
250 const tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
251 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
252 }
253 }
254 }
255 };
256
257 class InstancedDrawInstance : public TestInstance
258 {
259 public:
260 InstancedDrawInstance(Context &context, TestParams params);
261 virtual tcu::TestStatus iterate(void);
262
263 private:
264 void prepareVertexData(int instanceCount, int firstInstance, int instanceDivisor);
265 void preRenderCommands(const vk::VkClearValue &clearColor, uint32_t numLayers);
266 void draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer vertexBuffer, vk::VkBuffer instancedVertexBuffer,
267 de::SharedPtr<Buffer> indexBuffer, de::SharedPtr<Buffer> indirectBuffer, vk::VkDeviceSize indexBufferSize,
268 uint32_t firstInstance, uint32_t instanceCount);
269 void cmdBindIndexBufferImpl(vk::VkCommandBuffer commandBuffer, vk::VkBuffer indexBuffer, vk::VkDeviceSize offset,
270 vk::VkDeviceSize size, vk::VkIndexType indexType);
271
272 #ifndef CTS_USES_VULKANSC
273 void beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags = 0u);
274 #endif // CTS_USES_VULKANSC
275
276 private:
277 const TestParams m_params;
278 const vk::DeviceInterface &m_vk;
279
280 vk::VkFormat m_colorAttachmentFormat;
281
282 vk::Move<vk::VkPipeline> m_pipeline;
283 vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
284
285 de::SharedPtr<Image> m_colorTargetImage;
286 vk::Move<vk::VkImageView> m_colorTargetView;
287
288 PipelineCreateInfo::VertexInputState m_vertexInputState;
289
290 vk::Move<vk::VkCommandPool> m_cmdPool;
291 vk::Move<vk::VkCommandBuffer> m_cmdBuffer;
292 vk::Move<vk::VkCommandBuffer> m_secCmdBuffer;
293
294 vk::Move<vk::VkFramebuffer> m_framebuffer;
295 vk::Move<vk::VkRenderPass> m_renderPass;
296
297 // Vertex data
298 std::vector<VertexPositionAndColor> m_data;
299 std::vector<uint32_t> m_indexes;
300 std::vector<tcu::Vec4> m_instancedColor;
301 };
302
303 class InstancedDrawCase : public TestCase
304 {
305 public:
InstancedDrawCase(tcu::TestContext & testCtx,const std::string & name,TestParams params)306 InstancedDrawCase(tcu::TestContext &testCtx, const std::string &name, TestParams params)
307 : TestCase(testCtx, name)
308 , m_params(params)
309 {
310 m_vertexShader = "#version 430\n"
311 "layout(location = 0) in vec4 in_position;\n"
312 "layout(location = 1) in vec4 in_color;\n"
313 "layout(location = 2) in vec4 in_color_2;\n"
314 "layout(push_constant) uniform TestParams {\n"
315 " float firstInstance;\n"
316 " float instanceCount;\n"
317 "} params;\n"
318 "layout(location = 0) out vec4 out_color;\n"
319 "out gl_PerVertex {\n"
320 " vec4 gl_Position;\n"
321 " float gl_PointSize;\n"
322 "};\n"
323 "void main() {\n"
324 " gl_PointSize = 1.0;\n"
325 " gl_Position = in_position + vec4(float(gl_InstanceIndex - params.firstInstance) * 2.0 / "
326 "params.instanceCount, 0.0, 0.0, 0.0);\n"
327 " out_color = in_color + vec4(float(gl_InstanceIndex) / params.instanceCount, 0.0, 0.0, "
328 "1.0) + in_color_2;\n"
329 "}\n";
330
331 m_fragmentShader = "#version 430\n"
332 "layout(location = 0) in vec4 in_color;\n"
333 "layout(location = 0) out vec4 out_color;\n"
334 "void main()\n"
335 "{\n"
336 " out_color = in_color;\n"
337 "}\n";
338 }
339
checkSupport(Context & context) const340 virtual void checkSupport(Context &context) const
341 {
342 if (m_params.dynamicState)
343 {
344 const auto physicalVertexInputDynamicState = context.getVertexInputDynamicStateFeaturesEXT();
345 if (!physicalVertexInputDynamicState.vertexInputDynamicState)
346 TCU_THROW(NotSupportedError, "Implementation does not support vertexInputDynamicState");
347 }
348 if (m_params.testAttribDivisor == ATTRIBUTE_DIVISOR_EXT)
349 {
350 context.requireDeviceFunctionality("VK_EXT_vertex_attribute_divisor");
351
352 const auto &vertexAttributeDivisorFeatures = context.getVertexAttributeDivisorFeatures();
353 if (m_params.attribDivisor != 1 && !vertexAttributeDivisorFeatures.vertexAttributeInstanceRateDivisor)
354 TCU_THROW(NotSupportedError, "Implementation does not support vertexAttributeInstanceRateDivisor");
355
356 if (m_params.attribDivisor == 0 && !vertexAttributeDivisorFeatures.vertexAttributeInstanceRateZeroDivisor)
357 TCU_THROW(NotSupportedError, "Implementation does not support vertexAttributeInstanceRateDivisorZero");
358 }
359 #ifndef CTS_USES_VULKANSC
360 else if (m_params.testAttribDivisor == ATTRIBUTE_DIVISOR_KHR)
361 {
362 context.requireDeviceFunctionality("VK_KHR_vertex_attribute_divisor");
363
364 const vk::VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR &vertexAttributeDivisorFeatures =
365 context.getVertexAttributeDivisorFeatures();
366
367 if (m_params.attribDivisor != 1 && !vertexAttributeDivisorFeatures.vertexAttributeInstanceRateDivisor)
368 TCU_THROW(NotSupportedError, "Implementation does not support vertexAttributeInstanceRateDivisor");
369
370 if (m_params.attribDivisor == 0 && !vertexAttributeDivisorFeatures.vertexAttributeInstanceRateZeroDivisor)
371 TCU_THROW(NotSupportedError, "Implementation does not support vertexAttributeInstanceRateDivisorZero");
372
373 const vk::VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR &vertexAttributeDivisorProperties =
374 context.getVertexAttributeDivisorProperties();
375
376 if (!vertexAttributeDivisorProperties.supportsNonZeroFirstInstance)
377 TCU_THROW(NotSupportedError, "Implementation does not support supportsNonZeroFirstInstance");
378 }
379 #endif
380
381 if (m_params.testMultiview)
382 {
383 context.requireDeviceFunctionality("VK_KHR_multiview");
384
385 const vk::VkPhysicalDeviceMultiviewFeatures &multiviewFeatures = context.getMultiviewFeatures();
386
387 if (!multiviewFeatures.multiview)
388 TCU_THROW(NotSupportedError, "Implementation does not support multiview feature");
389 }
390
391 #ifndef CTS_USES_VULKANSC
392 if (m_params.groupParams->useDynamicRendering)
393 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
394
395 if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
396 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
397 !context.getPortabilitySubsetFeatures().triangleFans)
398 {
399 TCU_THROW(NotSupportedError,
400 "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
401 }
402
403 if (m_params.useMaintenance5Ext)
404 {
405 context.requireDeviceFunctionality(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
406 }
407 #endif // CTS_USES_VULKANSC
408 }
409
createInstance(Context & context) const410 TestInstance *createInstance(Context &context) const
411 {
412 return new InstancedDrawInstance(context, m_params);
413 }
414
initPrograms(vk::SourceCollections & programCollection) const415 virtual void initPrograms(vk::SourceCollections &programCollection) const
416 {
417 programCollection.glslSources.add("InstancedDrawVert") << glu::VertexSource(m_vertexShader);
418 programCollection.glslSources.add("InstancedDrawFrag") << glu::FragmentSource(m_fragmentShader);
419 }
420
421 private:
422 const TestParams m_params;
423 std::string m_vertexShader;
424 std::string m_fragmentShader;
425 };
426
InstancedDrawInstance(Context & context,TestParams params)427 InstancedDrawInstance::InstancedDrawInstance(Context &context, TestParams params)
428 : TestInstance(context)
429 , m_params(params)
430 , m_vk(context.getDeviceInterface())
431 , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
432 {
433 const vk::VkDevice device = m_context.getDevice();
434 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
435
436 const vk::VkPushConstantRange pushConstantRange = {
437 vk::VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlags stageFlags;
438 0u, // uint32_t offset;
439 (uint32_t)sizeof(float) * 2, // uint32_t size;
440 };
441
442 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo(0, DE_NULL, 1, &pushConstantRange);
443 m_pipelineLayout = vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
444
445 uint32_t arrayLayers = m_params.testMultiview ? 2 : 1;
446 const vk::VkExtent3D targetImageExtent = {WIDTH, HEIGHT, 1};
447 const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1,
448 arrayLayers, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
449 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
450 vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
451 vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
452
453 m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
454 m_context.getUniversalQueueFamilyIndex());
455
456 const enum vk::VkImageViewType imageViewType =
457 m_params.testMultiview ? vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY : vk::VK_IMAGE_VIEW_TYPE_2D;
458 ImageSubresourceRange subresourceRange = ImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
459
460 if (m_params.testMultiview)
461 subresourceRange.layerCount = 2;
462
463 const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), imageViewType, m_colorAttachmentFormat,
464 subresourceRange);
465 m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo);
466
467 if (!m_params.groupParams->useDynamicRendering)
468 {
469 RenderPassCreateInfo renderPassCreateInfo;
470 renderPassCreateInfo.addAttachment(AttachmentDescription(
471 m_colorAttachmentFormat, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
472 vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_STORE,
473 vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_GENERAL));
474
475 const vk::VkAttachmentReference colorAttachmentReference = {0, vk::VK_IMAGE_LAYOUT_GENERAL};
476
477 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1,
478 &colorAttachmentReference, DE_NULL, AttachmentReference(), 0,
479 DE_NULL));
480
481 vk::VkRenderPassMultiviewCreateInfo renderPassMultiviewCreateInfo;
482 // Bit mask that specifies which view rendering is broadcast to
483 // 0011 = Broadcast to first and second view (layer)
484 const uint32_t viewMask = 0x3;
485 // Bit mask that specifices correlation between views
486 // An implementation may use this for optimizations (concurrent render)
487 const uint32_t correlationMask = 0x3;
488
489 if (m_params.testMultiview)
490 {
491 DE_ASSERT(renderPassCreateInfo.subpassCount == 1);
492
493 renderPassMultiviewCreateInfo.sType = vk::VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
494 renderPassMultiviewCreateInfo.pNext = DE_NULL;
495 renderPassMultiviewCreateInfo.subpassCount = renderPassCreateInfo.subpassCount;
496 renderPassMultiviewCreateInfo.pViewMasks = &viewMask;
497 renderPassMultiviewCreateInfo.correlationMaskCount = 1u;
498 renderPassMultiviewCreateInfo.pCorrelationMasks = &correlationMask;
499 renderPassMultiviewCreateInfo.pViewOffsets = DE_NULL;
500 renderPassMultiviewCreateInfo.dependencyCount = 0u;
501
502 renderPassCreateInfo.pNext = &renderPassMultiviewCreateInfo;
503 }
504
505 m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
506
507 // create framebuffer
508 std::vector<vk::VkImageView> colorAttachments{*m_colorTargetView};
509 const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
510 m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
511 }
512
513 const vk::VkVertexInputBindingDescription vertexInputBindingDescription[2] = {
514 {
515 0u,
516 (uint32_t)sizeof(VertexPositionAndColor),
517 vk::VK_VERTEX_INPUT_RATE_VERTEX,
518 },
519 {
520 1u,
521 (uint32_t)sizeof(tcu::Vec4),
522 vk::VK_VERTEX_INPUT_RATE_INSTANCE,
523 },
524 };
525
526 const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
527 {0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
528 {
529 1u,
530 0u,
531 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
532 (uint32_t)sizeof(tcu::Vec4),
533 },
534 {
535 2u,
536 1u,
537 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
538 0,
539 }};
540
541 m_vertexInputState = PipelineCreateInfo::VertexInputState(2, vertexInputBindingDescription,
542 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),
543 vertexInputAttributeDescriptions);
544
545 const vk::VkVertexInputBindingDivisorDescriptionEXT vertexInputBindingDivisorDescription = {
546 1u,
547 m_params.attribDivisor,
548 };
549
550 if (m_params.testAttribDivisor != ATTRIBUTE_DIVISOR_NONE)
551 m_vertexInputState.addDivisors(1, &vertexInputBindingDivisorDescription);
552
553 const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
554 m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
555 m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
556 if (m_params.groupParams->useSecondaryCmdBuffer)
557 m_secCmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
558
559 const vk::Unique<vk::VkShaderModule> vs(
560 createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawVert"), 0));
561 const vk::Unique<vk::VkShaderModule> fs(
562 createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawFrag"), 0));
563
564 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
565
566 vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
567 vk::VkRect2D scissor = vk::makeRect2D(WIDTH, HEIGHT);
568
569 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
570 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
571 pipelineCreateInfo.addShader(
572 PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
573 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_params.topology));
574 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
575 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport),
576 std::vector<vk::VkRect2D>(1, scissor)));
577 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
578 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
579 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
580
581 if (m_params.dynamicState)
582 {
583 vk::VkDynamicState dynStates[] = {vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT};
584
585 vk::VkPipelineDynamicStateCreateInfo dynamicState{vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
586 DE_NULL, 0, 1, dynStates};
587 pipelineCreateInfo.addState(dynamicState);
588 }
589 else
590 {
591 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
592 }
593
594 #ifndef CTS_USES_VULKANSC
595 vk::VkPipelineRenderingCreateInfoKHR renderingFormatCreateInfo{
596 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
597 DE_NULL,
598 0u,
599 1u,
600 &m_colorAttachmentFormat,
601 vk::VK_FORMAT_UNDEFINED,
602 vk::VK_FORMAT_UNDEFINED};
603
604 if (m_params.groupParams->useDynamicRendering)
605 {
606 pipelineCreateInfo.pNext = &renderingFormatCreateInfo;
607
608 if (m_params.testMultiview)
609 renderingFormatCreateInfo.viewMask = 3u;
610 }
611 #endif // CTS_USES_VULKANSC
612
613 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
614 }
615
iterate()616 tcu::TestStatus InstancedDrawInstance::iterate()
617 {
618 const vk::VkQueue queue = m_context.getUniversalQueue();
619 const vk::VkDevice device = m_context.getDevice();
620 static const uint32_t instanceCounts[] = {0, 1, 2, 4, 20};
621 static const uint32_t firstInstanceIndices[] = {0, 1, 3, 4, 20};
622 const uint32_t numLayers = m_params.testMultiview ? 2 : 1;
623 const vk::VkRect2D renderArea = vk::makeRect2D(WIDTH, HEIGHT);
624
625 qpTestResult res = QP_TEST_RESULT_PASS;
626
627 const vk::VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
628 int firstInstanceIndicesCount = DE_LENGTH_OF_ARRAY(firstInstanceIndices);
629
630 // Require 'drawIndirectFirstInstance' feature to run non-zero firstInstance indirect draw tests.
631 const auto &deviceFeatures = m_context.getDeviceFeatures();
632 if (m_params.isIndirectDraw() && !deviceFeatures.drawIndirectFirstInstance)
633 {
634 firstInstanceIndicesCount = 1;
635 }
636
637 for (int instanceCountNdx = 0; instanceCountNdx < DE_LENGTH_OF_ARRAY(instanceCounts); instanceCountNdx++)
638 {
639 const uint32_t instanceCount = instanceCounts[instanceCountNdx];
640 for (int firstInstanceIndexNdx = 0; firstInstanceIndexNdx < firstInstanceIndicesCount; firstInstanceIndexNdx++)
641 {
642 // Prepare vertex data for at least one instance
643 const uint32_t prepareCount = de::max(instanceCount, 1u);
644 const uint32_t firstInstance = firstInstanceIndices[firstInstanceIndexNdx];
645
646 prepareVertexData(prepareCount, firstInstance,
647 (m_params.testAttribDivisor != ATTRIBUTE_DIVISOR_NONE) ? m_params.attribDivisor : 1);
648 const de::SharedPtr<Buffer> vertexBuffer =
649 createAndUploadBuffer(m_data, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
650 const de::SharedPtr<Buffer> instancedVertexBuffer =
651 createAndUploadBuffer(m_instancedColor, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
652
653 de::SharedPtr<Buffer> indexBuffer;
654 if (m_params.function == TestParams::FUNCTION_DRAW_INDEXED ||
655 m_params.function == TestParams::FUNCTION_DRAW_INDEXED_INDIRECT)
656 indexBuffer = createAndUploadBuffer(m_indexes, m_vk, m_context, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
657
658 de::SharedPtr<Buffer> indirectBuffer;
659 if (m_params.function == TestParams::FUNCTION_DRAW_INDIRECT)
660 {
661 std::vector<vk::VkDrawIndirectCommand> drawCommands;
662 drawCommands.push_back({
663 (uint32_t)m_data.size(), // uint32_t vertexCount;
664 instanceCount, // uint32_t instanceCount;
665 0u, // uint32_t firstVertex;
666 firstInstance // uint32_t firstInstance;
667 });
668 indirectBuffer =
669 createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
670 }
671 if (m_params.function == TestParams::FUNCTION_DRAW_INDEXED_INDIRECT)
672 {
673 std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands;
674 drawCommands.push_back({
675 (uint32_t)m_indexes.size(), // uint32_t indexCount;
676 instanceCount, // uint32_t instanceCount;
677 0u, // uint32_t firstIndex;
678 0, // int32_t vertexOffset;
679 firstInstance // uint32_t firstInstance;
680 });
681 indirectBuffer =
682 createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
683 }
684
685 #ifndef CTS_USES_VULKANSC
686 const uint32_t layerCount = (m_params.testMultiview) ? 2u : 1u;
687 const uint32_t viewMask = (m_params.testMultiview) ? 3u : 0u;
688 if (m_params.groupParams->useSecondaryCmdBuffer)
689 {
690 // record secondary command buffer
691 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
692 {
693 beginSecondaryCmdBuffer(vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
694 beginRendering(m_vk, *m_secCmdBuffer, *m_colorTargetView, renderArea, clearColor,
695 vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD, 0u, layerCount,
696 viewMask);
697 }
698 else
699 beginSecondaryCmdBuffer();
700
701 draw(*m_secCmdBuffer, vertexBuffer->object(), instancedVertexBuffer->object(), indexBuffer,
702 indirectBuffer, (m_indexes.size() * sizeof(uint32_t)), firstInstance, instanceCount);
703
704 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
705 endRendering(m_vk, *m_secCmdBuffer);
706
707 endCommandBuffer(m_vk, *m_secCmdBuffer);
708
709 // record primary command buffer
710 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
711
712 preRenderCommands(clearColor, numLayers);
713
714 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
715 {
716 beginRendering(m_vk, *m_cmdBuffer, *m_colorTargetView, renderArea, clearColor,
717 vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
718 vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR, layerCount, viewMask);
719 }
720
721 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
722
723 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
724 endRendering(m_vk, *m_cmdBuffer);
725
726 endCommandBuffer(m_vk, *m_cmdBuffer);
727 }
728 else if (m_params.groupParams->useDynamicRendering)
729 {
730 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
731 preRenderCommands(clearColor, numLayers);
732
733 beginRendering(m_vk, *m_cmdBuffer, *m_colorTargetView, renderArea, clearColor,
734 vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD, 0u, layerCount, viewMask);
735 draw(*m_cmdBuffer, vertexBuffer->object(), instancedVertexBuffer->object(), indexBuffer, indirectBuffer,
736 (m_indexes.size() * sizeof(uint32_t)), firstInstance, instanceCount);
737 endRendering(m_vk, *m_cmdBuffer);
738
739 endCommandBuffer(m_vk, *m_cmdBuffer);
740 }
741 #endif // CTS_USES_VULKANSC
742
743 if (!m_params.groupParams->useDynamicRendering)
744 {
745 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
746 preRenderCommands(clearColor, numLayers);
747
748 beginRenderPass(m_vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, renderArea);
749 draw(*m_cmdBuffer, vertexBuffer->object(), instancedVertexBuffer->object(), indexBuffer, indirectBuffer,
750 (m_indexes.size() * sizeof(uint32_t)), firstInstance, instanceCount);
751 endRenderPass(m_vk, *m_cmdBuffer);
752
753 endCommandBuffer(m_vk, *m_cmdBuffer);
754 }
755
756 /*
757
758 void InstancedDrawInstance::beginRender(vk::VkCommandBuffer cmdBuffer, const vk::VkClearValue& clearColor, vk::VkRenderingFlagsKHR renderingFlags)
759 {
760
761 if (m_params.groupParams->useDynamicRendering)
762 else
763 */
764
765 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
766 m_context.resetCommandPoolForVKSC(device, *m_cmdPool);
767
768 // Reference rendering
769 std::vector<tcu::Vec4> vetrices;
770 std::vector<tcu::Vec4> colors;
771
772 for (std::vector<VertexPositionAndColor>::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
773 {
774 vetrices.push_back(it->position);
775 colors.push_back(it->color);
776 }
777
778 tcu::TextureLevel refImage(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH),
779 (int)(0.5 + HEIGHT));
780
781 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
782
783 const TestVertShader vertShader(instanceCount, firstInstance);
784 const TestFragShader fragShader;
785 const rr::Program program(&vertShader, &fragShader);
786 const rr::MultisamplePixelBufferAccess colorBuffer =
787 rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refImage.getAccess());
788 const rr::RenderTarget renderTarget(colorBuffer);
789 const rr::RenderState renderState((rr::ViewportState(colorBuffer)),
790 m_context.getDeviceProperties().limits.subPixelPrecisionBits);
791 const rr::Renderer renderer;
792
793 const rr::VertexAttrib vertexAttribs[] = {
794 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vetrices[0]),
795 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0]),
796 // The reference renderer treats a divisor of 0 as meaning per-vertex. Use INT_MAX instead; it should work just as well.
797 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4),
798 (m_params.testAttribDivisor != ATTRIBUTE_DIVISOR_NONE) ?
799 (m_params.attribDivisor == 0 ? INT_MAX : m_params.attribDivisor) :
800 1,
801 &m_instancedColor[0])};
802
803 if (m_params.function == TestParams::FUNCTION_DRAW ||
804 m_params.function == TestParams::FUNCTION_DRAW_INDIRECT)
805 {
806 const rr::PrimitiveList primitives =
807 rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)vetrices.size(), 0);
808 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
809 &vertexAttribs[0], primitives);
810 renderer.drawInstanced(command, instanceCount);
811 }
812 else
813 {
814 const rr::DrawIndices indicies(m_indexes.data());
815
816 const rr::PrimitiveList primitives =
817 rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)m_indexes.size(), indicies);
818 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
819 &vertexAttribs[0], primitives);
820 renderer.drawInstanced(command, instanceCount);
821 }
822
823 const vk::VkOffset3D zeroOffset = {0, 0, 0};
824 for (uint32_t i = 0; i < numLayers; i++)
825 {
826 const tcu::ConstPixelBufferAccess renderedFrame =
827 m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
828 zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT, 0, i);
829
830 tcu::TestLog &log = m_context.getTestContext().getLog();
831
832 std::ostringstream resultDesc;
833 resultDesc << "Image layer " << i << " comparison result. Instance count: " << instanceCount
834 << " first instance index: " << firstInstance;
835
836 if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
837 {
838 const bool ok = tcu::intThresholdPositionDeviationCompare(
839 log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame,
840 tcu::UVec4(4u), // color threshold
841 tcu::IVec3(1, 1, 0), // position deviation tolerance
842 true, // don't check the pixels at the boundary
843 tcu::COMPARE_LOG_RESULT);
844
845 if (!ok)
846 res = QP_TEST_RESULT_FAIL;
847 }
848 else
849 {
850 if (!tcu::fuzzyCompare(log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame,
851 0.05f, tcu::COMPARE_LOG_RESULT))
852 res = QP_TEST_RESULT_FAIL;
853 }
854 }
855 }
856 }
857 return tcu::TestStatus(res, qpGetTestResultName(res));
858 }
859
prepareVertexData(int instanceCount,int firstInstance,int instanceDivisor)860 void InstancedDrawInstance::prepareVertexData(int instanceCount, int firstInstance, int instanceDivisor)
861 {
862 m_data.clear();
863 m_indexes.clear();
864 m_instancedColor.clear();
865
866 if (m_params.function == TestParams::FUNCTION_DRAW || m_params.function == TestParams::FUNCTION_DRAW_INDIRECT)
867 {
868 for (int y = 0; y < QUAD_GRID_SIZE; y++)
869 {
870 for (int x = 0; x < QUAD_GRID_SIZE; x++)
871 {
872 const float fx0 = -1.0f + (float)(x + 0) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
873 const float fx1 = -1.0f + (float)(x + 1) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
874 const float fy0 = -1.0f + (float)(y + 0) / (float)QUAD_GRID_SIZE * 2.0f;
875 const float fy1 = -1.0f + (float)(y + 1) / (float)QUAD_GRID_SIZE * 2.0f;
876
877 // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1)
878 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
879 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
880 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
881
882 // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0)
883 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
884 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
885 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
886 }
887 }
888 }
889 else
890 {
891 for (int y = 0; y < QUAD_GRID_SIZE + 1; y++)
892 {
893 for (int x = 0; x < QUAD_GRID_SIZE + 1; x++)
894 {
895 const float fx = -1.0f + (float)x / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
896 const float fy = -1.0f + (float)y / (float)QUAD_GRID_SIZE * 2.0f;
897
898 m_data.push_back(VertexPositionAndColor(
899 tcu::Vec4(fx, fy, 1.0f, 1.0f), (y % 2 ? tcu::RGBA::blue().toVec() : tcu::RGBA::green().toVec())));
900 }
901 }
902
903 for (int y = 0; y < QUAD_GRID_SIZE; y++)
904 {
905 for (int x = 0; x < QUAD_GRID_SIZE; x++)
906 {
907 const int ndx00 = y * (QUAD_GRID_SIZE + 1) + x;
908 const int ndx10 = y * (QUAD_GRID_SIZE + 1) + x + 1;
909 const int ndx01 = (y + 1) * (QUAD_GRID_SIZE + 1) + x;
910 const int ndx11 = (y + 1) * (QUAD_GRID_SIZE + 1) + x + 1;
911
912 // Lower-left triangle of a quad.
913 m_indexes.push_back((uint16_t)ndx00);
914 m_indexes.push_back((uint16_t)ndx10);
915 m_indexes.push_back((uint16_t)ndx01);
916
917 // Upper-right triangle of a quad.
918 m_indexes.push_back((uint16_t)ndx11);
919 m_indexes.push_back((uint16_t)ndx01);
920 m_indexes.push_back((uint16_t)ndx10);
921 }
922 }
923 }
924
925 const int colorCount =
926 instanceDivisor == 0 ? 1 : (instanceCount + firstInstance + instanceDivisor - 1) / instanceDivisor;
927 for (int i = 0; i < instanceCount + firstInstance; i++)
928 {
929 m_instancedColor.push_back(tcu::Vec4(0.0, (float)(1.0 - i * 1.0 / colorCount) / 2, 0.0, 1.0));
930 }
931 }
932
preRenderCommands(const vk::VkClearValue & clearColor,uint32_t numLayers)933 void InstancedDrawInstance::preRenderCommands(const vk::VkClearValue &clearColor, uint32_t numLayers)
934 {
935 const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, numLayers);
936
937 if (m_params.testMultiview)
938 {
939 vk::VkImageMemoryBarrier barrier{
940 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
941 DE_NULL, // const void* pNext;
942 0u, // VkAccessFlags srcAccessMask;
943 vk::VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
944 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
945 vk::VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout;
946 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
947 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
948 m_colorTargetImage->object(), // VkImage image;
949 subresourceRange // VkImageSubresourceRange subresourceRange;
950 };
951
952 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
953 (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 0,
954 (const vk::VkBufferMemoryBarrier *)DE_NULL, 1, &barrier);
955 }
956 else
957 {
958 initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
959 vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
960 }
961
962 m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor.color,
963 1, &subresourceRange);
964
965 const vk::VkMemoryBarrier memBarrier{
966 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, vk::VK_ACCESS_TRANSFER_WRITE_BIT,
967 vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT};
968
969 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
970 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0,
971 DE_NULL);
972 }
973
cmdBindIndexBufferImpl(vk::VkCommandBuffer commandBuffer,vk::VkBuffer indexBuffer,vk::VkDeviceSize offset,vk::VkDeviceSize size,vk::VkIndexType indexType)974 void InstancedDrawInstance::cmdBindIndexBufferImpl(vk::VkCommandBuffer commandBuffer, vk::VkBuffer indexBuffer,
975 vk::VkDeviceSize offset, vk::VkDeviceSize size,
976 vk::VkIndexType indexType)
977 {
978 #ifndef CTS_USES_VULKANSC
979 if (m_params.useMaintenance5Ext)
980 m_vk.cmdBindIndexBuffer2KHR(commandBuffer, indexBuffer, offset, size, indexType);
981 else
982 #endif
983 {
984 DE_UNREF(size);
985 m_vk.cmdBindIndexBuffer(commandBuffer, indexBuffer, offset, indexType);
986 }
987 }
988
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer vertexBuffer,vk::VkBuffer instancedVertexBuffer,de::SharedPtr<Buffer> indexBuffer,de::SharedPtr<Buffer> indirectBuffer,vk::VkDeviceSize indexBufferSize,uint32_t firstInstance,uint32_t instanceCount)989 void InstancedDrawInstance::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer vertexBuffer,
990 vk::VkBuffer instancedVertexBuffer, de::SharedPtr<Buffer> indexBuffer,
991 de::SharedPtr<Buffer> indirectBuffer, vk::VkDeviceSize indexBufferSize,
992 uint32_t firstInstance, uint32_t instanceCount)
993 {
994 if (m_params.function == TestParams::FUNCTION_DRAW_INDEXED ||
995 m_params.function == TestParams::FUNCTION_DRAW_INDEXED_INDIRECT)
996 cmdBindIndexBufferImpl(cmdBuffer, indexBuffer->object(), 0, indexBufferSize, vk::VK_INDEX_TYPE_UINT32);
997
998 const vk::VkBuffer vertexBuffers[]{vertexBuffer, instancedVertexBuffer};
999 const vk::VkDeviceSize vertexBufferOffsets[]{0, 0};
1000
1001 m_vk.cmdBindVertexBuffers(cmdBuffer, 0, DE_LENGTH_OF_ARRAY(vertexBuffers), vertexBuffers, vertexBufferOffsets);
1002
1003 const float pushConstants[] = {(float)firstInstance, (float)instanceCount};
1004 m_vk.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u,
1005 (uint32_t)sizeof(pushConstants), pushConstants);
1006 m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1007
1008 if (m_params.dynamicState)
1009 {
1010 vk::VkVertexInputBindingDescription2EXT vertexBindingDescription[2]{
1011 {vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT, 0, 0u,
1012 (uint32_t)sizeof(VertexPositionAndColor), vk::VK_VERTEX_INPUT_RATE_VERTEX, 1},
1013 {vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT, 0, 1u, (uint32_t)sizeof(tcu::Vec4),
1014 vk::VK_VERTEX_INPUT_RATE_INSTANCE, m_params.attribDivisor},
1015
1016 };
1017 vk::VkVertexInputAttributeDescription2EXT vertexAttributeDescription[3]{
1018 {vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, 0, 0u, 0u,
1019 vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
1020 {
1021 vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
1022 0,
1023 1u,
1024 0u,
1025 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
1026 (uint32_t)sizeof(tcu::Vec4),
1027 },
1028 {
1029 vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
1030 0,
1031 2u,
1032 1u,
1033 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
1034 0,
1035 }};
1036
1037 m_vk.cmdSetVertexInputEXT(cmdBuffer, 2, vertexBindingDescription, 3, vertexAttributeDescription);
1038 }
1039
1040 switch (m_params.function)
1041 {
1042 case TestParams::FUNCTION_DRAW:
1043 m_vk.cmdDraw(cmdBuffer, (uint32_t)m_data.size(), instanceCount, 0u, firstInstance);
1044 break;
1045
1046 case TestParams::FUNCTION_DRAW_INDEXED:
1047 m_vk.cmdDrawIndexed(cmdBuffer, (uint32_t)m_indexes.size(), instanceCount, 0u, 0u, firstInstance);
1048 break;
1049
1050 case TestParams::FUNCTION_DRAW_INDIRECT:
1051 m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
1052 break;
1053
1054 case TestParams::FUNCTION_DRAW_INDEXED_INDIRECT:
1055 m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
1056 break;
1057
1058 default:
1059 DE_ASSERT(false);
1060 }
1061 }
1062
1063 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)1064 void InstancedDrawInstance::beginSecondaryCmdBuffer(vk::VkRenderingFlagsKHR renderingFlags)
1065 {
1066 const vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
1067 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
1068 DE_NULL, // const void* pNext;
1069 renderingFlags, // VkRenderingFlagsKHR flags;
1070 (m_params.testMultiview) ? 3u : 0u, // uint32_t viewMask;
1071 1u, // uint32_t colorAttachmentCount;
1072 &m_colorAttachmentFormat, // const VkFormat* pColorAttachmentFormats;
1073 vk::VK_FORMAT_UNDEFINED, // VkFormat depthAttachmentFormat;
1074 vk::VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat;
1075 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
1076 };
1077
1078 const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo{
1079 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
1080 &inheritanceRenderingInfo, // const void* pNext;
1081 DE_NULL, // VkRenderPass renderPass;
1082 0u, // uint32_t subpass;
1083 DE_NULL, // VkFramebuffer framebuffer;
1084 VK_FALSE, // VkBool32 occlusionQueryEnable;
1085 (vk::VkQueryControlFlags)0u, // VkQueryControlFlags queryFlags;
1086 (vk::VkQueryPipelineStatisticFlags)0u // VkQueryPipelineStatisticFlags pipelineStatistics;
1087 };
1088
1089 vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1090 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1091 usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
1092
1093 const vk::VkCommandBufferBeginInfo commandBufBeginParams{
1094 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
1095 DE_NULL, // const void* pNext;
1096 usageFlags, // VkCommandBufferUsageFlags flags;
1097 &bufferInheritanceInfo};
1098
1099 VK_CHECK(m_vk.beginCommandBuffer(*m_secCmdBuffer, &commandBufBeginParams));
1100 }
1101 #endif // CTS_USES_VULKANSC
1102
1103 } // namespace
1104
InstancedTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1105 InstancedTests::InstancedTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
1106 : TestCaseGroup(testCtx, "instanced")
1107 , m_groupParams(groupParams)
1108 {
1109 static const vk::VkPrimitiveTopology topologies[] = {
1110 vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
1111 vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1112 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
1113 };
1114 static const TestParams::DrawFunction functions[] = {
1115 TestParams::FUNCTION_DRAW,
1116 TestParams::FUNCTION_DRAW_INDEXED,
1117 TestParams::FUNCTION_DRAW_INDIRECT,
1118 TestParams::FUNCTION_DRAW_INDEXED_INDIRECT,
1119 };
1120 static const AttributeDivisor attribDivisors[] = {
1121 ATTRIBUTE_DIVISOR_NONE,
1122 ATTRIBUTE_DIVISOR_EXT,
1123 #ifndef CTS_USES_VULKANSC
1124 ATTRIBUTE_DIVISOR_KHR,
1125 #endif
1126 };
1127
1128 static const bool multiviews[] = {false, true};
1129
1130 static const uint32_t divisors[] = {0, 1, 2, 4, 20};
1131 for (int dynState = 0; dynState < 2; dynState++)
1132 {
1133 for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(topologies); topologyNdx++)
1134 {
1135 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1136 if (groupParams->useSecondaryCmdBuffer && (topologyNdx % 2u))
1137 continue;
1138
1139 for (int functionNdx = 0; functionNdx < DE_LENGTH_OF_ARRAY(functions); functionNdx++)
1140 {
1141 for (int testAttribDivisor = 0; testAttribDivisor < DE_LENGTH_OF_ARRAY(attribDivisors);
1142 testAttribDivisor++)
1143 {
1144 AttributeDivisor attribDivisor = attribDivisors[testAttribDivisor];
1145 for (int divisorNdx = 0; divisorNdx < DE_LENGTH_OF_ARRAY(divisors); divisorNdx++)
1146 {
1147 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1148 if (groupParams->useSecondaryCmdBuffer && (divisorNdx % 2u))
1149 continue;
1150
1151 for (int multiviewNdx = 0; multiviewNdx < DE_LENGTH_OF_ARRAY(multiviews); multiviewNdx++)
1152 {
1153 // If we don't have VK_EXT_vertex_attribute_divisor or VK_KHR_vertex_attribute_divisor, we only get a divisor or 1.
1154 if (attribDivisor == ATTRIBUTE_DIVISOR_NONE && divisors[divisorNdx] != 1)
1155 continue;
1156
1157 TestParams param{
1158 functions[functionNdx], // DrawFunction function;
1159 topologies[topologyNdx], // vk::VkPrimitiveTopology topology;
1160 groupParams, // const SharedGroupParams groupParams;
1161 attribDivisor, // AttributeDivisor testAttribDivisor;
1162 divisors[divisorNdx], // uint32_t attribDivisor;
1163 multiviews[multiviewNdx], // bool testMultiview;
1164 dynState == 0 ? false : true, // bool dynamicState;
1165 false // bool useMaintenance5Ext;
1166 };
1167
1168 // Add multiview tests only when vertex attribute divisor is enabled.
1169 if (param.testMultiview && !testAttribDivisor)
1170 continue;
1171
1172 std::string testName = de::toString(param);
1173
1174 addChild(new InstancedDrawCase(m_testCtx, de::toLower(testName), param));
1175
1176 #ifndef CTS_USES_VULKANSC
1177 if (TestParams::FUNCTION_DRAW_INDEXED == functions[functionNdx] ||
1178 TestParams::FUNCTION_DRAW_INDEXED_INDIRECT == functions[functionNdx])
1179 {
1180 param.useMaintenance5Ext = true;
1181 testName += "_maintenance_5";
1182 // Instanced drawing test using vkCmdBindIndexBuffer2KHR() introduced in VK_KHR_maintenance5
1183 addChild(new InstancedDrawCase(m_testCtx, de::toLower(testName), param));
1184 }
1185 #endif // CTS_USES_VULKANSC
1186 }
1187 }
1188 }
1189 }
1190 }
1191 }
1192 }
1193
~InstancedTests()1194 InstancedTests::~InstancedTests()
1195 {
1196 }
1197
1198 } // namespace Draw
1199 } // namespace vkt
1200