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