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 Simple Draw Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktBasicDrawTests.hpp"
26
27 #include "vktDrawBaseClass.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32
33 #include "deDefs.h"
34 #include "deRandom.hpp"
35 #include "deString.h"
36
37 #include "tcuTestCase.hpp"
38 #include "tcuRGBA.hpp"
39 #include "tcuTextureUtil.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuVectorUtil.hpp"
42
43 #include "rrRenderer.hpp"
44
45 #include <string>
46 #include <sstream>
47
48 namespace vkt
49 {
50 namespace Draw
51 {
52 namespace
53 {
54 static const deUint32 SEED = 0xc2a39fu;
55 static const deUint32 INDEX_LIMIT = 10000;
56 // To avoid too big and mostly empty structures
57 static const deUint32 OFFSET_LIMIT = 1000;
58 // Number of primitives to draw
59 static const deUint32 PRIMITIVE_COUNT[] = {1, 3, 17, 45};
60
61 enum DrawCommandType
62 {
63 DRAW_COMMAND_TYPE_DRAW,
64 DRAW_COMMAND_TYPE_DRAW_INDEXED,
65 DRAW_COMMAND_TYPE_DRAW_INDIRECT,
66 DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT,
67
68 DRAW_COMMAND_TYPE_DRAW_LAST
69 };
70
getDrawCommandTypeName(DrawCommandType command)71 const char* getDrawCommandTypeName (DrawCommandType command)
72 {
73 switch (command)
74 {
75 case DRAW_COMMAND_TYPE_DRAW: return "draw";
76 case DRAW_COMMAND_TYPE_DRAW_INDEXED: return "draw_indexed";
77 case DRAW_COMMAND_TYPE_DRAW_INDIRECT: return "draw_indirect";
78 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT: return "draw_indexed_indirect";
79 default: DE_ASSERT(false);
80 }
81 return "";
82 }
83
mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)84 rr::PrimitiveType mapVkPrimitiveTopology (vk::VkPrimitiveTopology primitiveTopology)
85 {
86 switch (primitiveTopology)
87 {
88 case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST: return rr::PRIMITIVETYPE_POINTS;
89 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST: return rr::PRIMITIVETYPE_LINES;
90 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: return rr::PRIMITIVETYPE_LINE_STRIP;
91 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: return rr::PRIMITIVETYPE_TRIANGLES;
92 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: return rr::PRIMITIVETYPE_TRIANGLE_FAN;
93 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: return rr::PRIMITIVETYPE_TRIANGLE_STRIP;
94 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: return rr::PRIMITIVETYPE_LINES_ADJACENCY;
95 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: return rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY;
96 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: return rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY;
97 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: return rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY;
98 default:
99 DE_ASSERT(false);
100 }
101 return rr::PRIMITIVETYPE_LAST;
102 }
103
104 struct DrawParamsBase
105 {
106 std::vector<PositionColorVertex> vertices;
107 vk::VkPrimitiveTopology topology;
108 GroupParams groupParams; // we can't use SharedGroupParams here
109
DrawParamsBasevkt::Draw::__anona9f947520111::DrawParamsBase110 DrawParamsBase ()
111 {}
112
DrawParamsBasevkt::Draw::__anona9f947520111::DrawParamsBase113 DrawParamsBase (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
114 : topology (top)
115 , groupParams
116 {
117 gParams->useDynamicRendering,
118 gParams->useSecondaryCmdBuffer,
119 gParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass
120 }
121 {}
122 };
123
124 struct IndexedParamsBase
125 {
126 std::vector<deUint32> indexes;
127 const vk::VkIndexType indexType;
128
IndexedParamsBasevkt::Draw::__anona9f947520111::IndexedParamsBase129 IndexedParamsBase (const vk::VkIndexType indexT)
130 : indexType (indexT)
131 {}
132 };
133
134 // Structs to store draw parameters
135 struct DrawParams : DrawParamsBase
136 {
137 // vkCmdDraw parameters is like a single VkDrawIndirectCommand
138 vk::VkDrawIndirectCommand params;
139
DrawParamsvkt::Draw::__anona9f947520111::DrawParams140 DrawParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
141 : DrawParamsBase (top, gParams)
142 {
143 params.vertexCount = vertexC;
144 params.instanceCount = instanceC;
145 params.firstVertex = firstV;
146 params.firstInstance = firstI;
147 }
148 };
149
150 struct DrawIndexedParams : DrawParamsBase, IndexedParamsBase
151 {
152 // vkCmdDrawIndexed parameters is like a single VkDrawIndexedIndirectCommand
153 vk::VkDrawIndexedIndirectCommand params;
154
DrawIndexedParamsvkt::Draw::__anona9f947520111::DrawIndexedParams155 DrawIndexedParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const vk::VkIndexType indexT, const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
156 : DrawParamsBase (top, gParams)
157 , IndexedParamsBase (indexT)
158 {
159 params.indexCount = indexC;
160 params.instanceCount = instanceC;
161 params.firstIndex = firstIdx;
162 params.vertexOffset = vertexO;
163 params.firstInstance = firstIns;
164 }
165 };
166
167 struct DrawIndirectParams : DrawParamsBase
168 {
169 std::vector<vk::VkDrawIndirectCommand> commands;
170
DrawIndirectParamsvkt::Draw::__anona9f947520111::DrawIndirectParams171 DrawIndirectParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
172 : DrawParamsBase (top, gParams)
173 {}
174
addCommandvkt::Draw::__anona9f947520111::DrawIndirectParams175 void addCommand (const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
176 {
177 vk::VkDrawIndirectCommand cmd;
178 cmd.vertexCount = vertexC;
179 cmd.instanceCount = instanceC;
180 cmd.firstVertex = firstV;
181 cmd.firstInstance = firstI;
182
183 commands.push_back(cmd);
184 }
185 };
186
187 struct DrawIndexedIndirectParams : DrawParamsBase, IndexedParamsBase
188 {
189 std::vector<vk::VkDrawIndexedIndirectCommand> commands;
190
DrawIndexedIndirectParamsvkt::Draw::__anona9f947520111::DrawIndexedIndirectParams191 DrawIndexedIndirectParams (const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const vk::VkIndexType indexT)
192 : DrawParamsBase (top, gParams)
193 , IndexedParamsBase (indexT)
194 {}
195
addCommandvkt::Draw::__anona9f947520111::DrawIndexedIndirectParams196 void addCommand (const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
197 {
198 vk::VkDrawIndexedIndirectCommand cmd;
199 cmd.indexCount = indexC;
200 cmd.instanceCount = instanceC;
201 cmd.firstIndex = firstIdx;
202 cmd.vertexOffset = vertexO;
203 cmd.firstInstance = firstIns;
204
205 commands.push_back(cmd);
206 }
207 };
208
209 // Reference renderer shaders
210 class PassthruVertShader : public rr::VertexShader
211 {
212 public:
PassthruVertShader(void)213 PassthruVertShader (void)
214 : rr::VertexShader (2, 1)
215 {
216 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
217 m_inputs[1].type = rr::GENERICVECTYPE_FLOAT;
218 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
219 }
220
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const221 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
222 {
223 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
224 {
225 packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0],
226 packets[packetNdx]->instanceNdx,
227 packets[packetNdx]->vertexNdx);
228
229 tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1],
230 packets[packetNdx]->instanceNdx,
231 packets[packetNdx]->vertexNdx);
232
233 packets[packetNdx]->outputs[0] = color;
234 }
235 }
236 };
237
238 class PassthruFragShader : public rr::FragmentShader
239 {
240 public:
PassthruFragShader(void)241 PassthruFragShader (void)
242 : rr::FragmentShader(1, 1)
243 {
244 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
245 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
246 }
247
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const248 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
249 {
250 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
251 {
252 rr::FragmentPacket& packet = packets[packetNdx];
253 for (deUint32 fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
254 {
255 tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
256 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
257 }
258 }
259 }
260 };
261
imageCompare(tcu::TestLog & log,const tcu::ConstPixelBufferAccess & reference,const tcu::ConstPixelBufferAccess & result,const vk::VkPrimitiveTopology topology)262 inline bool imageCompare (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const vk::VkPrimitiveTopology topology)
263 {
264 if (topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
265 {
266 return tcu::intThresholdPositionDeviationCompare(
267 log, "Result", "Image comparison result", reference, result,
268 tcu::UVec4(4u), // color threshold
269 tcu::IVec3(1, 1, 0), // position deviation tolerance
270 true, // don't check the pixels at the boundary
271 tcu::COMPARE_LOG_RESULT);
272 }
273 else
274 return tcu::fuzzyCompare(log, "Result", "Image comparison result", reference, result, 0.053f, tcu::COMPARE_LOG_RESULT);
275 }
276
277 class DrawTestInstanceBase : public TestInstance
278 {
279 public:
280 DrawTestInstanceBase (Context& context);
281 virtual ~DrawTestInstanceBase (void) = 0;
282 void initialize (const DrawParamsBase& data);
283 void initPipeline (const vk::VkDevice device);
284 void preRenderBarriers (void);
285 void beginRenderPass (vk::VkCommandBuffer cmdBuffer);
286 void endRenderPass (vk::VkCommandBuffer cmdBuffer);
287
288 #ifndef CTS_USES_VULKANSC
289 void beginSecondaryCmdBuffer (const vk::DeviceInterface& vk, vk::VkRenderingFlagsKHR renderingFlags = 0u);
290 void beginDynamicRender (vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags = 0u);
291 void endDynamicRender (vk::VkCommandBuffer cmdBuffer);
292 #endif // CTS_USES_VULKANSC
293
294 // Specialize this function for each type
295 virtual tcu::TestStatus iterate (void) = 0;
296 protected:
297 // Specialize this function for each type
298 virtual void generateDrawData (void) = 0;
299 void generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
300
301 DrawParamsBase m_data;
302 const vk::DeviceInterface& m_vk;
303 vk::Move<vk::VkPipeline> m_pipeline;
304 vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
305 vk::VkFormat m_colorAttachmentFormat;
306 de::SharedPtr<Image> m_colorTargetImage;
307 vk::Move<vk::VkImageView> m_colorTargetView;
308 vk::Move<vk::VkRenderPass> m_renderPass;
309 vk::Move<vk::VkFramebuffer> m_framebuffer;
310 PipelineCreateInfo::VertexInputState m_vertexInputState;
311 de::SharedPtr<Buffer> m_vertexBuffer;
312 vk::Move<vk::VkCommandPool> m_cmdPool;
313 vk::Move<vk::VkCommandBuffer> m_cmdBuffer;
314 vk::Move<vk::VkCommandBuffer> m_secCmdBuffer;
315
316 enum
317 {
318 WIDTH = 256,
319 HEIGHT = 256
320 };
321 };
322
DrawTestInstanceBase(Context & context)323 DrawTestInstanceBase::DrawTestInstanceBase (Context& context)
324 : vkt::TestInstance (context)
325 , m_vk (context.getDeviceInterface())
326 , m_colorAttachmentFormat (vk::VK_FORMAT_R8G8B8A8_UNORM)
327 {
328 }
329
~DrawTestInstanceBase(void)330 DrawTestInstanceBase::~DrawTestInstanceBase (void)
331 {
332 }
333
initialize(const DrawParamsBase & data)334 void DrawTestInstanceBase::initialize (const DrawParamsBase& data)
335 {
336 m_data = data;
337
338 const vk::VkDevice device = m_context.getDevice();
339 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
340
341 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
342 m_pipelineLayout = vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
343
344 const vk::VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 };
345 const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
346 vk::VK_IMAGE_TILING_OPTIMAL, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
347
348 m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
349
350 const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
351 m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo);
352
353 // create render pass only when we are not using dynamic rendering
354 if (!m_data.groupParams.useDynamicRendering)
355 {
356 RenderPassCreateInfo renderPassCreateInfo;
357 renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
358 vk::VK_SAMPLE_COUNT_1_BIT,
359 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
360 vk::VK_ATTACHMENT_STORE_OP_STORE,
361 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
362 vk::VK_ATTACHMENT_STORE_OP_STORE,
363 vk::VK_IMAGE_LAYOUT_GENERAL,
364 vk::VK_IMAGE_LAYOUT_GENERAL));
365
366 const vk::VkAttachmentReference colorAttachmentReference
367 {
368 0,
369 vk::VK_IMAGE_LAYOUT_GENERAL
370 };
371
372 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
373 0,
374 0,
375 DE_NULL,
376 1,
377 &colorAttachmentReference,
378 DE_NULL,
379 AttachmentReference(),
380 0,
381 DE_NULL));
382
383 m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
384
385 // create framebuffer
386 std::vector<vk::VkImageView> colorAttachments { *m_colorTargetView };
387 const FramebufferCreateInfo framebufferCreateInfo (*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
388 m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
389 }
390
391 const vk::VkVertexInputBindingDescription vertexInputBindingDescription =
392 {
393 0,
394 (deUint32)sizeof(tcu::Vec4) * 2,
395 vk::VK_VERTEX_INPUT_RATE_VERTEX,
396 };
397
398 const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
399 {
400 {
401 0u,
402 0u,
403 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
404 0u
405 },
406 {
407 1u,
408 0u,
409 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
410 (deUint32)(sizeof(float)* 4),
411 }
412 };
413
414 m_vertexInputState = PipelineCreateInfo::VertexInputState(1,
415 &vertexInputBindingDescription,
416 2,
417 vertexInputAttributeDescriptions);
418
419 const vk::VkDeviceSize dataSize = m_data.vertices.size() * sizeof(PositionColorVertex);
420 m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, BufferCreateInfo(dataSize,
421 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
422
423 deUint8* ptr = reinterpret_cast<deUint8*>(m_vertexBuffer->getBoundMemory().getHostPtr());
424 deMemcpy(ptr, &(m_data.vertices[0]), static_cast<size_t>(dataSize));
425
426 vk::flushAlloc(m_vk, device, m_vertexBuffer->getBoundMemory());
427
428 const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
429 m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
430 m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
431
432 if (m_data.groupParams.useSecondaryCmdBuffer)
433 m_secCmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
434
435 initPipeline(device);
436 }
437
initPipeline(const vk::VkDevice device)438 void DrawTestInstanceBase::initPipeline (const vk::VkDevice device)
439 {
440 const vk::Unique<vk::VkShaderModule> vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
441 const vk::Unique<vk::VkShaderModule> fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
442
443 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
444
445 vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
446 vk::VkRect2D scissor = vk::makeRect2D(WIDTH, HEIGHT);
447
448 // when dynamic_rendering is tested then renderPass won't be created and VK_NULL_HANDLE will be used here
449 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
450 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
451 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
452 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
453 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_data.topology));
454 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
455 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
456 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
457 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
458 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
459
460 #ifndef CTS_USES_VULKANSC
461 vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
462 {
463 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
464 DE_NULL,
465 0u,
466 1u,
467 &m_colorAttachmentFormat,
468 vk::VK_FORMAT_UNDEFINED,
469 vk::VK_FORMAT_UNDEFINED
470 };
471
472 if (m_data.groupParams.useDynamicRendering)
473 pipelineCreateInfo.pNext = &renderingCreateInfo;
474 #endif // CTS_USES_VULKANSC
475
476 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
477 }
478
preRenderBarriers(void)479 void DrawTestInstanceBase::preRenderBarriers (void)
480 {
481 const vk::VkClearValue clearColor { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
482
483 initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
484 vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
485
486 const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
487 m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
488 vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange);
489
490 const vk::VkMemoryBarrier memBarrier
491 {
492 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
493 DE_NULL,
494 vk::VK_ACCESS_TRANSFER_WRITE_BIT,
495 vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
496 };
497
498 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
499 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
500 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
501 }
502
beginRenderPass(vk::VkCommandBuffer cmdBuffer)503 void DrawTestInstanceBase::beginRenderPass (vk::VkCommandBuffer cmdBuffer)
504 {
505 const vk::VkClearValue clearColor { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
506 const vk::VkRect2D renderArea = vk::makeRect2D(WIDTH, HEIGHT);
507
508 vk::beginRenderPass(m_vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, 1u, &clearColor);
509 }
510
endRenderPass(vk::VkCommandBuffer cmdBuffer)511 void DrawTestInstanceBase::endRenderPass (vk::VkCommandBuffer cmdBuffer)
512 {
513 vk::endRenderPass(m_vk, cmdBuffer);
514 }
515
516 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(const vk::DeviceInterface & vk,vk::VkRenderingFlagsKHR renderingFlags)517 void DrawTestInstanceBase::beginSecondaryCmdBuffer(const vk::DeviceInterface& vk, vk::VkRenderingFlagsKHR renderingFlags)
518 {
519 const vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
520 {
521 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
522 DE_NULL, // const void* pNext;
523 renderingFlags, // VkRenderingFlagsKHR flags;
524 0u, // uint32_t viewMask;
525 1u, // uint32_t colorAttachmentCount;
526 &m_colorAttachmentFormat, // const VkFormat* pColorAttachmentFormats;
527 vk::VK_FORMAT_UNDEFINED, // VkFormat depthAttachmentFormat;
528 vk::VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat;
529 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
530 };
531
532 const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo
533 {
534 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
535 &inheritanceRenderingInfo, // const void* pNext;
536 DE_NULL, // VkRenderPass renderPass;
537 0u, // deUint32 subpass;
538 DE_NULL, // VkFramebuffer framebuffer;
539 VK_FALSE, // VkBool32 occlusionQueryEnable;
540 (vk::VkQueryControlFlags)0u, // VkQueryControlFlags queryFlags;
541 (vk::VkQueryPipelineStatisticFlags)0u // VkQueryPipelineStatisticFlags pipelineStatistics;
542 };
543
544 vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
545 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
546 usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
547
548 const vk::VkCommandBufferBeginInfo commandBufBeginParams
549 {
550 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
551 DE_NULL, // const void* pNext;
552 usageFlags, // VkCommandBufferUsageFlags flags;
553 &bufferInheritanceInfo
554 };
555
556 VK_CHECK(vk.beginCommandBuffer(*m_secCmdBuffer, &commandBufBeginParams));
557 }
558
beginDynamicRender(vk::VkCommandBuffer cmdBuffer,vk::VkRenderingFlagsKHR renderingFlags)559 void DrawTestInstanceBase::beginDynamicRender(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags)
560 {
561 const vk::VkClearValue clearColor{ { { 0.0f, 0.0f, 0.0f, 1.0f } } };
562 const vk::VkRect2D renderArea = vk::makeRect2D(WIDTH, HEIGHT);
563
564 vk::beginRendering(m_vk, cmdBuffer, *m_colorTargetView, renderArea, clearColor, vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ATTACHMENT_LOAD_OP_LOAD, renderingFlags);
565 }
566
endDynamicRender(vk::VkCommandBuffer cmdBuffer)567 void DrawTestInstanceBase::endDynamicRender(vk::VkCommandBuffer cmdBuffer)
568 {
569 vk::endRendering(m_vk, cmdBuffer);
570 }
571 #endif // CTS_USES_VULKANSC
572
generateRefImage(const tcu::PixelBufferAccess & access,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const573 void DrawTestInstanceBase::generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
574 {
575 const PassthruVertShader vertShader;
576 const PassthruFragShader fragShader;
577 const rr::Program program (&vertShader, &fragShader);
578 const rr::MultisamplePixelBufferAccess colorBuffer = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(access);
579 const rr::RenderTarget renderTarget (colorBuffer);
580 const rr::RenderState renderState ((rr::ViewportState(colorBuffer)), m_context.getDeviceProperties().limits.subPixelPrecisionBits);
581 const rr::Renderer renderer;
582
583 const rr::VertexAttrib vertexAttribs[] =
584 {
585 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
586 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0])
587 };
588
589 renderer.draw(rr::DrawCommand(renderState,
590 renderTarget,
591 program,
592 DE_LENGTH_OF_ARRAY(vertexAttribs),
593 &vertexAttribs[0],
594 rr::PrimitiveList(mapVkPrimitiveTopology(m_data.topology), (deUint32)vertices.size(), 0)));
595 }
596
597 template<typename T>
598 class DrawTestInstance : public DrawTestInstanceBase
599 {
600 public:
601 DrawTestInstance (Context& context, const T& data);
602 virtual ~DrawTestInstance (void);
603 virtual void generateDrawData (void);
604 virtual void draw (vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer = DE_NULL, vk::VkDeviceSize indirectOffset = 0ul);
605 virtual tcu::TestStatus iterate (void);
606 private:
607 T m_data;
608 };
609
610 template<typename T>
DrawTestInstance(Context & context,const T & data)611 DrawTestInstance<T>::DrawTestInstance (Context& context, const T& data)
612 : DrawTestInstanceBase (context)
613 , m_data(data)
614 {
615 generateDrawData();
616 initialize(m_data);
617 }
618
619 template<typename T>
~DrawTestInstance(void)620 DrawTestInstance<T>::~DrawTestInstance (void)
621 {
622 }
623
624 template<typename T>
generateDrawData(void)625 void DrawTestInstance<T>::generateDrawData (void)
626 {
627 DE_FATAL("Using the general case of this function is forbidden!");
628 }
629
630 template<typename T>
draw(vk::VkCommandBuffer,vk::VkBuffer,vk::VkDeviceSize)631 void DrawTestInstance<T>::draw(vk::VkCommandBuffer, vk::VkBuffer, vk::VkDeviceSize)
632 {
633 DE_FATAL("Using the general case of this function is forbidden!");
634 }
635
636 template<typename T>
iterate(void)637 tcu::TestStatus DrawTestInstance<T>::iterate (void)
638 {
639 DE_FATAL("Using the general case of this function is forbidden!");
640 return tcu::TestStatus::fail("");
641 }
642
643 template<typename T>
644 class DrawTestCase : public TestCase
645 {
646 public:
647 DrawTestCase (tcu::TestContext& context, const char* name, const char* desc, const T data);
648 ~DrawTestCase (void);
649 virtual void initPrograms (vk::SourceCollections& programCollection) const;
650 virtual void initShaderSources (void);
651 virtual void checkSupport (Context& context) const;
652 virtual TestInstance* createInstance (Context& context) const;
653
654 private:
655 T m_data;
656 std::string m_vertShaderSource;
657 std::string m_fragShaderSource;
658 };
659
660 template<typename T>
DrawTestCase(tcu::TestContext & context,const char * name,const char * desc,const T data)661 DrawTestCase<T>::DrawTestCase (tcu::TestContext& context, const char* name, const char* desc, const T data)
662 : vkt::TestCase (context, name, desc)
663 , m_data (data)
664 {
665 initShaderSources();
666 }
667
668 template<typename T>
~DrawTestCase(void)669 DrawTestCase<T>::~DrawTestCase (void)
670 {
671 }
672
673 template<typename T>
initPrograms(vk::SourceCollections & programCollection) const674 void DrawTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
675 {
676 programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
677 programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
678 }
679
680 template<typename T>
checkSupport(Context & context) const681 void DrawTestCase<T>::checkSupport (Context& context) const
682 {
683 if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
684 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
685 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ||
686 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY)
687 {
688 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
689 }
690
691 #ifndef CTS_USES_VULKANSC
692 if (m_data.groupParams.useDynamicRendering)
693 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
694
695 if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
696 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
697 !context.getPortabilitySubsetFeatures().triangleFans)
698 {
699 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
700 }
701 #endif // CTS_USES_VULKANSC
702 }
703
704 template<typename T>
initShaderSources(void)705 void DrawTestCase<T>::initShaderSources (void)
706 {
707 std::stringstream vertShader;
708 vertShader << "#version 430\n"
709 << "layout(location = 0) in vec4 in_position;\n"
710 << "layout(location = 1) in vec4 in_color;\n"
711 << "layout(location = 0) out vec4 out_color;\n"
712
713 << "out gl_PerVertex {\n"
714 << " vec4 gl_Position;\n"
715 << " float gl_PointSize;\n"
716 << "};\n"
717 << "void main() {\n"
718 << " gl_PointSize = 1.0;\n"
719 << " gl_Position = in_position;\n"
720 << " out_color = in_color;\n"
721 << "}\n";
722
723 m_vertShaderSource = vertShader.str();
724
725 std::stringstream fragShader;
726 fragShader << "#version 430\n"
727 << "layout(location = 0) in vec4 in_color;\n"
728 << "layout(location = 0) out vec4 out_color;\n"
729 << "void main()\n"
730 << "{\n"
731 << " out_color = in_color;\n"
732 << "}\n";
733
734 m_fragShaderSource = fragShader.str();
735 }
736
737 template<typename T>
createInstance(Context & context) const738 TestInstance* DrawTestCase<T>::createInstance (Context& context) const
739 {
740 return new DrawTestInstance<T>(context, m_data);
741 }
742
743 // Specialized cases
744 template<>
generateDrawData(void)745 void DrawTestInstance<DrawParams>::generateDrawData (void)
746 {
747 de::Random rnd (SEED ^ m_data.params.firstVertex ^ m_data.params.vertexCount);
748
749 const deUint32 vectorSize = m_data.params.firstVertex + m_data.params.vertexCount;
750
751 // Initialize the vector
752 m_data.vertices = std::vector<PositionColorVertex>(vectorSize, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
753
754 // Fill only the used indexes
755 for (deUint32 vertexIdx = m_data.params.firstVertex; vertexIdx < vectorSize; ++vertexIdx)
756 {
757 const float f0 = rnd.getFloat(-1.0f, 1.0f);
758 const float f1 = rnd.getFloat(-1.0f, 1.0f);
759
760 m_data.vertices[vertexIdx] = PositionColorVertex(
761 tcu::Vec4(f0, f1, 1.0f, 1.0f), // Coord
762 tcu::randomVec4(rnd)); // Color
763 }
764 }
765
766 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer,vk::VkDeviceSize)767 void DrawTestInstance<DrawParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer, vk::VkDeviceSize)
768 {
769 m_vk.cmdDraw(cmdBuffer, m_data.params.vertexCount, m_data.params.instanceCount, m_data.params.firstVertex, m_data.params.firstInstance);
770 }
771
772 template<>
iterate(void)773 tcu::TestStatus DrawTestInstance<DrawParams>::iterate (void)
774 {
775 tcu::TestLog &log = m_context.getTestContext().getLog();
776 const vk::VkQueue queue = m_context.getUniversalQueue();
777 const vk::VkDevice device = m_context.getDevice();
778 const vk::VkDeviceSize vertexBufferOffset = 0;
779 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
780
781 #ifndef CTS_USES_VULKANSC
782 if (m_data.groupParams.useSecondaryCmdBuffer)
783 {
784 // record secondary command buffer
785 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
786 {
787 beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
788 beginDynamicRender(*m_secCmdBuffer);
789 }
790 else
791 beginSecondaryCmdBuffer(m_vk);
792
793 m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
794 m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
795 draw(*m_secCmdBuffer);
796
797 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
798 endDynamicRender(*m_secCmdBuffer);
799
800 endCommandBuffer(m_vk, *m_secCmdBuffer);
801
802 // record primary command buffer
803 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
804
805 preRenderBarriers();
806
807 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
808 beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
809
810 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
811
812 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
813 endDynamicRender(*m_cmdBuffer);
814
815 endCommandBuffer(m_vk, *m_cmdBuffer);
816 }
817 else if(m_data.groupParams.useDynamicRendering)
818 {
819 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
820 preRenderBarriers();
821 beginDynamicRender(*m_cmdBuffer);
822
823 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
824 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
825 draw(*m_cmdBuffer);
826
827 endDynamicRender(*m_cmdBuffer);
828 endCommandBuffer(m_vk, *m_cmdBuffer);
829 }
830 #endif // CTS_USES_VULKANSC
831
832 if (!m_data.groupParams.useDynamicRendering)
833 {
834 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
835 preRenderBarriers();
836 beginRenderPass(*m_cmdBuffer);
837
838 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
839 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
840 draw(*m_cmdBuffer);
841
842 endRenderPass(*m_cmdBuffer);
843 endCommandBuffer(m_vk, *m_cmdBuffer);
844 }
845
846 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
847
848 // Validation
849 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
850 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
851
852 std::vector<tcu::Vec4> vertices;
853 std::vector<tcu::Vec4> colors;
854
855 for (std::vector<PositionColorVertex>::const_iterator vertex = m_data.vertices.begin() + m_data.params.firstVertex; vertex != m_data.vertices.end(); ++vertex)
856 {
857 vertices.push_back(vertex->position);
858 colors.push_back(vertex->color);
859 }
860 generateRefImage(refImage.getAccess(), vertices, colors);
861
862 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
863 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
864 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
865
866 qpTestResult res = QP_TEST_RESULT_PASS;
867
868 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
869 res = QP_TEST_RESULT_FAIL;
870
871 return tcu::TestStatus(res, qpGetTestResultName(res));
872 }
873
874 template<>
generateDrawData(void)875 void DrawTestInstance<DrawIndexedParams>::generateDrawData (void)
876 {
877 de::Random rnd (SEED ^ m_data.params.firstIndex ^ m_data.params.indexCount);
878 const deUint32 indexSize = m_data.params.firstIndex + m_data.params.indexCount;
879
880 // Initialize the vector with zeros
881 m_data.indexes = std::vector<deUint32>(indexSize, 0);
882
883 deUint32 highestIndex = 0; // Store to highest index to calculate the vertices size
884 // Fill the indexes from firstIndex
885 for (deUint32 idx = 0; idx < m_data.params.indexCount; ++idx)
886 {
887 deUint32 vertexIdx = rnd.getInt(m_data.params.vertexOffset, INDEX_LIMIT);
888 highestIndex = (vertexIdx > highestIndex) ? vertexIdx : highestIndex;
889
890 m_data.indexes[m_data.params.firstIndex + idx] = vertexIdx;
891 }
892
893 // Fill up the vertex coordinates with zeros until the highestIndex including the vertexOffset
894 m_data.vertices = std::vector<PositionColorVertex>(m_data.params.vertexOffset + highestIndex + 1, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
895
896 // Generate random vertex only where you have index pointing at
897 for (std::vector<deUint32>::const_iterator indexIt = m_data.indexes.begin() + m_data.params.firstIndex; indexIt != m_data.indexes.end(); ++indexIt)
898 {
899 // Get iterator to the vertex position with the vertexOffset
900 std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + m_data.params.vertexOffset + *indexIt;
901
902 tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
903 const float f0 = rnd.getFloat(-1.0f, 1.0f);
904 const float f1 = rnd.getFloat(-1.0f, 1.0f);
905 positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
906
907 tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
908 colorAccess = tcu::randomVec4(rnd);
909 }
910 }
911
912 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer,vk::VkDeviceSize)913 void DrawTestInstance<DrawIndexedParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer, vk::VkDeviceSize)
914 {
915 m_vk.cmdDrawIndexed(cmdBuffer, m_data.params.indexCount, m_data.params.instanceCount, m_data.params.firstIndex, m_data.params.vertexOffset, m_data.params.firstInstance);
916 }
917
918 template<>
iterate(void)919 tcu::TestStatus DrawTestInstance<DrawIndexedParams>::iterate (void)
920 {
921 tcu::TestLog &log = m_context.getTestContext().getLog();
922 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
923 const vk::VkDevice vkDevice = m_context.getDevice();
924 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
925 const vk::VkQueue queue = m_context.getUniversalQueue();
926 vk::Allocator& allocator = m_context.getDefaultAllocator();
927 const vk::VkDeviceSize vertexBufferOffset = 0;
928 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
929 const deUint32 bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
930
931 const vk::VkBufferCreateInfo bufferCreateInfo =
932 {
933 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
934 DE_NULL, // const void* pNext;
935 0u, // VkBufferCreateFlags flags;
936 bufferSize, // VkDeviceSize size;
937 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage;
938 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
939 1u, // deUint32 queueFamilyIndexCount;
940 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
941 };
942
943 vk::Move<vk::VkBuffer> indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
944 de::MovePtr<vk::Allocation> indexAlloc;
945
946 indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
947 VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
948
949 deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
950
951 vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
952
953 #ifndef CTS_USES_VULKANSC
954 if (m_data.groupParams.useSecondaryCmdBuffer)
955 {
956 // record secondary command buffer
957 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
958 {
959 beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
960 beginDynamicRender(*m_secCmdBuffer);
961 }
962 else
963 beginSecondaryCmdBuffer(m_vk);
964
965 m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
966 m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
967 m_vk.cmdBindIndexBuffer(*m_secCmdBuffer, *indexBuffer, 0u, m_data.indexType);
968 draw(*m_secCmdBuffer);
969
970 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
971 endDynamicRender(*m_secCmdBuffer);
972
973 endCommandBuffer(m_vk, *m_secCmdBuffer);
974
975 // record primary command buffer
976 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
977
978 preRenderBarriers();
979
980 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
981 beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
982
983 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
984
985 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
986 endDynamicRender(*m_cmdBuffer);
987
988 endCommandBuffer(m_vk, *m_cmdBuffer);
989 }
990 else if (m_data.groupParams.useDynamicRendering)
991 {
992 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
993 preRenderBarriers();
994 beginDynamicRender(*m_cmdBuffer);
995
996 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
997 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
998 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
999 draw(*m_cmdBuffer);
1000
1001 endDynamicRender(*m_cmdBuffer);
1002 endCommandBuffer(m_vk, *m_cmdBuffer);
1003 }
1004 #endif // CTS_USES_VULKANSC
1005
1006 if (!m_data.groupParams.useDynamicRendering)
1007 {
1008 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1009 preRenderBarriers();
1010 beginRenderPass(*m_cmdBuffer);
1011
1012 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1013 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1014 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1015 draw(*m_cmdBuffer);
1016
1017 endRenderPass(*m_cmdBuffer);
1018 endCommandBuffer(m_vk, *m_cmdBuffer);
1019 }
1020
1021 submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1022
1023 // Validation
1024 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1025 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1026
1027 std::vector<tcu::Vec4> vertices;
1028 std::vector<tcu::Vec4> colors;
1029
1030 for (std::vector<deUint32>::const_iterator it = m_data.indexes.begin() + m_data.params.firstIndex; it != m_data.indexes.end(); ++it)
1031 {
1032 deUint32 idx = m_data.params.vertexOffset + *it;
1033 vertices.push_back(m_data.vertices[idx].position);
1034 colors.push_back(m_data.vertices[idx].color);
1035 }
1036 generateRefImage(refImage.getAccess(), vertices, colors);
1037
1038 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1039 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1040 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1041
1042 qpTestResult res = QP_TEST_RESULT_PASS;
1043
1044 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1045 res = QP_TEST_RESULT_FAIL;
1046
1047 return tcu::TestStatus(res, qpGetTestResultName(res));
1048 }
1049
1050 template<>
generateDrawData(void)1051 void DrawTestInstance<DrawIndirectParams>::generateDrawData (void)
1052 {
1053 de::Random rnd(SEED ^ m_data.commands[0].vertexCount ^ m_data.commands[0].firstVertex);
1054
1055 deUint32 lastIndex = 0;
1056
1057 // Find the interval which will be used
1058 for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1059 {
1060 const deUint32 index = it->firstVertex + it->vertexCount;
1061 lastIndex = (index > lastIndex) ? index : lastIndex;
1062 }
1063
1064 // Initialize with zeros
1065 m_data.vertices = std::vector<PositionColorVertex>(lastIndex, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
1066
1067 // Generate random vertices only where necessary
1068 for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1069 {
1070 std::vector<PositionColorVertex>::iterator vertexStart = m_data.vertices.begin() + it->firstVertex;
1071
1072 for (deUint32 idx = 0; idx < it->vertexCount; ++idx)
1073 {
1074 std::vector<PositionColorVertex>::iterator vertexIt = vertexStart + idx;
1075
1076 tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1077 const float f0 = rnd.getFloat(-1.0f, 1.0f);
1078 const float f1 = rnd.getFloat(-1.0f, 1.0f);
1079 positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1080
1081 tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1082 colorAccess = tcu::randomVec4(rnd);
1083 }
1084 }
1085 }
1086
1087 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer indirectBuffer,vk::VkDeviceSize indirectOffset)1088 void DrawTestInstance<DrawIndirectParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer, vk::VkDeviceSize indirectOffset)
1089 {
1090 const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
1091
1092 // If multiDrawIndirect not supported execute single calls
1093 if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1094 {
1095 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1096 {
1097 const deUint32 offset = (deUint32)(indirectOffset + cmdIdx * sizeof(vk::VkDrawIndirectCommand));
1098 m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer, offset, 1, sizeof(vk::VkDrawIndirectCommand));
1099 }
1100 }
1101 else
1102 {
1103 m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer, indirectOffset, (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndirectCommand));
1104 }
1105 }
1106
1107 template<>
iterate(void)1108 tcu::TestStatus DrawTestInstance<DrawIndirectParams>::iterate (void)
1109 {
1110 tcu::TestLog &log = m_context.getTestContext().getLog();
1111 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
1112 const vk::VkDevice vkDevice = m_context.getDevice();
1113 vk::Allocator& allocator = m_context.getDefaultAllocator();
1114 const vk::VkQueue queue = m_context.getUniversalQueue();
1115 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1116 const vk::VkDeviceSize vertexBufferOffset = 0;
1117 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
1118 vk::Move<vk::VkBuffer> indirectBuffer;
1119 de::MovePtr<vk::Allocation> indirectAlloc;
1120
1121 {
1122 const vk::VkDeviceSize indirectInfoSize = m_data.commands.size() * sizeof(vk::VkDrawIndirectCommand);
1123
1124 const vk::VkBufferCreateInfo indirectCreateInfo =
1125 {
1126 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1127 DE_NULL, // const void* pNext;
1128 0u, // VkBufferCreateFlags flags;
1129 indirectInfoSize, // VkDeviceSize size;
1130 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, // VkBufferUsageFlags usage;
1131 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1132 1u, // deUint32 queueFamilyIndexCount;
1133 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
1134 };
1135
1136 indirectBuffer = createBuffer(vk, vkDevice, &indirectCreateInfo);
1137 indirectAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1138 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1139
1140 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1141
1142 vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1143 }
1144
1145 #ifndef CTS_USES_VULKANSC
1146 if (m_data.groupParams.useSecondaryCmdBuffer)
1147 {
1148 // record secondary command buffer
1149 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1150 {
1151 beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1152 beginDynamicRender(*m_secCmdBuffer);
1153 }
1154 else
1155 beginSecondaryCmdBuffer(m_vk);
1156
1157 m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1158 m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1159 draw(*m_secCmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1160
1161 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1162 endDynamicRender(*m_secCmdBuffer);
1163
1164 endCommandBuffer(m_vk, *m_secCmdBuffer);
1165
1166 // record primary command buffer
1167 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1168
1169 preRenderBarriers();
1170
1171 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1172 beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1173
1174 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1175
1176 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1177 endDynamicRender(*m_cmdBuffer);
1178
1179 endCommandBuffer(m_vk, *m_cmdBuffer);
1180 }
1181 else if (m_data.groupParams.useDynamicRendering)
1182 {
1183 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1184 preRenderBarriers();
1185 beginDynamicRender(*m_cmdBuffer);
1186
1187 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1188 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1189 draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1190
1191 endDynamicRender(*m_cmdBuffer);
1192 endCommandBuffer(m_vk, *m_cmdBuffer);
1193 }
1194 #endif // CTS_USES_VULKANSC
1195
1196 if (!m_data.groupParams.useDynamicRendering)
1197 {
1198 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1199 preRenderBarriers();
1200 beginRenderPass(*m_cmdBuffer);
1201
1202 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1203 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1204 draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1205
1206 endRenderPass(*m_cmdBuffer);
1207 endCommandBuffer(m_vk, *m_cmdBuffer);
1208 }
1209
1210 submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1211
1212 // Validation
1213 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1214 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1215
1216 for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1217 {
1218 std::vector<tcu::Vec4> vertices;
1219 std::vector<tcu::Vec4> colors;
1220
1221 std::vector<PositionColorVertex>::const_iterator firstIt = m_data.vertices.begin() + it->firstVertex;
1222 std::vector<PositionColorVertex>::const_iterator lastIt = firstIt + it->vertexCount;
1223
1224 for (std::vector<PositionColorVertex>::const_iterator vertex = firstIt; vertex != lastIt; ++vertex)
1225 {
1226 vertices.push_back(vertex->position);
1227 colors.push_back(vertex->color);
1228 }
1229 generateRefImage(refImage.getAccess(), vertices, colors);
1230 }
1231
1232 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1233 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1234 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1235
1236 qpTestResult res = QP_TEST_RESULT_PASS;
1237
1238 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1239 res = QP_TEST_RESULT_FAIL;
1240
1241 return tcu::TestStatus(res, qpGetTestResultName(res));
1242 }
1243
1244 template<>
generateDrawData(void)1245 void DrawTestInstance<DrawIndexedIndirectParams>::generateDrawData (void)
1246 {
1247 de::Random rnd (SEED ^ m_data.commands[0].firstIndex ^ m_data.commands[0].indexCount);
1248
1249 deUint32 lastIndex = 0;
1250
1251 // Get the maximum range of indexes
1252 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1253 {
1254 const deUint32 index = it->firstIndex + it->indexCount;
1255 lastIndex = (index > lastIndex) ? index : lastIndex;
1256 }
1257
1258 // Initialize the vector with zeros
1259 m_data.indexes = std::vector<deUint32>(lastIndex, 0);
1260
1261 deUint32 highestIndex = 0;
1262
1263 // Generate random indexes for the ranges
1264 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1265 {
1266 for (deUint32 idx = 0; idx < it->indexCount; ++idx)
1267 {
1268 const deUint32 vertexIdx = rnd.getInt(it->vertexOffset, INDEX_LIMIT);
1269 const deUint32 maxIndex = vertexIdx + it->vertexOffset;
1270
1271 highestIndex = (maxIndex > highestIndex) ? maxIndex : highestIndex;
1272 m_data.indexes[it->firstIndex + idx] = vertexIdx;
1273 }
1274 }
1275
1276 // Initialize the vertex vector
1277 m_data.vertices = std::vector<PositionColorVertex>(highestIndex + 1, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
1278
1279 // Generate random vertices in the used locations
1280 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmdIt = m_data.commands.begin(); cmdIt != m_data.commands.end(); ++cmdIt)
1281 {
1282 deUint32 firstIdx = cmdIt->firstIndex;
1283 deUint32 lastIdx = firstIdx + cmdIt->indexCount;
1284
1285 for (deUint32 idx = firstIdx; idx < lastIdx; ++idx)
1286 {
1287 std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + cmdIt->vertexOffset + m_data.indexes[idx];
1288
1289 tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1290 const float f0 = rnd.getFloat(-1.0f, 1.0f);
1291 const float f1 = rnd.getFloat(-1.0f, 1.0f);
1292 positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1293
1294 tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1295 colorAccess = tcu::randomVec4(rnd);
1296 }
1297 }
1298 }
1299
1300 template<>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer indirectBuffer,vk::VkDeviceSize indirectOffset)1301 void DrawTestInstance<DrawIndexedIndirectParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer, vk::VkDeviceSize indirectOffset)
1302 {
1303 const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
1304
1305 // If multiDrawIndirect not supported execute single calls
1306 if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1307 {
1308 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1309 {
1310 const deUint32 offset = (deUint32)(indirectOffset + cmdIdx * sizeof(vk::VkDrawIndexedIndirectCommand));
1311 m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer, offset, 1, sizeof(vk::VkDrawIndexedIndirectCommand));
1312 }
1313 }
1314 else
1315 {
1316 m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer, indirectOffset, (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndexedIndirectCommand));
1317 }
1318 }
1319
1320 template<>
iterate(void)1321 tcu::TestStatus DrawTestInstance<DrawIndexedIndirectParams>::iterate (void)
1322 {
1323 tcu::TestLog &log = m_context.getTestContext().getLog();
1324 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
1325 const vk::VkDevice vkDevice = m_context.getDevice();
1326 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1327 const vk::VkQueue queue = m_context.getUniversalQueue();
1328 vk::Allocator& allocator = m_context.getDefaultAllocator();
1329 const vk::VkDeviceSize vertexBufferOffset = 0;
1330 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
1331 vk::Move<vk::VkBuffer> indirectBuffer;
1332 de::MovePtr<vk::Allocation> indirectAlloc;
1333
1334 {
1335 const vk::VkDeviceSize indirectInfoSize = m_data.commands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
1336
1337 const vk::VkBufferCreateInfo indirectCreateInfo =
1338 {
1339 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1340 DE_NULL, // const void* pNext;
1341 0u, // VkBufferCreateFlags flags;
1342 indirectInfoSize, // VkDeviceSize size;
1343 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, // VkBufferUsageFlags usage;
1344 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1345 1u, // deUint32 queueFamilyIndexCount;
1346 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
1347 };
1348
1349 indirectBuffer = createBuffer(vk, vkDevice, &indirectCreateInfo);
1350 indirectAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1351 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1352
1353 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1354
1355 vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1356 }
1357
1358 const deUint32 bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
1359
1360 vk::Move<vk::VkBuffer> indexBuffer;
1361
1362 const vk::VkBufferCreateInfo bufferCreateInfo =
1363 {
1364 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1365 DE_NULL, // const void* pNext;
1366 0u, // VkBufferCreateFlags flags;
1367 bufferSize, // VkDeviceSize size;
1368 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage;
1369 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1370 1u, // deUint32 queueFamilyIndexCount;
1371 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
1372 };
1373
1374 indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1375
1376 de::MovePtr<vk::Allocation> indexAlloc;
1377
1378 indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1379 VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1380
1381 deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1382
1383 vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
1384
1385 #ifndef CTS_USES_VULKANSC
1386 if (m_data.groupParams.useSecondaryCmdBuffer)
1387 {
1388 // record secondary command buffer
1389 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1390 {
1391 beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1392 beginDynamicRender(*m_secCmdBuffer);
1393 }
1394 else
1395 beginSecondaryCmdBuffer(m_vk);
1396
1397 m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1398 m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1399 m_vk.cmdBindIndexBuffer(*m_secCmdBuffer, *indexBuffer, 0u, m_data.indexType);
1400 draw(*m_secCmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1401
1402 if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1403 endDynamicRender(*m_secCmdBuffer);
1404
1405 endCommandBuffer(m_vk, *m_secCmdBuffer);
1406
1407 // record primary command buffer
1408 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1409
1410 preRenderBarriers();
1411
1412 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1413 beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1414
1415 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1416
1417 if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1418 endDynamicRender(*m_cmdBuffer);
1419
1420 endCommandBuffer(m_vk, *m_cmdBuffer);
1421 }
1422 else if (m_data.groupParams.useDynamicRendering)
1423 {
1424 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1425 preRenderBarriers();
1426 beginDynamicRender(*m_cmdBuffer);
1427
1428 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1429 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1430 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1431 draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1432
1433 endDynamicRender(*m_cmdBuffer);
1434 endCommandBuffer(m_vk, *m_cmdBuffer);
1435 }
1436 #endif // CTS_USES_VULKANSC
1437
1438 if (!m_data.groupParams.useDynamicRendering)
1439 {
1440 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1441 preRenderBarriers();
1442 beginRenderPass(*m_cmdBuffer);
1443
1444 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1445 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1446 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1447 draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1448
1449 endRenderPass(*m_cmdBuffer);
1450 endCommandBuffer(m_vk, *m_cmdBuffer);
1451 }
1452
1453 submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1454
1455 // Validation
1456 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1457 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1458
1459 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmd = m_data.commands.begin(); cmd != m_data.commands.end(); ++cmd)
1460 {
1461 std::vector<tcu::Vec4> vertices;
1462 std::vector<tcu::Vec4> colors;
1463
1464 for (deUint32 idx = 0; idx < cmd->indexCount; ++idx)
1465 {
1466 const deUint32 vertexIndex = cmd->vertexOffset + m_data.indexes[cmd->firstIndex + idx];
1467 vertices.push_back(m_data.vertices[vertexIndex].position);
1468 colors.push_back(m_data.vertices[vertexIndex].color);
1469 }
1470 generateRefImage(refImage.getAccess(), vertices, colors);
1471 }
1472
1473 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1474 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1475 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1476
1477 qpTestResult res = QP_TEST_RESULT_PASS;
1478
1479 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1480 res = QP_TEST_RESULT_FAIL;
1481
1482 return tcu::TestStatus(res, qpGetTestResultName(res));
1483 }
1484
1485 typedef DrawTestCase<DrawParams> DrawCase;
1486 typedef DrawTestCase<DrawIndexedParams> IndexedCase;
1487 typedef DrawTestCase<DrawIndirectParams> IndirectCase;
1488 typedef DrawTestCase<DrawIndexedIndirectParams> IndexedIndirectCase;
1489
1490 struct TestCaseParams
1491 {
1492 const DrawCommandType command;
1493 const vk::VkPrimitiveTopology topology;
1494 const SharedGroupParams groupParams;
1495
TestCaseParamsvkt::Draw::__anona9f947520111::TestCaseParams1496 TestCaseParams (const DrawCommandType cmd, const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
1497 : command (cmd)
1498 , topology (top)
1499 , groupParams (gParams)
1500 {}
1501 };
1502
1503 } // anonymous
1504
populateSubGroup(tcu::TestCaseGroup * testGroup,const TestCaseParams caseParams)1505 void populateSubGroup (tcu::TestCaseGroup* testGroup, const TestCaseParams caseParams)
1506 {
1507 de::Random rnd (SEED ^ deStringHash(testGroup->getName()));
1508 tcu::TestContext& testCtx = testGroup->getTestContext();
1509 const DrawCommandType command = caseParams.command;
1510 const vk::VkPrimitiveTopology topology = caseParams.topology;
1511 const SharedGroupParams groupParams = caseParams.groupParams;
1512 const deUint32 primitiveCountArrLength = DE_LENGTH_OF_ARRAY(PRIMITIVE_COUNT);
1513
1514 for (deUint32 primitiveCountIdx = 0; primitiveCountIdx < primitiveCountArrLength; ++primitiveCountIdx)
1515 {
1516 const deUint32 primitives = PRIMITIVE_COUNT[primitiveCountIdx];
1517
1518 // when testing VK_KHR_dynamic_rendering there is no need to duplicate tests for all primitive counts; use just 1 and 45
1519 if (groupParams->useDynamicRendering && (primitiveCountIdx != 0) && (primitiveCountIdx != primitiveCountArrLength-1))
1520 continue;
1521
1522 deUint32 multiplier = 1;
1523 deUint32 offset = 0;
1524 // Calculated by Vulkan 23.1
1525 switch (topology)
1526 {
1527 case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST: break;
1528 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST: multiplier = 2; break;
1529 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: break;
1530 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: multiplier = 3; break;
1531 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: break;
1532 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: offset = 1; break;
1533 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: multiplier = 4; offset = 1; break;
1534 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: offset = 1; break;
1535 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: multiplier = 6; break;
1536 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: multiplier = 2; break;
1537 default: DE_FATAL("Unsupported topology.");
1538 }
1539
1540 const deUint32 vertexCount = multiplier * primitives + offset;
1541 std::string name = de::toString(primitives);
1542
1543 switch (command)
1544 {
1545 case DRAW_COMMAND_TYPE_DRAW:
1546 {
1547 deUint32 firstPrimitive = rnd.getInt(0, primitives);
1548 deUint32 firstVertex = multiplier * firstPrimitive;
1549 testGroup->addChild(new DrawCase(testCtx, name.c_str(), "vkCmdDraw testcase.",
1550 DrawParams(topology, groupParams, vertexCount, 1, firstVertex, 0))
1551 );
1552 break;
1553 }
1554 case DRAW_COMMAND_TYPE_DRAW_INDEXED:
1555 {
1556 deUint32 firstIndex = rnd.getInt(0, OFFSET_LIMIT);
1557 deUint32 vertexOffset = rnd.getInt(0, OFFSET_LIMIT);
1558 testGroup->addChild(new IndexedCase(testCtx, name.c_str(), "vkCmdDrawIndexed testcase.",
1559 DrawIndexedParams(topology, groupParams, vk::VK_INDEX_TYPE_UINT32, vertexCount, 1, firstIndex, vertexOffset, 0))
1560 );
1561 break;
1562 }
1563 case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
1564 {
1565 deUint32 firstVertex = rnd.getInt(0, OFFSET_LIMIT);
1566
1567 DrawIndirectParams params = DrawIndirectParams(topology, groupParams);
1568
1569 params.addCommand(vertexCount, 1, 0, 0);
1570 testGroup->addChild(new IndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1571
1572 params.addCommand(vertexCount, 1, firstVertex, 0);
1573 testGroup->addChild(new IndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1574 break;
1575 }
1576 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
1577 {
1578 deUint32 firstIndex = rnd.getInt(vertexCount, OFFSET_LIMIT);
1579 deUint32 vertexOffset = rnd.getInt(vertexCount, OFFSET_LIMIT);
1580
1581 DrawIndexedIndirectParams params = DrawIndexedIndirectParams(topology, groupParams, vk::VK_INDEX_TYPE_UINT32);
1582 params.addCommand(vertexCount, 1, 0, 0, 0);
1583 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1584
1585 params.addCommand(vertexCount, 1, firstIndex, vertexOffset, 0);
1586 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1587 break;
1588 }
1589 default:
1590 DE_FATAL("Unsupported draw command.");
1591 }
1592 }
1593 }
1594
createDrawTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)1595 void createDrawTests(tcu::TestCaseGroup* testGroup, const SharedGroupParams groupParams)
1596 {
1597 for (deUint32 drawTypeIndex = 0; drawTypeIndex < DRAW_COMMAND_TYPE_DRAW_LAST; ++drawTypeIndex)
1598 {
1599 const DrawCommandType command (static_cast<DrawCommandType>(drawTypeIndex));
1600 de::MovePtr<tcu::TestCaseGroup> topologyGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), getDrawCommandTypeName(command), "Group for testing a specific draw command."));
1601
1602 for (deUint32 topologyIdx = 0; topologyIdx != vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; ++topologyIdx)
1603 {
1604 const vk::VkPrimitiveTopology topology (static_cast<vk::VkPrimitiveTopology>(topologyIdx));
1605 const std::string groupName (de::toLower(getPrimitiveTopologyName(topology)).substr(22));
1606
1607 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1608 if (groupParams->useSecondaryCmdBuffer && (topologyIdx % 2u))
1609 continue;
1610
1611 addTestGroup(topologyGroup.get(), groupName, "Testcases with a specific topology.", populateSubGroup, TestCaseParams(command, topology, groupParams));
1612 }
1613
1614 testGroup->addChild(topologyGroup.release());
1615 }
1616 }
1617
createBasicDrawTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1618 tcu::TestCaseGroup* createBasicDrawTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1619 {
1620 return createTestGroup(testCtx, "basic_draw", "Basic drawing tests", createDrawTests, groupParams);
1621 }
1622
1623 } // DrawTests
1624 } // vkt
1625