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 bool useDynamicRendering;
109
DrawParamsBasevkt::Draw::__anondb648a740111::DrawParamsBase110 DrawParamsBase ()
111 {}
112
DrawParamsBasevkt::Draw::__anondb648a740111::DrawParamsBase113 DrawParamsBase (const vk::VkPrimitiveTopology top, bool dynamicRendering)
114 : topology (top)
115 , useDynamicRendering(dynamicRendering)
116 {}
117 };
118
119 struct IndexedParamsBase
120 {
121 std::vector<deUint32> indexes;
122 const vk::VkIndexType indexType;
123
IndexedParamsBasevkt::Draw::__anondb648a740111::IndexedParamsBase124 IndexedParamsBase (const vk::VkIndexType indexT)
125 : indexType (indexT)
126 {}
127 };
128
129 // Structs to store draw parameters
130 struct DrawParams : DrawParamsBase
131 {
132 // vkCmdDraw parameters is like a single VkDrawIndirectCommand
133 vk::VkDrawIndirectCommand params;
134
DrawParamsvkt::Draw::__anondb648a740111::DrawParams135 DrawParams (const vk::VkPrimitiveTopology top, bool dynamicRendering, const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
136 : DrawParamsBase (top, dynamicRendering)
137 {
138 params.vertexCount = vertexC;
139 params.instanceCount = instanceC;
140 params.firstVertex = firstV;
141 params.firstInstance = firstI;
142 }
143 };
144
145 struct DrawIndexedParams : DrawParamsBase, IndexedParamsBase
146 {
147 // vkCmdDrawIndexed parameters is like a single VkDrawIndexedIndirectCommand
148 vk::VkDrawIndexedIndirectCommand params;
149
DrawIndexedParamsvkt::Draw::__anondb648a740111::DrawIndexedParams150 DrawIndexedParams (const vk::VkPrimitiveTopology top, bool dynamicRendering, const vk::VkIndexType indexT, const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
151 : DrawParamsBase (top, dynamicRendering)
152 , IndexedParamsBase (indexT)
153 {
154 params.indexCount = indexC;
155 params.instanceCount = instanceC;
156 params.firstIndex = firstIdx;
157 params.vertexOffset = vertexO;
158 params.firstInstance = firstIns;
159 }
160 };
161
162 struct DrawIndirectParams : DrawParamsBase
163 {
164 std::vector<vk::VkDrawIndirectCommand> commands;
165
DrawIndirectParamsvkt::Draw::__anondb648a740111::DrawIndirectParams166 DrawIndirectParams (const vk::VkPrimitiveTopology top, bool dynamicRendering)
167 : DrawParamsBase (top, dynamicRendering)
168 {}
169
addCommandvkt::Draw::__anondb648a740111::DrawIndirectParams170 void addCommand (const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
171 {
172 vk::VkDrawIndirectCommand cmd;
173 cmd.vertexCount = vertexC;
174 cmd.instanceCount = instanceC;
175 cmd.firstVertex = firstV;
176 cmd.firstInstance = firstI;
177
178 commands.push_back(cmd);
179 }
180 };
181
182 struct DrawIndexedIndirectParams : DrawParamsBase, IndexedParamsBase
183 {
184 std::vector<vk::VkDrawIndexedIndirectCommand> commands;
185
DrawIndexedIndirectParamsvkt::Draw::__anondb648a740111::DrawIndexedIndirectParams186 DrawIndexedIndirectParams (const vk::VkPrimitiveTopology top, bool dynamicRendering, const vk::VkIndexType indexT)
187 : DrawParamsBase (top, dynamicRendering)
188 , IndexedParamsBase (indexT)
189 {}
190
addCommandvkt::Draw::__anondb648a740111::DrawIndexedIndirectParams191 void addCommand (const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
192 {
193 vk::VkDrawIndexedIndirectCommand cmd;
194 cmd.indexCount = indexC;
195 cmd.instanceCount = instanceC;
196 cmd.firstIndex = firstIdx;
197 cmd.vertexOffset = vertexO;
198 cmd.firstInstance = firstIns;
199
200 commands.push_back(cmd);
201 }
202 };
203
204 // Reference renderer shaders
205 class PassthruVertShader : public rr::VertexShader
206 {
207 public:
PassthruVertShader(void)208 PassthruVertShader (void)
209 : rr::VertexShader (2, 1)
210 {
211 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
212 m_inputs[1].type = rr::GENERICVECTYPE_FLOAT;
213 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
214 }
215
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const216 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
217 {
218 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
219 {
220 packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0],
221 packets[packetNdx]->instanceNdx,
222 packets[packetNdx]->vertexNdx);
223
224 tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1],
225 packets[packetNdx]->instanceNdx,
226 packets[packetNdx]->vertexNdx);
227
228 packets[packetNdx]->outputs[0] = color;
229 }
230 }
231 };
232
233 class PassthruFragShader : public rr::FragmentShader
234 {
235 public:
PassthruFragShader(void)236 PassthruFragShader (void)
237 : rr::FragmentShader(1, 1)
238 {
239 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
240 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
241 }
242
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const243 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
244 {
245 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
246 {
247 rr::FragmentPacket& packet = packets[packetNdx];
248 for (deUint32 fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
249 {
250 tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
251 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
252 }
253 }
254 }
255 };
256
imageCompare(tcu::TestLog & log,const tcu::ConstPixelBufferAccess & reference,const tcu::ConstPixelBufferAccess & result,const vk::VkPrimitiveTopology topology)257 inline bool imageCompare (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const vk::VkPrimitiveTopology topology)
258 {
259 if (topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
260 {
261 return tcu::intThresholdPositionDeviationCompare(
262 log, "Result", "Image comparison result", reference, result,
263 tcu::UVec4(4u), // color threshold
264 tcu::IVec3(1, 1, 0), // position deviation tolerance
265 true, // don't check the pixels at the boundary
266 tcu::COMPARE_LOG_RESULT);
267 }
268 else
269 return tcu::fuzzyCompare(log, "Result", "Image comparison result", reference, result, 0.053f, tcu::COMPARE_LOG_RESULT);
270 }
271
272 class DrawTestInstanceBase : public TestInstance
273 {
274 public:
275 DrawTestInstanceBase (Context& context);
276 virtual ~DrawTestInstanceBase (void) = 0;
277 void initialize (const DrawParamsBase& data);
278 void initPipeline (const vk::VkDevice device);
279 void beginRenderPass (void);
280 void endRenderPass (void);
281
282 // Specialize this function for each type
283 virtual tcu::TestStatus iterate (void) = 0;
284 protected:
285 // Specialize this function for each type
286 virtual void generateDrawData (void) = 0;
287 void generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
288
289 DrawParamsBase m_data;
290 const vk::DeviceInterface& m_vk;
291 vk::Move<vk::VkPipeline> m_pipeline;
292 vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
293 vk::VkFormat m_colorAttachmentFormat;
294 de::SharedPtr<Image> m_colorTargetImage;
295 vk::Move<vk::VkImageView> m_colorTargetView;
296 vk::Move<vk::VkRenderPass> m_renderPass;
297 vk::Move<vk::VkFramebuffer> m_framebuffer;
298 PipelineCreateInfo::VertexInputState m_vertexInputState;
299 de::SharedPtr<Buffer> m_vertexBuffer;
300 vk::Move<vk::VkCommandPool> m_cmdPool;
301 vk::Move<vk::VkCommandBuffer> m_cmdBuffer;
302
303 enum
304 {
305 WIDTH = 256,
306 HEIGHT = 256
307 };
308 };
309
DrawTestInstanceBase(Context & context)310 DrawTestInstanceBase::DrawTestInstanceBase (Context& context)
311 : vkt::TestInstance (context)
312 , m_vk (context.getDeviceInterface())
313 , m_colorAttachmentFormat (vk::VK_FORMAT_R8G8B8A8_UNORM)
314 {
315 }
316
~DrawTestInstanceBase(void)317 DrawTestInstanceBase::~DrawTestInstanceBase (void)
318 {
319 }
320
initialize(const DrawParamsBase & data)321 void DrawTestInstanceBase::initialize (const DrawParamsBase& data)
322 {
323 m_data = data;
324
325 const vk::VkDevice device = m_context.getDevice();
326 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
327
328 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
329 m_pipelineLayout = vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
330
331 const vk::VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 };
332 const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
333 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);
334
335 m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
336
337 const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
338 m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo);
339
340 // create render pass only when we are not using dynamic rendering
341 if (!m_data.useDynamicRendering)
342 {
343 RenderPassCreateInfo renderPassCreateInfo;
344 renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
345 vk::VK_SAMPLE_COUNT_1_BIT,
346 vk::VK_ATTACHMENT_LOAD_OP_LOAD,
347 vk::VK_ATTACHMENT_STORE_OP_STORE,
348 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
349 vk::VK_ATTACHMENT_STORE_OP_STORE,
350 vk::VK_IMAGE_LAYOUT_GENERAL,
351 vk::VK_IMAGE_LAYOUT_GENERAL));
352
353 const vk::VkAttachmentReference colorAttachmentReference
354 {
355 0,
356 vk::VK_IMAGE_LAYOUT_GENERAL
357 };
358
359 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
360 0,
361 0,
362 DE_NULL,
363 1,
364 &colorAttachmentReference,
365 DE_NULL,
366 AttachmentReference(),
367 0,
368 DE_NULL));
369
370 m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
371
372 // create framebuffer
373 std::vector<vk::VkImageView> colorAttachments { *m_colorTargetView };
374 const FramebufferCreateInfo framebufferCreateInfo (*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
375 m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
376 }
377
378 const vk::VkVertexInputBindingDescription vertexInputBindingDescription =
379 {
380 0,
381 (deUint32)sizeof(tcu::Vec4) * 2,
382 vk::VK_VERTEX_INPUT_RATE_VERTEX,
383 };
384
385 const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
386 {
387 {
388 0u,
389 0u,
390 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
391 0u
392 },
393 {
394 1u,
395 0u,
396 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
397 (deUint32)(sizeof(float)* 4),
398 }
399 };
400
401 m_vertexInputState = PipelineCreateInfo::VertexInputState(1,
402 &vertexInputBindingDescription,
403 2,
404 vertexInputAttributeDescriptions);
405
406 const vk::VkDeviceSize dataSize = m_data.vertices.size() * sizeof(PositionColorVertex);
407 m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, BufferCreateInfo(dataSize,
408 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
409
410 deUint8* ptr = reinterpret_cast<deUint8*>(m_vertexBuffer->getBoundMemory().getHostPtr());
411 deMemcpy(ptr, &(m_data.vertices[0]), static_cast<size_t>(dataSize));
412
413 vk::flushAlloc(m_vk, device, m_vertexBuffer->getBoundMemory());
414
415 const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
416 m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
417 m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
418
419 initPipeline(device);
420 }
421
initPipeline(const vk::VkDevice device)422 void DrawTestInstanceBase::initPipeline (const vk::VkDevice device)
423 {
424 const vk::Unique<vk::VkShaderModule> vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
425 const vk::Unique<vk::VkShaderModule> fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
426
427 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
428
429 vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
430 vk::VkRect2D scissor = vk::makeRect2D(WIDTH, HEIGHT);
431
432 // when dynamic_rendering is tested then renderPass won't be created and VK_NULL_HANDLE will be used here
433 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
434 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
435 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
436 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
437 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_data.topology));
438 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
439 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
440 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
441 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
442 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
443
444 vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
445 {
446 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
447 DE_NULL,
448 0u,
449 1u,
450 &m_colorAttachmentFormat,
451 vk::VK_FORMAT_UNDEFINED,
452 vk::VK_FORMAT_UNDEFINED
453 };
454
455 if (m_data.useDynamicRendering)
456 pipelineCreateInfo.pNext = &renderingCreateInfo;
457
458 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
459 }
460
beginRenderPass(void)461 void DrawTestInstanceBase::beginRenderPass (void)
462 {
463 const vk::VkClearValue clearColor { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
464
465 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
466
467 initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
468 vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
469
470 const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
471 m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
472 vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange);
473
474 const vk::VkMemoryBarrier memBarrier =
475 {
476 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
477 DE_NULL,
478 vk::VK_ACCESS_TRANSFER_WRITE_BIT,
479 vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
480 };
481
482 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
483 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
484 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
485
486 const vk::VkRect2D renderArea = vk::makeRect2D(WIDTH, HEIGHT);
487
488 if (m_data.useDynamicRendering)
489 vk::beginRendering(m_vk, *m_cmdBuffer, *m_colorTargetView, renderArea, clearColor);
490 else
491 vk::beginRenderPass(m_vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, 1u, &clearColor);
492 }
493
endRenderPass(void)494 void DrawTestInstanceBase::endRenderPass (void)
495 {
496 if (m_data.useDynamicRendering)
497 vk::endRendering(m_vk, *m_cmdBuffer);
498 else
499 vk::endRenderPass(m_vk, *m_cmdBuffer);
500 }
501
generateRefImage(const tcu::PixelBufferAccess & access,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const502 void DrawTestInstanceBase::generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
503 {
504 const PassthruVertShader vertShader;
505 const PassthruFragShader fragShader;
506 const rr::Program program (&vertShader, &fragShader);
507 const rr::MultisamplePixelBufferAccess colorBuffer = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(access);
508 const rr::RenderTarget renderTarget (colorBuffer);
509 const rr::RenderState renderState ((rr::ViewportState(colorBuffer)), m_context.getDeviceProperties().limits.subPixelPrecisionBits);
510 const rr::Renderer renderer;
511
512 const rr::VertexAttrib vertexAttribs[] =
513 {
514 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
515 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0])
516 };
517
518 renderer.draw(rr::DrawCommand(renderState,
519 renderTarget,
520 program,
521 DE_LENGTH_OF_ARRAY(vertexAttribs),
522 &vertexAttribs[0],
523 rr::PrimitiveList(mapVkPrimitiveTopology(m_data.topology), (deUint32)vertices.size(), 0)));
524 }
525
526 template<typename T>
527 class DrawTestInstance : public DrawTestInstanceBase
528 {
529 public:
530 DrawTestInstance (Context& context, const T& data);
531 virtual ~DrawTestInstance (void);
532 virtual void generateDrawData (void);
533 virtual tcu::TestStatus iterate (void);
534 private:
535 T m_data;
536 };
537
538 template<typename T>
DrawTestInstance(Context & context,const T & data)539 DrawTestInstance<T>::DrawTestInstance (Context& context, const T& data)
540 : DrawTestInstanceBase (context)
541 , m_data (data)
542 {
543 generateDrawData();
544 initialize(m_data);
545 }
546
547 template<typename T>
~DrawTestInstance(void)548 DrawTestInstance<T>::~DrawTestInstance (void)
549 {
550 }
551
552 template<typename T>
generateDrawData(void)553 void DrawTestInstance<T>::generateDrawData (void)
554 {
555 DE_FATAL("Using the general case of this function is forbidden!");
556 }
557
558 template<typename T>
iterate(void)559 tcu::TestStatus DrawTestInstance<T>::iterate (void)
560 {
561 DE_FATAL("Using the general case of this function is forbidden!");
562 return tcu::TestStatus::fail("");
563 }
564
565 template<typename T>
566 class DrawTestCase : public TestCase
567 {
568 public:
569 DrawTestCase (tcu::TestContext& context, const char* name, const char* desc, const T data);
570 ~DrawTestCase (void);
571 virtual void initPrograms (vk::SourceCollections& programCollection) const;
572 virtual void initShaderSources (void);
573 virtual void checkSupport (Context& context) const;
574 virtual TestInstance* createInstance (Context& context) const;
575
576 private:
577 T m_data;
578 std::string m_vertShaderSource;
579 std::string m_fragShaderSource;
580 };
581
582 template<typename T>
DrawTestCase(tcu::TestContext & context,const char * name,const char * desc,const T data)583 DrawTestCase<T>::DrawTestCase (tcu::TestContext& context, const char* name, const char* desc, const T data)
584 : vkt::TestCase (context, name, desc)
585 , m_data (data)
586 {
587 initShaderSources();
588 }
589
590 template<typename T>
~DrawTestCase(void)591 DrawTestCase<T>::~DrawTestCase (void)
592 {
593 }
594
595 template<typename T>
initPrograms(vk::SourceCollections & programCollection) const596 void DrawTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
597 {
598 programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
599 programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
600 }
601
602 template<typename T>
checkSupport(Context & context) const603 void DrawTestCase<T>::checkSupport (Context& context) const
604 {
605 if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
606 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
607 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ||
608 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY)
609 {
610 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
611 }
612
613 if (m_data.useDynamicRendering)
614 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
615
616 if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
617 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
618 !context.getPortabilitySubsetFeatures().triangleFans)
619 {
620 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
621 }
622 }
623
624 template<typename T>
initShaderSources(void)625 void DrawTestCase<T>::initShaderSources (void)
626 {
627 std::stringstream vertShader;
628 vertShader << "#version 430\n"
629 << "layout(location = 0) in vec4 in_position;\n"
630 << "layout(location = 1) in vec4 in_color;\n"
631 << "layout(location = 0) out vec4 out_color;\n"
632
633 << "out gl_PerVertex {\n"
634 << " vec4 gl_Position;\n"
635 << " float gl_PointSize;\n"
636 << "};\n"
637 << "void main() {\n"
638 << " gl_PointSize = 1.0;\n"
639 << " gl_Position = in_position;\n"
640 << " out_color = in_color;\n"
641 << "}\n";
642
643 m_vertShaderSource = vertShader.str();
644
645 std::stringstream fragShader;
646 fragShader << "#version 430\n"
647 << "layout(location = 0) in vec4 in_color;\n"
648 << "layout(location = 0) out vec4 out_color;\n"
649 << "void main()\n"
650 << "{\n"
651 << " out_color = in_color;\n"
652 << "}\n";
653
654 m_fragShaderSource = fragShader.str();
655 }
656
657 template<typename T>
createInstance(Context & context) const658 TestInstance* DrawTestCase<T>::createInstance (Context& context) const
659 {
660 return new DrawTestInstance<T>(context, m_data);
661 }
662
663 // Specialized cases
664 template<>
generateDrawData(void)665 void DrawTestInstance<DrawParams>::generateDrawData (void)
666 {
667 de::Random rnd (SEED ^ m_data.params.firstVertex ^ m_data.params.vertexCount);
668
669 const deUint32 vectorSize = m_data.params.firstVertex + m_data.params.vertexCount;
670
671 // Initialize the vector
672 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)));
673
674 // Fill only the used indexes
675 for (deUint32 vertexIdx = m_data.params.firstVertex; vertexIdx < vectorSize; ++vertexIdx)
676 {
677 const float f0 = rnd.getFloat(-1.0f, 1.0f);
678 const float f1 = rnd.getFloat(-1.0f, 1.0f);
679
680 m_data.vertices[vertexIdx] = PositionColorVertex(
681 tcu::Vec4(f0, f1, 1.0f, 1.0f), // Coord
682 tcu::randomVec4(rnd)); // Color
683 }
684 }
685
686 template<>
iterate(void)687 tcu::TestStatus DrawTestInstance<DrawParams>::iterate (void)
688 {
689 tcu::TestLog &log = m_context.getTestContext().getLog();
690 const vk::VkQueue queue = m_context.getUniversalQueue();
691 const vk::VkDevice device = m_context.getDevice();
692
693 beginRenderPass();
694
695 const vk::VkDeviceSize vertexBufferOffset = 0;
696 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
697
698 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
699 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
700 m_vk.cmdDraw(*m_cmdBuffer, m_data.params.vertexCount, m_data.params.instanceCount, m_data.params.firstVertex, m_data.params.firstInstance);
701 endRenderPass();
702 endCommandBuffer(m_vk, *m_cmdBuffer);
703
704 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
705
706 // Validation
707 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
708 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
709
710 std::vector<tcu::Vec4> vertices;
711 std::vector<tcu::Vec4> colors;
712
713 for (std::vector<PositionColorVertex>::const_iterator vertex = m_data.vertices.begin() + m_data.params.firstVertex; vertex != m_data.vertices.end(); ++vertex)
714 {
715 vertices.push_back(vertex->position);
716 colors.push_back(vertex->color);
717 }
718 generateRefImage(refImage.getAccess(), vertices, colors);
719
720 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
721 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
722 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
723
724 qpTestResult res = QP_TEST_RESULT_PASS;
725
726 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
727 res = QP_TEST_RESULT_FAIL;
728
729 return tcu::TestStatus(res, qpGetTestResultName(res));
730 }
731
732 template<>
generateDrawData(void)733 void DrawTestInstance<DrawIndexedParams>::generateDrawData (void)
734 {
735 de::Random rnd (SEED ^ m_data.params.firstIndex ^ m_data.params.indexCount);
736 const deUint32 indexSize = m_data.params.firstIndex + m_data.params.indexCount;
737
738 // Initialize the vector with zeros
739 m_data.indexes = std::vector<deUint32>(indexSize, 0);
740
741 deUint32 highestIndex = 0; // Store to highest index to calculate the vertices size
742 // Fill the indexes from firstIndex
743 for (deUint32 idx = 0; idx < m_data.params.indexCount; ++idx)
744 {
745 deUint32 vertexIdx = rnd.getInt(m_data.params.vertexOffset, INDEX_LIMIT);
746 highestIndex = (vertexIdx > highestIndex) ? vertexIdx : highestIndex;
747
748 m_data.indexes[m_data.params.firstIndex + idx] = vertexIdx;
749 }
750
751 // Fill up the vertex coordinates with zeros until the highestIndex including the vertexOffset
752 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)));
753
754 // Generate random vertex only where you have index pointing at
755 for (std::vector<deUint32>::const_iterator indexIt = m_data.indexes.begin() + m_data.params.firstIndex; indexIt != m_data.indexes.end(); ++indexIt)
756 {
757 // Get iterator to the vertex position with the vertexOffset
758 std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + m_data.params.vertexOffset + *indexIt;
759
760 tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
761 const float f0 = rnd.getFloat(-1.0f, 1.0f);
762 const float f1 = rnd.getFloat(-1.0f, 1.0f);
763 positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
764
765 tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
766 colorAccess = tcu::randomVec4(rnd);
767 }
768 }
769
770 template<>
iterate(void)771 tcu::TestStatus DrawTestInstance<DrawIndexedParams>::iterate (void)
772 {
773 tcu::TestLog &log = m_context.getTestContext().getLog();
774 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
775 const vk::VkDevice vkDevice = m_context.getDevice();
776 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
777 const vk::VkQueue queue = m_context.getUniversalQueue();
778 vk::Allocator& allocator = m_context.getDefaultAllocator();
779
780 beginRenderPass();
781
782 const vk::VkDeviceSize vertexBufferOffset = 0;
783 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
784
785 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
786 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
787
788 const deUint32 bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
789
790 vk::Move<vk::VkBuffer> indexBuffer;
791
792 const vk::VkBufferCreateInfo bufferCreateInfo =
793 {
794 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
795 DE_NULL, // const void* pNext;
796 0u, // VkBufferCreateFlags flags;
797 bufferSize, // VkDeviceSize size;
798 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage;
799 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
800 1u, // deUint32 queueFamilyIndexCount;
801 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
802 };
803
804 indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
805
806 de::MovePtr<vk::Allocation> indexAlloc;
807
808 indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
809 VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
810
811 deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
812
813 vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
814
815 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
816 m_vk.cmdDrawIndexed(*m_cmdBuffer, m_data.params.indexCount, m_data.params.instanceCount, m_data.params.firstIndex, m_data.params.vertexOffset, m_data.params.firstInstance);
817 endRenderPass();
818 endCommandBuffer(m_vk, *m_cmdBuffer);
819
820 submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
821
822 // Validation
823 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
824 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
825
826 std::vector<tcu::Vec4> vertices;
827 std::vector<tcu::Vec4> colors;
828
829 for (std::vector<deUint32>::const_iterator it = m_data.indexes.begin() + m_data.params.firstIndex; it != m_data.indexes.end(); ++it)
830 {
831 deUint32 idx = m_data.params.vertexOffset + *it;
832 vertices.push_back(m_data.vertices[idx].position);
833 colors.push_back(m_data.vertices[idx].color);
834 }
835 generateRefImage(refImage.getAccess(), vertices, colors);
836
837 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
838 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
839 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
840
841 qpTestResult res = QP_TEST_RESULT_PASS;
842
843 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
844 res = QP_TEST_RESULT_FAIL;
845
846 return tcu::TestStatus(res, qpGetTestResultName(res));
847 }
848
849 template<>
generateDrawData(void)850 void DrawTestInstance<DrawIndirectParams>::generateDrawData (void)
851 {
852 de::Random rnd(SEED ^ m_data.commands[0].vertexCount ^ m_data.commands[0].firstVertex);
853
854 deUint32 lastIndex = 0;
855
856 // Find the interval which will be used
857 for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
858 {
859 const deUint32 index = it->firstVertex + it->vertexCount;
860 lastIndex = (index > lastIndex) ? index : lastIndex;
861 }
862
863 // Initialize with zeros
864 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)));
865
866 // Generate random vertices only where necessary
867 for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
868 {
869 std::vector<PositionColorVertex>::iterator vertexStart = m_data.vertices.begin() + it->firstVertex;
870
871 for (deUint32 idx = 0; idx < it->vertexCount; ++idx)
872 {
873 std::vector<PositionColorVertex>::iterator vertexIt = vertexStart + idx;
874
875 tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
876 const float f0 = rnd.getFloat(-1.0f, 1.0f);
877 const float f1 = rnd.getFloat(-1.0f, 1.0f);
878 positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
879
880 tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
881 colorAccess = tcu::randomVec4(rnd);
882 }
883 }
884 }
885
886 template<>
iterate(void)887 tcu::TestStatus DrawTestInstance<DrawIndirectParams>::iterate (void)
888 {
889 tcu::TestLog &log = m_context.getTestContext().getLog();
890 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
891 const vk::VkDevice vkDevice = m_context.getDevice();
892 vk::Allocator& allocator = m_context.getDefaultAllocator();
893 const vk::VkQueue queue = m_context.getUniversalQueue();
894 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
895 const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
896
897 beginRenderPass();
898
899 const vk::VkDeviceSize vertexBufferOffset = 0;
900 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
901
902 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
903 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
904
905 vk::Move<vk::VkBuffer> indirectBuffer;
906 de::MovePtr<vk::Allocation> indirectAlloc;
907
908 {
909 const vk::VkDeviceSize indirectInfoSize = m_data.commands.size() * sizeof(vk::VkDrawIndirectCommand);
910
911 const vk::VkBufferCreateInfo indirectCreateInfo =
912 {
913 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
914 DE_NULL, // const void* pNext;
915 0u, // VkBufferCreateFlags flags;
916 indirectInfoSize, // VkDeviceSize size;
917 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, // VkBufferUsageFlags usage;
918 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
919 1u, // deUint32 queueFamilyIndexCount;
920 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
921 };
922
923 indirectBuffer = createBuffer(vk, vkDevice, &indirectCreateInfo);
924 indirectAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
925 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
926
927 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
928
929 vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
930 }
931
932 // If multiDrawIndirect not supported execute single calls
933 if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
934 {
935 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
936 {
937 const deUint32 offset = (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndirectCommand));
938 m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndirectCommand));
939 }
940 }
941 else
942 {
943 m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndirectCommand));
944 }
945
946 endRenderPass();
947 endCommandBuffer(m_vk, *m_cmdBuffer);
948
949 submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
950
951 // Validation
952 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
953 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
954
955 for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
956 {
957 std::vector<tcu::Vec4> vertices;
958 std::vector<tcu::Vec4> colors;
959
960 std::vector<PositionColorVertex>::const_iterator firstIt = m_data.vertices.begin() + it->firstVertex;
961 std::vector<PositionColorVertex>::const_iterator lastIt = firstIt + it->vertexCount;
962
963 for (std::vector<PositionColorVertex>::const_iterator vertex = firstIt; vertex != lastIt; ++vertex)
964 {
965 vertices.push_back(vertex->position);
966 colors.push_back(vertex->color);
967 }
968 generateRefImage(refImage.getAccess(), vertices, colors);
969 }
970
971 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
972 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
973 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
974
975 qpTestResult res = QP_TEST_RESULT_PASS;
976
977 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
978 res = QP_TEST_RESULT_FAIL;
979
980 return tcu::TestStatus(res, qpGetTestResultName(res));
981 }
982
983 template<>
generateDrawData(void)984 void DrawTestInstance<DrawIndexedIndirectParams>::generateDrawData (void)
985 {
986 de::Random rnd (SEED ^ m_data.commands[0].firstIndex ^ m_data.commands[0].indexCount);
987
988 deUint32 lastIndex = 0;
989
990 // Get the maximum range of indexes
991 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
992 {
993 const deUint32 index = it->firstIndex + it->indexCount;
994 lastIndex = (index > lastIndex) ? index : lastIndex;
995 }
996
997 // Initialize the vector with zeros
998 m_data.indexes = std::vector<deUint32>(lastIndex, 0);
999
1000 deUint32 highestIndex = 0;
1001
1002 // Generate random indexes for the ranges
1003 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1004 {
1005 for (deUint32 idx = 0; idx < it->indexCount; ++idx)
1006 {
1007 const deUint32 vertexIdx = rnd.getInt(it->vertexOffset, INDEX_LIMIT);
1008 const deUint32 maxIndex = vertexIdx + it->vertexOffset;
1009
1010 highestIndex = (maxIndex > highestIndex) ? maxIndex : highestIndex;
1011 m_data.indexes[it->firstIndex + idx] = vertexIdx;
1012 }
1013 }
1014
1015 // Initialize the vertex vector
1016 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)));
1017
1018 // Generate random vertices in the used locations
1019 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmdIt = m_data.commands.begin(); cmdIt != m_data.commands.end(); ++cmdIt)
1020 {
1021 deUint32 firstIdx = cmdIt->firstIndex;
1022 deUint32 lastIdx = firstIdx + cmdIt->indexCount;
1023
1024 for (deUint32 idx = firstIdx; idx < lastIdx; ++idx)
1025 {
1026 std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + cmdIt->vertexOffset + m_data.indexes[idx];
1027
1028 tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1029 const float f0 = rnd.getFloat(-1.0f, 1.0f);
1030 const float f1 = rnd.getFloat(-1.0f, 1.0f);
1031 positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1032
1033 tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1034 colorAccess = tcu::randomVec4(rnd);
1035 }
1036 }
1037 }
1038
1039 template<>
iterate(void)1040 tcu::TestStatus DrawTestInstance<DrawIndexedIndirectParams>::iterate (void)
1041 {
1042 tcu::TestLog &log = m_context.getTestContext().getLog();
1043 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
1044 const vk::VkDevice vkDevice = m_context.getDevice();
1045 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1046 const vk::VkQueue queue = m_context.getUniversalQueue();
1047 vk::Allocator& allocator = m_context.getDefaultAllocator();
1048 const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
1049
1050 beginRenderPass();
1051
1052 const vk::VkDeviceSize vertexBufferOffset = 0;
1053 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
1054
1055 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1056 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1057
1058 vk::Move<vk::VkBuffer> indirectBuffer;
1059 de::MovePtr<vk::Allocation> indirectAlloc;
1060
1061 {
1062 const vk::VkDeviceSize indirectInfoSize = m_data.commands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
1063
1064 const vk::VkBufferCreateInfo indirectCreateInfo =
1065 {
1066 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1067 DE_NULL, // const void* pNext;
1068 0u, // VkBufferCreateFlags flags;
1069 indirectInfoSize, // VkDeviceSize size;
1070 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, // VkBufferUsageFlags usage;
1071 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1072 1u, // deUint32 queueFamilyIndexCount;
1073 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
1074 };
1075
1076 indirectBuffer = createBuffer(vk, vkDevice, &indirectCreateInfo);
1077 indirectAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1078 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1079
1080 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1081
1082 vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1083 }
1084
1085 const deUint32 bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
1086
1087 vk::Move<vk::VkBuffer> indexBuffer;
1088
1089 const vk::VkBufferCreateInfo bufferCreateInfo =
1090 {
1091 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1092 DE_NULL, // const void* pNext;
1093 0u, // VkBufferCreateFlags flags;
1094 bufferSize, // VkDeviceSize size;
1095 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage;
1096 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1097 1u, // deUint32 queueFamilyIndexCount;
1098 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
1099 };
1100
1101 indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1102
1103 de::MovePtr<vk::Allocation> indexAlloc;
1104
1105 indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1106 VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1107
1108 deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1109
1110 vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
1111
1112 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1113
1114 // If multiDrawIndirect not supported execute single calls
1115 if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1116 {
1117 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1118 {
1119 const deUint32 offset = (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndexedIndirectCommand));
1120 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndexedIndirectCommand));
1121 }
1122 }
1123 else
1124 {
1125 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndexedIndirectCommand));
1126 }
1127
1128 endRenderPass();
1129 endCommandBuffer(m_vk, *m_cmdBuffer);
1130
1131 submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1132
1133 // Validation
1134 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1135 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1136
1137 for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmd = m_data.commands.begin(); cmd != m_data.commands.end(); ++cmd)
1138 {
1139 std::vector<tcu::Vec4> vertices;
1140 std::vector<tcu::Vec4> colors;
1141
1142 for (deUint32 idx = 0; idx < cmd->indexCount; ++idx)
1143 {
1144 const deUint32 vertexIndex = cmd->vertexOffset + m_data.indexes[cmd->firstIndex + idx];
1145 vertices.push_back(m_data.vertices[vertexIndex].position);
1146 colors.push_back(m_data.vertices[vertexIndex].color);
1147 }
1148 generateRefImage(refImage.getAccess(), vertices, colors);
1149 }
1150
1151 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1152 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1153 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1154
1155 qpTestResult res = QP_TEST_RESULT_PASS;
1156
1157 if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1158 res = QP_TEST_RESULT_FAIL;
1159
1160 return tcu::TestStatus(res, qpGetTestResultName(res));
1161 }
1162
1163 typedef DrawTestCase<DrawParams> DrawCase;
1164 typedef DrawTestCase<DrawIndexedParams> IndexedCase;
1165 typedef DrawTestCase<DrawIndirectParams> IndirectCase;
1166 typedef DrawTestCase<DrawIndexedIndirectParams> IndexedIndirectCase;
1167
1168 struct TestCaseParams
1169 {
1170 const DrawCommandType command;
1171 const vk::VkPrimitiveTopology topology;
1172 const bool useDynamicRendering;
1173
TestCaseParamsvkt::Draw::__anondb648a740111::TestCaseParams1174 TestCaseParams (const DrawCommandType cmd, const vk::VkPrimitiveTopology top, bool dynamicRendering)
1175 : command (cmd)
1176 , topology (top)
1177 , useDynamicRendering (dynamicRendering)
1178 {}
1179 };
1180
1181 } // anonymous
1182
populateSubGroup(tcu::TestCaseGroup * testGroup,const TestCaseParams caseParams)1183 void populateSubGroup (tcu::TestCaseGroup* testGroup, const TestCaseParams caseParams)
1184 {
1185 de::Random rnd (SEED ^ deStringHash(testGroup->getName()));
1186 tcu::TestContext& testCtx = testGroup->getTestContext();
1187 const DrawCommandType command = caseParams.command;
1188 const vk::VkPrimitiveTopology topology = caseParams.topology;
1189 const bool useDynamicRendering = caseParams.useDynamicRendering;
1190 const deUint32 primitiveCountArrLength = DE_LENGTH_OF_ARRAY(PRIMITIVE_COUNT);
1191
1192 for (deUint32 primitiveCountIdx = 0; primitiveCountIdx < primitiveCountArrLength; ++primitiveCountIdx)
1193 {
1194 const deUint32 primitives = PRIMITIVE_COUNT[primitiveCountIdx];
1195
1196 // when testing VK_KHR_dynamic_rendering there is no need to duplicate tests for all primitive counts; use just 1 and 45
1197 if (useDynamicRendering && (primitiveCountIdx != 0) && (primitiveCountIdx != primitiveCountArrLength-1))
1198 continue;
1199
1200 deUint32 multiplier = 1;
1201 deUint32 offset = 0;
1202 // Calculated by Vulkan 23.1
1203 switch (topology)
1204 {
1205 case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST: break;
1206 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST: multiplier = 2; break;
1207 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: break;
1208 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: multiplier = 3; break;
1209 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: break;
1210 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: offset = 1; break;
1211 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: multiplier = 4; offset = 1; break;
1212 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: offset = 1; break;
1213 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: multiplier = 6; break;
1214 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: multiplier = 2; break;
1215 default: DE_FATAL("Unsupported topology.");
1216 }
1217
1218 const deUint32 vertexCount = multiplier * primitives + offset;
1219 std::string name = de::toString(primitives);
1220
1221 switch (command)
1222 {
1223 case DRAW_COMMAND_TYPE_DRAW:
1224 {
1225 deUint32 firstPrimitive = rnd.getInt(0, primitives);
1226 deUint32 firstVertex = multiplier * firstPrimitive;
1227 testGroup->addChild(new DrawCase(testCtx, name.c_str(), "vkCmdDraw testcase.",
1228 DrawParams(topology, useDynamicRendering, vertexCount, 1, firstVertex, 0))
1229 );
1230 break;
1231 }
1232 case DRAW_COMMAND_TYPE_DRAW_INDEXED:
1233 {
1234 deUint32 firstIndex = rnd.getInt(0, OFFSET_LIMIT);
1235 deUint32 vertexOffset = rnd.getInt(0, OFFSET_LIMIT);
1236 testGroup->addChild(new IndexedCase(testCtx, name.c_str(), "vkCmdDrawIndexed testcase.",
1237 DrawIndexedParams(topology, useDynamicRendering, vk::VK_INDEX_TYPE_UINT32, vertexCount, 1, firstIndex, vertexOffset, 0))
1238 );
1239 break;
1240 }
1241 case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
1242 {
1243 deUint32 firstVertex = rnd.getInt(0, OFFSET_LIMIT);
1244
1245 DrawIndirectParams params = DrawIndirectParams(topology, useDynamicRendering);
1246
1247 params.addCommand(vertexCount, 1, 0, 0);
1248 testGroup->addChild(new IndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1249
1250 params.addCommand(vertexCount, 1, firstVertex, 0);
1251 testGroup->addChild(new IndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1252 break;
1253 }
1254 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
1255 {
1256 deUint32 firstIndex = rnd.getInt(vertexCount, OFFSET_LIMIT);
1257 deUint32 vertexOffset = rnd.getInt(vertexCount, OFFSET_LIMIT);
1258
1259 DrawIndexedIndirectParams params = DrawIndexedIndirectParams(topology, useDynamicRendering, vk::VK_INDEX_TYPE_UINT32);
1260 params.addCommand(vertexCount, 1, 0, 0, 0);
1261 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1262
1263 params.addCommand(vertexCount, 1, firstIndex, vertexOffset, 0);
1264 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1265 break;
1266 }
1267 default:
1268 DE_FATAL("Unsupported draw command.");
1269 }
1270 }
1271 }
1272
createDrawTests(tcu::TestCaseGroup * testGroup,bool useDynamicRendering)1273 void createDrawTests(tcu::TestCaseGroup* testGroup, bool useDynamicRendering)
1274 {
1275 for (deUint32 drawTypeIndex = 0; drawTypeIndex < DRAW_COMMAND_TYPE_DRAW_LAST; ++drawTypeIndex)
1276 {
1277 const DrawCommandType command (static_cast<DrawCommandType>(drawTypeIndex));
1278 de::MovePtr<tcu::TestCaseGroup> topologyGroup (new tcu::TestCaseGroup(testGroup->getTestContext(), getDrawCommandTypeName(command), "Group for testing a specific draw command."));
1279
1280 for (deUint32 topologyIdx = 0; topologyIdx != vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; ++topologyIdx)
1281 {
1282 const vk::VkPrimitiveTopology topology (static_cast<vk::VkPrimitiveTopology>(topologyIdx));
1283 const std::string groupName (de::toLower(getPrimitiveTopologyName(topology)).substr(22));
1284
1285 addTestGroup(topologyGroup.get(), groupName, "Testcases with a specific topology.", populateSubGroup, TestCaseParams(command, topology, useDynamicRendering));
1286 }
1287
1288 testGroup->addChild(topologyGroup.release());
1289 }
1290 }
1291
createBasicDrawTests(tcu::TestContext & testCtx,bool useDynamicRendering)1292 tcu::TestCaseGroup* createBasicDrawTests (tcu::TestContext& testCtx, bool useDynamicRendering)
1293 {
1294 return createTestGroup(testCtx, "basic_draw", "Basic drawing tests", createDrawTests, useDynamicRendering);
1295 }
1296
1297 } // DrawTests
1298 } // vkt
1299