1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2015 The Khronos Group Inc. 6 * Copyright (c) 2015 Intel Corporation 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 Draw Indirect Test 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktDrawIndirectTest.hpp" 26 27#include "vktTestCaseUtil.hpp" 28#include "vktDrawTestCaseUtil.hpp" 29 30#include "vktDrawBaseClass.hpp" 31 32#include "tcuTestLog.hpp" 33#include "tcuResource.hpp" 34#include "tcuImageCompare.hpp" 35#include "tcuTextureUtil.hpp" 36#include "tcuRGBA.hpp" 37 38#include "vkDefs.hpp" 39 40namespace vkt 41{ 42namespace Draw 43{ 44namespace 45{ 46 47enum 48{ 49 VERTEX_OFFSET = 13 50}; 51 52struct JunkData 53{ 54 JunkData() 55 : varA (0xcd) 56 , varB (0xcd) 57 { 58 } 59 const deUint16 varA; 60 const deUint32 varB; 61}; 62 63enum DrawType 64{ 65 DRAW_TYPE_SEQUENTIAL, 66 DRAW_TYPE_INDEXED, 67 68 DRAWTYPE_LAST 69}; 70 71struct DrawTypedTestSpec : public TestSpecBase 72{ 73 DrawType drawType; 74}; 75 76class IndirectDraw : public DrawTestsBaseClass 77{ 78public: 79 typedef DrawTypedTestSpec TestSpec; 80 81 IndirectDraw (Context &context, TestSpec testSpec); 82 virtual tcu::TestStatus iterate (void); 83 84 template<typename T> void addCommand (const T&); 85 86protected: 87 std::vector<char> m_indirectBufferContents; 88 de::SharedPtr<Buffer> m_indirectBuffer; 89 vk::VkDeviceSize m_offsetInBuffer; 90 deUint32 m_strideInBuffer; 91 92 deUint32 m_drawCount; 93 JunkData m_junkData; 94 95 const DrawType m_drawType; 96 deBool m_isMultiDrawEnabled; 97 deUint32 m_drawIndirectMaxCount; 98 99 de::SharedPtr<Buffer> m_indexBuffer; 100}; 101 102struct FirtsInstanceSupported 103{ 104 static deUint32 getFirstInstance (void) { return 2; } 105 static bool isTestSupported (const vk::VkPhysicalDeviceFeatures& features) { return features.drawIndirectFirstInstance == VK_TRUE; } 106}; 107 108struct FirtsInstanceNotSupported 109{ 110 static deUint32 getFirstInstance (void) { return 0; } 111 static bool isTestSupported (const vk::VkPhysicalDeviceFeatures&) { return true; } 112}; 113 114template<class FirstInstanceSupport> 115class IndirectDrawInstanced : public IndirectDraw 116{ 117public: 118 IndirectDrawInstanced (Context &context, TestSpec testSpec); 119 virtual tcu::TestStatus iterate (void); 120}; 121 122IndirectDraw::IndirectDraw (Context &context, TestSpec testSpec) 123 : DrawTestsBaseClass (context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.topology) 124 , m_drawType (testSpec.drawType) 125{ 126 127 int refVertexIndex = 2; 128 129 if (testSpec.drawType == DRAW_TYPE_INDEXED) 130 { 131 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++) 132 { 133 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1)); 134 } 135 refVertexIndex += VERTEX_OFFSET; 136 } 137 138 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1)); 139 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1)); 140 141 switch (m_topology) 142 { 143 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 144 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 145 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 146 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 147 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 148 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 149 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 150 break; 151 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 152 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 153 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 154 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 155 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 156 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 157 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 158 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 159 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++)); 160 break; 161 default: 162 DE_FATAL("Unknown topology"); 163 break; 164 } 165 166 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1)); 167 168 initialize(); 169 170 if (testSpec.drawType == DRAW_TYPE_INDEXED) 171 { 172 const size_t indexBufferLength = m_data.size() - VERTEX_OFFSET; 173 174 m_indexBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(sizeof(deUint32) * indexBufferLength, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible); 175 deUint32* indices = reinterpret_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr()); 176 for (size_t i = 0; i < indexBufferLength; i++) 177 { 178 indices[i] = static_cast<deUint32>(i); 179 } 180 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(), m_indexBuffer->getBoundMemory().getOffset(), sizeof(deUint32) * indexBufferLength); 181 } 182 183 // Check device for multidraw support: 184 if (m_context.getDeviceFeatures().multiDrawIndirect) 185 m_isMultiDrawEnabled = true; 186 else 187 m_isMultiDrawEnabled = false; 188 189 m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount; 190 191} 192 193template<> 194void IndirectDraw::addCommand<vk::VkDrawIndirectCommand> (const vk::VkDrawIndirectCommand& command) 195{ 196 DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL); 197 198 const size_t currentSize = m_indirectBufferContents.size(); 199 200 m_indirectBufferContents.resize(currentSize + sizeof(command)); 201 202 deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command)); 203} 204 205template<> 206void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand>(const vk::VkDrawIndexedIndirectCommand& command) 207{ 208 DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED); 209 210 const size_t currentSize = m_indirectBufferContents.size(); 211 212 m_indirectBufferContents.resize(currentSize + sizeof(command)); 213 214 deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command)); 215} 216 217tcu::TestStatus IndirectDraw::iterate (void) 218{ 219 tcu::TestLog &log = m_context.getTestContext().getLog(); 220 const vk::VkQueue queue = m_context.getUniversalQueue(); 221 222 if (m_drawType == DRAW_TYPE_SEQUENTIAL) 223 { 224 switch (m_topology) 225 { 226 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 227 { 228 vk::VkDrawIndirectCommand drawCommands[] = 229 { 230 { 231 3, //vertexCount 232 1, //instanceCount 233 2, //firstVertex 234 0 //firstInstance 235 }, 236 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride) 237 { 238 3, //vertexCount 239 1, //instanceCount 240 5, //firstVertex 241 0 //firstInstance 242 } 243 }; 244 addCommand(drawCommands[0]); 245 addCommand(drawCommands[1]); 246 addCommand(drawCommands[2]); 247 break; 248 } 249 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 250 { 251 vk::VkDrawIndirectCommand drawCommands[] = 252 { 253 { 254 4, //vertexCount 255 1, //instanceCount 256 2, //firstVertex 257 0 //firstInstance 258 }, 259 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride) 260 { 261 4, //vertexCount 262 1, //instanceCount 263 6, //firstVertex 264 0 //firstInstance 265 } 266 }; 267 addCommand(drawCommands[0]); 268 addCommand(drawCommands[1]); 269 addCommand(drawCommands[2]); 270 break; 271 } 272 default: 273 TCU_FAIL("impossible"); 274 } 275 276 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand); 277 } 278 else if (m_drawType == DRAW_TYPE_INDEXED) 279 { 280 switch (m_topology) 281 { 282 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 283 { 284 vk::VkDrawIndexedIndirectCommand drawCommands[] = 285 { 286 { 287 3, // indexCount 288 1, // instanceCount 289 2, // firstIndex 290 VERTEX_OFFSET, // vertexOffset 291 0, // firstInstance 292 }, 293 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride) 294 { 295 3, // indexCount 296 1, // instanceCount 297 5, // firstIndex 298 VERTEX_OFFSET, // vertexOffset 299 0, // firstInstance 300 } 301 }; 302 addCommand(drawCommands[0]); 303 addCommand(drawCommands[1]); 304 addCommand(drawCommands[2]); 305 break; 306 } 307 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 308 { 309 vk::VkDrawIndexedIndirectCommand drawCommands[] = 310 { 311 { 312 4, // indexCount 313 1, // instanceCount 314 2, // firstIndex 315 VERTEX_OFFSET, // vertexOffset 316 0, // firstInstance 317 }, 318 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride) 319 { 320 4, // indexCount 321 1, // instanceCount 322 6, // firstIndex 323 VERTEX_OFFSET, // vertexOffset 324 0, // firstInstance 325 } 326 }; 327 addCommand(drawCommands[0]); 328 addCommand(drawCommands[1]); 329 addCommand(drawCommands[2]); 330 break; 331 } 332 default: 333 TCU_FAIL("impossible"); 334 } 335 336 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand); 337 } 338 339 m_drawCount = 2; 340 m_offsetInBuffer = sizeof(m_junkData); 341 342 beginRenderPass(); 343 344 const vk::VkDeviceSize vertexBufferOffset = 0; 345 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object(); 346 347 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset); 348 349 const vk::VkDeviceSize dataSize = m_indirectBufferContents.size(); 350 351 m_indirectBuffer = Buffer::createAndAlloc( m_vk, 352 m_context.getDevice(), 353 BufferCreateInfo(dataSize + m_offsetInBuffer, 354 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), 355 m_context.getDefaultAllocator(), 356 vk::MemoryRequirement::HostVisible); 357 358 deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr()); 359 360 deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer)); 361 deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize)); 362 363 vk::flushMappedMemoryRange(m_vk, 364 m_context.getDevice(), 365 m_indirectBuffer->getBoundMemory().getMemory(), 366 m_indirectBuffer->getBoundMemory().getOffset(), 367 dataSize + m_offsetInBuffer); 368 369 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 370 371 if (m_drawType == DRAW_TYPE_INDEXED) 372 { 373 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32); 374 } 375 376 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount) 377 { 378 switch (m_drawType) 379 { 380 case DRAW_TYPE_SEQUENTIAL: 381 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer); 382 break; 383 case DRAW_TYPE_INDEXED: 384 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer); 385 break; 386 default: 387 TCU_FAIL("impossible"); 388 } 389 } 390 else 391 { 392 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++) 393 { 394 switch (m_drawType) 395 { 396 case DRAW_TYPE_SEQUENTIAL: 397 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u); 398 break; 399 case DRAW_TYPE_INDEXED: 400 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u); 401 break; 402 default: 403 TCU_FAIL("impossible"); 404 } 405 } 406 } 407 m_vk.cmdEndRenderPass(*m_cmdBuffer); 408 m_vk.endCommandBuffer(*m_cmdBuffer); 409 410 vk::VkSubmitInfo submitInfo = 411 { 412 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; 413 DE_NULL, // const void* pNext; 414 0, // deUint32 waitSemaphoreCount; 415 DE_NULL, // const VkSemaphore* pWaitSemaphores; 416 (const vk::VkPipelineStageFlags*)DE_NULL, 417 1, // deUint32 commandBufferCount; 418 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; 419 0, // deUint32 signalSemaphoreCount; 420 DE_NULL // const VkSemaphore* pSignalSemaphores; 421 }; 422 VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL)); 423 424 VK_CHECK(m_vk.queueWaitIdle(queue)); 425 426 // Validation 427 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT)); 428 referenceFrame.allocLevel(0); 429 430 const deInt32 frameWidth = referenceFrame.getWidth(); 431 const deInt32 frameHeight = referenceFrame.getHeight(); 432 433 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 434 435 ReferenceImageCoordinates refCoords; 436 437 for (int y = 0; y < frameHeight; y++) 438 { 439 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f; 440 441 for (int x = 0; x < frameWidth; x++) 442 { 443 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f; 444 445 if ((yCoord >= refCoords.bottom && 446 yCoord <= refCoords.top && 447 xCoord >= refCoords.left && 448 xCoord <= refCoords.right)) 449 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y); 450 } 451 } 452 453 const vk::VkOffset3D zeroOffset = { 0, 0, 0 }; 454 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), 455 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT); 456 457 qpTestResult res = QP_TEST_RESULT_PASS; 458 459 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", 460 referenceFrame.getLevel(0), renderedFrame, 0.05f, 461 tcu::COMPARE_LOG_RESULT)) { 462 res = QP_TEST_RESULT_FAIL; 463 } 464 465 return tcu::TestStatus(res, qpGetTestResultName(res)); 466 467} 468 469template<class FirstInstanceSupport> 470IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, TestSpec testSpec) 471 : IndirectDraw(context, testSpec) 472{ 473 if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures())) 474 { 475 throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported"); 476 } 477} 478 479template<class FirstInstanceSupport> 480tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void) 481{ 482 tcu::TestLog &log = m_context.getTestContext().getLog(); 483 const vk::VkQueue queue = m_context.getUniversalQueue(); 484 485 if (m_drawType == DRAW_TYPE_SEQUENTIAL) 486 { 487 switch (m_topology) 488 { 489 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 490 { 491 vk::VkDrawIndirectCommand drawCmd[] = 492 { 493 { 494 3, //vertexCount 495 4, //instanceCount 496 2, //firstVertex 497 FirstInstanceSupport::getFirstInstance() //firstInstance 498 }, 499 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride) 500 { 501 3, //vertexCount 502 4, //instanceCount 503 5, //firstVertex 504 FirstInstanceSupport::getFirstInstance() //firstInstance 505 } 506 }; 507 addCommand(drawCmd[0]); 508 addCommand(drawCmd[1]); 509 addCommand(drawCmd[2]); 510 break; 511 } 512 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 513 { 514 vk::VkDrawIndirectCommand drawCmd[] = 515 { 516 { 517 4, //vertexCount 518 4, //instanceCount 519 2, //firstVertex 520 FirstInstanceSupport::getFirstInstance() //firstInstance 521 }, 522 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, 523 { 524 4, //vertexCount 525 4, //instanceCount 526 6, //firstVertex 527 FirstInstanceSupport::getFirstInstance() //firstInstance 528 } 529 }; 530 addCommand(drawCmd[0]); 531 addCommand(drawCmd[1]); 532 addCommand(drawCmd[2]); 533 break; 534 } 535 default: 536 TCU_FAIL("impossible"); 537 break; 538 } 539 540 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand); 541 } 542 else if (m_drawType == DRAW_TYPE_INDEXED) 543 { 544 switch (m_topology) 545 { 546 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 547 { 548 vk::VkDrawIndexedIndirectCommand drawCmd[] = 549 { 550 { 551 3, // indexCount 552 4, // instanceCount 553 2, // firstIndex 554 VERTEX_OFFSET, // vertexOffset 555 FirstInstanceSupport::getFirstInstance() // firstInstance 556 }, 557 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride) 558 { 559 3, // indexCount 560 4, // instanceCount 561 5, // firstIndex 562 VERTEX_OFFSET, // vertexOffset 563 FirstInstanceSupport::getFirstInstance() // firstInstance 564 } 565 }; 566 addCommand(drawCmd[0]); 567 addCommand(drawCmd[1]); 568 addCommand(drawCmd[2]); 569 break; 570 } 571 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 572 { 573 vk::VkDrawIndexedIndirectCommand drawCmd[] = 574 { 575 { 576 4, // indexCount 577 4, // instanceCount 578 2, // firstIndex 579 VERTEX_OFFSET, // vertexOffset 580 FirstInstanceSupport::getFirstInstance() // firstInstance 581 }, 582 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride) 583 { 584 4, // indexCount 585 4, // instanceCount 586 6, // firstIndex 587 VERTEX_OFFSET, // vertexOffset 588 FirstInstanceSupport::getFirstInstance() // firstInstance 589 } 590 }; 591 addCommand(drawCmd[0]); 592 addCommand(drawCmd[1]); 593 addCommand(drawCmd[2]); 594 break; 595 } 596 default: 597 TCU_FAIL("impossible"); 598 break; 599 } 600 601 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand); 602 } 603 604 m_drawCount = 2; 605 m_offsetInBuffer = sizeof(m_junkData); 606 607 beginRenderPass(); 608 609 const vk::VkDeviceSize vertexBufferOffset = 0; 610 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object(); 611 612 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset); 613 614 const vk::VkDeviceSize dataSize = m_indirectBufferContents.size(); 615 616 m_indirectBuffer = Buffer::createAndAlloc( m_vk, 617 m_context.getDevice(), 618 BufferCreateInfo(dataSize + m_offsetInBuffer, 619 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), 620 m_context.getDefaultAllocator(), 621 vk::MemoryRequirement::HostVisible); 622 623 deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr()); 624 625 deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer)); 626 deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize)); 627 628 vk::flushMappedMemoryRange(m_vk, 629 m_context.getDevice(), 630 m_indirectBuffer->getBoundMemory().getMemory(), 631 m_indirectBuffer->getBoundMemory().getOffset(), 632 dataSize + m_offsetInBuffer); 633 634 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 635 636 if (m_drawType == DRAW_TYPE_INDEXED) 637 { 638 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32); 639 } 640 641 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount) 642 { 643 switch (m_drawType) 644 { 645 case DRAW_TYPE_SEQUENTIAL: 646 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer); 647 break; 648 case DRAW_TYPE_INDEXED: 649 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer); 650 break; 651 default: 652 TCU_FAIL("impossible"); 653 } 654 } 655 else 656 { 657 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++) 658 { 659 switch (m_drawType) 660 { 661 case DRAW_TYPE_SEQUENTIAL: 662 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u); 663 break; 664 case DRAW_TYPE_INDEXED: 665 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u); 666 break; 667 default: 668 TCU_FAIL("impossible"); 669 } 670 } 671 } 672 m_vk.cmdEndRenderPass(*m_cmdBuffer); 673 m_vk.endCommandBuffer(*m_cmdBuffer); 674 675 vk::VkSubmitInfo submitInfo = 676 { 677 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; 678 DE_NULL, // const void* pNext; 679 0, // deUint32 waitSemaphoreCount; 680 DE_NULL, // const VkSemaphore* pWaitSemaphores; 681 (const vk::VkPipelineStageFlags*)DE_NULL, 682 1, // deUint32 commandBufferCount; 683 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; 684 0, // deUint32 signalSemaphoreCount; 685 DE_NULL // const VkSemaphore* pSignalSemaphores; 686 }; 687 VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL)); 688 689 VK_CHECK(m_vk.queueWaitIdle(queue)); 690 691 // Validation 692 VK_CHECK(m_vk.queueWaitIdle(queue)); 693 694 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT)); 695 696 referenceFrame.allocLevel(0); 697 698 const deInt32 frameWidth = referenceFrame.getWidth(); 699 const deInt32 frameHeight = referenceFrame.getHeight(); 700 701 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 702 703 ReferenceImageInstancedCoordinates refInstancedCoords; 704 705 for (int y = 0; y < frameHeight; y++) 706 { 707 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f; 708 709 for (int x = 0; x < frameWidth; x++) 710 { 711 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f; 712 713 if ((yCoord >= refInstancedCoords.bottom && 714 yCoord <= refInstancedCoords.top && 715 xCoord >= refInstancedCoords.left && 716 xCoord <= refInstancedCoords.right)) 717 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y); 718 } 719 } 720 721 const vk::VkOffset3D zeroOffset = { 0, 0, 0 }; 722 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), 723 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT); 724 725 qpTestResult res = QP_TEST_RESULT_PASS; 726 727 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", 728 referenceFrame.getLevel(0), renderedFrame, 0.05f, 729 tcu::COMPARE_LOG_RESULT)) { 730 res = QP_TEST_RESULT_FAIL; 731 } 732 733 return tcu::TestStatus(res, qpGetTestResultName(res)); 734 735 } 736 737} // anonymous 738 739IndirectDrawTests::IndirectDrawTests (tcu::TestContext& testCtx) 740 : TestCaseGroup(testCtx, "indirect_draw", "indirect drawing simple geometry") 741{ 742 /* Left blank on purpose */ 743} 744 745IndirectDrawTests::~IndirectDrawTests (void) {} 746 747 748void IndirectDrawTests::init (void) 749{ 750 for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++) 751 { 752 std::string drawTypeStr; 753 switch (drawTypeIdx) 754 { 755 case DRAW_TYPE_SEQUENTIAL: 756 drawTypeStr = "sequential"; 757 break; 758 case DRAW_TYPE_INDEXED: 759 drawTypeStr = "indexed"; 760 break; 761 default: 762 TCU_FAIL("impossible"); 763 } 764 765 tcu::TestCaseGroup* drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str(), ("Draws geometry using " + drawTypeStr + "draw call").c_str()); 766 { 767 tcu::TestCaseGroup* indirectDrawGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry"); 768 { 769 IndirectDraw::TestSpec testSpec; 770 testSpec.drawType = static_cast<DrawType>(drawTypeIdx); 771 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert"; 772 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag"; 773 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 774 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec)); 775 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; 776 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec)); 777 } 778 drawTypeGroup->addChild(indirectDrawGroup); 779 780 781 tcu::TestCaseGroup* indirectDrawInstancedGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry"); 782 { 783 tcu::TestCaseGroup* noFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance"); 784 { 785 IndirectDrawInstanced<FirtsInstanceNotSupported>::TestSpec testSpec; 786 testSpec.drawType = static_cast<DrawType>(drawTypeIdx); 787 788 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert"; 789 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag"; 790 791 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 792 noFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceNotSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec)); 793 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; 794 noFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceNotSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec)); 795 } 796 indirectDrawInstancedGroup->addChild(noFirstInstanceGroup); 797 798 tcu::TestCaseGroup* firstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature"); 799 { 800 IndirectDrawInstanced<FirtsInstanceSupported>::TestSpec testSpec; 801 testSpec.drawType = static_cast<DrawType>(drawTypeIdx); 802 803 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert"; 804 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag"; 805 806 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 807 firstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec)); 808 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; 809 firstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec)); 810 } 811 indirectDrawInstancedGroup->addChild(firstInstanceGroup); 812 } 813 drawTypeGroup->addChild(indirectDrawInstancedGroup); 814 } 815 816 addChild(drawTypeGroup); 817 } 818} 819 820} // DrawTests 821} // vkt 822