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