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