1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2022 The Khronos Group Inc. 6 * Copyright (c) 2022 Valve 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 Tests using VK_EXT_mesh_shader and VK_EXT_conditional_rendering 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktMeshShaderConditionalRenderingTestsEXT.hpp" 26#include "vktMeshShaderUtil.hpp" 27#include "vktTestCase.hpp" 28 29#include "vkObjUtil.hpp" 30#include "vkQueryUtil.hpp" 31#include "vkMemUtil.hpp" 32#include "vkTypeUtil.hpp" 33#include "vkImageUtil.hpp" 34#include "vkImageWithMemory.hpp" 35#include "vkBufferWithMemory.hpp" 36#include "vkCmdUtil.hpp" 37#include "vkBarrierUtil.hpp" 38 39#include "tcuVector.hpp" 40#include "tcuImageCompare.hpp" 41 42#include <vector> 43#include <sstream> 44#include <memory> 45 46namespace vkt 47{ 48namespace MeshShader 49{ 50 51namespace 52{ 53 54using namespace vk; 55 56using GroupPtr = de::MovePtr<tcu::TestCaseGroup>; 57 58enum class DrawType 59{ 60 DRAW, 61 DRAW_INDIRECT, 62 DRAW_INDIRECT_WITH_COUNT, 63}; 64 65enum class CmdBufferType 66{ 67 PRIMARY, 68 SECONDARY, 69 SECONDARY_WITH_INHERITANCE, 70}; 71 72static constexpr VkDeviceSize kBindOffset = 16u; 73 74std::vector<uint32_t> getCondValues (void) 75{ 76 const std::vector<uint32_t> values = 77 { 78 0x01000000u, 79 0x00010000u, 80 0x00000100u, 81 0x00000001u, 82 0x00000000u, 83 }; 84 85 return values; 86} 87 88std::string paddedHex (uint32_t value) 89{ 90 std::ostringstream repr; 91 repr << "0x" << std::hex << std::setw(8u) << std::setfill('0') << value; 92 return repr.str(); 93} 94 95tcu::Vec4 getOutputColor (void) 96{ 97 return tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f); 98} 99 100tcu::Vec4 getClearColor (void) 101{ 102 return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 103} 104 105struct TestParams 106{ 107 DrawType drawType; 108 CmdBufferType cmdBufferType; 109 bool bindWithOffset; 110 bool condWithOffset; 111 uint32_t condValue; 112 bool inverted; 113 bool useTask; 114 115 bool needsSecondaryCmdBuffer (void) const 116 { 117 return (cmdBufferType != CmdBufferType::PRIMARY); 118 } 119}; 120 121class ConditionalRenderingCase : public vkt::TestCase 122{ 123public: 124 ConditionalRenderingCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params) 125 : vkt::TestCase (testCtx, name) 126 , m_params (params) 127 {} 128 virtual ~ConditionalRenderingCase (void) {} 129 130 void initPrograms (vk::SourceCollections& programCollection) const override; 131 TestInstance* createInstance (Context& context) const override; 132 void checkSupport (Context& context) const override; 133 134protected: 135 const TestParams m_params; 136}; 137 138class ConditionBuffer 139{ 140public: 141 ConditionBuffer (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, uint32_t condValue, bool bindWithOffset, bool condWithOffset) 142 : m_buffer () 143 , m_allocation () 144 , m_condOffset (0ull) 145 { 146 // Create buffer with the desired size first. 147 const auto condSize = static_cast<VkDeviceSize>(sizeof(condValue)); 148 const auto condOffset = (condWithOffset ? condSize : 0ull); 149 const auto bufferSize = condSize + condOffset; 150 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT); 151 auto buffer = createBuffer(vkd, device, &bufferCreateInfo); 152 153 // Allocate memory taking bindWithOffset into account. 154 const auto bufferMemReqs = getBufferMemoryRequirements(vkd, device, buffer.get()); 155 const auto bindOffset = (bindWithOffset ? de::roundUp(kBindOffset, bufferMemReqs.alignment) : 0ull); 156 const auto allocSize = bufferMemReqs.size + bindOffset; 157 158 const auto actualMemReqs = makeMemoryRequirements(allocSize, bufferMemReqs.alignment, bufferMemReqs.memoryTypeBits); 159 auto allocation = alloc.allocate(actualMemReqs, MemoryRequirement::HostVisible); 160 vkd.bindBufferMemory(device, buffer.get(), allocation->getMemory(), bindOffset); 161 162 // Fill buffer data. 163 const uint32_t fillValue = ((condValue != 0u) ? 0u : 1u); 164 uint8_t* hostPtr = reinterpret_cast<uint8_t*>(allocation->getHostPtr()); 165 166 deMemset(hostPtr, 0, static_cast<size_t>(actualMemReqs.size)); 167 deMemcpy(hostPtr + bindOffset, &fillValue, sizeof(fillValue)); 168 deMemcpy(hostPtr + bindOffset + condOffset, &condValue, sizeof(condValue)); 169 170 m_buffer = buffer; 171 m_allocation = allocation; 172 m_condOffset = condOffset; 173 } 174 175 VkDeviceSize getCondOffset (void) const 176 { 177 return m_condOffset; 178 } 179 180 VkBuffer getBuffer (void) const 181 { 182 return m_buffer.get(); 183 } 184 185 // Cannot copy or assign this. 186 ConditionBuffer (const ConditionBuffer&) = delete; 187 ConditionBuffer& operator=(const ConditionBuffer&) = delete; 188 189protected: 190 Move<VkBuffer> m_buffer; 191 de::MovePtr<Allocation> m_allocation; 192 VkDeviceSize m_condOffset; 193}; 194 195class ConditionalRenderingInstance : public vkt::TestInstance 196{ 197public: 198 ConditionalRenderingInstance (Context& context, const TestParams& params) 199 : vkt::TestInstance (context) 200 , m_params (params) 201 , m_conditionBuffer () 202 , m_indirectDrawArgsBuffer () 203 , m_indirectDrawCountBuffer () 204 {} 205 virtual ~ConditionalRenderingInstance (void) {} 206 207 tcu::TestStatus iterate (void) override; 208 209protected: 210 // Creates the indirect buffers that are needed according to the test parameters. 211 void initIndirectBuffers (const DeviceInterface& vkd, const VkDevice device, Allocator& alloc); 212 213 // Calls the appropriate drawing command depending on the test parameters. 214 void drawMeshTasks (const DeviceInterface& vkd, const VkCommandBuffer cmdBuffer) const; 215 216 const TestParams m_params; 217 std::unique_ptr<ConditionBuffer> m_conditionBuffer; 218 std::unique_ptr<BufferWithMemory> m_indirectDrawArgsBuffer; 219 std::unique_ptr<BufferWithMemory> m_indirectDrawCountBuffer; 220}; 221 222// Makes an indirect buffer with the specified contents. 223template<class T> 224std::unique_ptr<BufferWithMemory> makeIndirectBuffer (const DeviceInterface& vkd, const VkDevice device, Allocator& alloc, const T& data) 225{ 226 const auto bufferSize = static_cast<VkDeviceSize>(sizeof(data)); 227 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); 228 229 std::unique_ptr<BufferWithMemory> buffer (new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)); 230 231 auto& allocation = buffer->getAllocation(); 232 void* dataPtr = allocation.getHostPtr(); 233 234 deMemcpy(dataPtr, &data, sizeof(data)); 235 flushAlloc(vkd, device, allocation); 236 237 return buffer; 238} 239 240void ConditionalRenderingInstance::initIndirectBuffers (const DeviceInterface& vkd, const VkDevice device, Allocator& alloc) 241{ 242 if (m_params.drawType != DrawType::DRAW) 243 { 244 const VkDrawMeshTasksIndirectCommandEXT drawArgs = { 1u, 1u, 1u }; 245 m_indirectDrawArgsBuffer = makeIndirectBuffer(vkd, device, alloc, drawArgs); 246 } 247 248 if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT) 249 { 250 const uint32_t drawCount = 1u; 251 m_indirectDrawCountBuffer = makeIndirectBuffer(vkd, device, alloc, drawCount); 252 } 253} 254 255void ConditionalRenderingInstance::drawMeshTasks (const DeviceInterface& vkd, const VkCommandBuffer cmdBuffer) const 256{ 257 const auto stride = static_cast<uint32_t>(sizeof(VkDrawMeshTasksIndirectCommandEXT)); 258 259 if (m_params.drawType == DrawType::DRAW) 260 { 261 vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u); 262 } 263 else if (m_params.drawType == DrawType::DRAW_INDIRECT) 264 { 265 vkd.cmdDrawMeshTasksIndirectEXT(cmdBuffer, m_indirectDrawArgsBuffer->get(), 0ull, 1u, stride); 266 } 267 else if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT) 268 { 269 vkd.cmdDrawMeshTasksIndirectCountEXT(cmdBuffer, m_indirectDrawArgsBuffer->get(), 0ull, m_indirectDrawCountBuffer->get(), 0ull, 1u, stride); 270 } 271 else 272 DE_ASSERT(false); 273} 274 275void ConditionalRenderingCase::initPrograms (vk::SourceCollections& programCollection) const 276{ 277 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion); 278 279 if (m_params.useTask) 280 { 281 std::ostringstream task; 282 task 283 << "#version 460\n" 284 << "#extension GL_EXT_mesh_shader : enable\n" 285 << "\n" 286 << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n" 287 << "\n" 288 << "void main (void) {\n" 289 << " EmitMeshTasksEXT(1u, 1u, 1u);\n" 290 << "}\n" 291 ; 292 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions; 293 } 294 295 std::ostringstream mesh; 296 mesh 297 << "#version 460\n" 298 << "#extension GL_EXT_mesh_shader : enable\n" 299 << "\n" 300 << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n" 301 << "layout (triangles) out;\n" 302 << "layout (max_vertices=3, max_primitives=1) out;\n" 303 << "\n" 304 << "void main (void) {\n" 305 << " SetMeshOutputsEXT(3u, 1u);\n" 306 << "\n" 307 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0u, 1u, 2u);\n" 308 << "\n" 309 << " gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" 310 << " gl_MeshVerticesEXT[1].gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n" 311 << " gl_MeshVerticesEXT[2].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n" 312 << "}\n" 313 ; 314 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions; 315 316 const auto outColor = getOutputColor(); 317 std::ostringstream frag; 318 frag 319 << "#version 460\n" 320 << "\n" 321 << "layout (location=0) out vec4 outColor;\n" 322 << "\n" 323 << "void main (void) {\n" 324 << " outColor = vec4" << outColor << ";\n" 325 << "}\n" 326 ; 327 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); 328} 329 330TestInstance* ConditionalRenderingCase::createInstance (Context& context) const 331{ 332 return new ConditionalRenderingInstance(context, m_params); 333} 334 335void ConditionalRenderingCase::checkSupport (Context& context) const 336{ 337 checkTaskMeshShaderSupportEXT(context, m_params.useTask/*requireTask*/, true/*requireMesh*/); 338 339 context.requireDeviceFunctionality("VK_EXT_conditional_rendering"); 340 341 if (m_params.drawType == DrawType::DRAW_INDIRECT_WITH_COUNT) 342 context.requireDeviceFunctionality("VK_KHR_draw_indirect_count"); 343 344 if (m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE) 345 { 346 const auto& condRenderingFeatures = context.getConditionalRenderingFeaturesEXT(); 347 if (!condRenderingFeatures.inheritedConditionalRendering) 348 TCU_THROW(NotSupportedError, "inheritedConditionalRendering not supported"); 349 } 350} 351 352tcu::TestStatus ConditionalRenderingInstance::iterate () 353{ 354 const auto& vkd = m_context.getDeviceInterface(); 355 const auto device = m_context.getDevice(); 356 auto& alloc = m_context.getDefaultAllocator(); 357 const auto queueIndex = m_context.getUniversalQueueFamilyIndex(); 358 const auto queue = m_context.getUniversalQueue(); 359 360 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM; 361 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); 362 const auto tcuFormat = mapVkFormat(colorFormat); 363 const auto colorExtent = makeExtent3D(4u, 4u, 1u); 364 const tcu::IVec3 iExtent3D (static_cast<int>(colorExtent.width), static_cast<int>(colorExtent.height), static_cast<int>(colorExtent.depth)); 365 const auto clearColor = getClearColor(); 366 const auto drawColor = getOutputColor(); 367 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 368 const auto needsSecCmd = m_params.needsSecondaryCmdBuffer(); 369 370 // Create color attachment. 371 const VkImageCreateInfo colorAttCreateInfo = 372 { 373 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 374 nullptr, // const void* pNext; 375 0u, // VkImageCreateFlags flags; 376 VK_IMAGE_TYPE_2D, // VkImageType imageType; 377 colorFormat, // VkFormat format; 378 colorExtent, // VkExtent3D extent; 379 1u, // uint32_t mipLevels; 380 1u, // uint32_t arrayLayers; 381 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 382 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 383 colorUsage, // VkImageUsageFlags usage; 384 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 385 0u, // uint32_t queueFamilyIndexCount; 386 nullptr, // const uint32_t* pQueueFamilyIndices; 387 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 388 }; 389 ImageWithMemory colorAtt (vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any); 390 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 391 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u); 392 const auto colorAttView = makeImageView(vkd, device, colorAtt.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR); 393 394 // Render pass and framebuffer. 395 const auto renderPass = makeRenderPass(vkd, device, colorFormat); 396 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorAttView.get(), colorExtent.width, colorExtent.height); 397 398 // Verification buffer. 399 const auto verifBufferSize = static_cast<VkDeviceSize>(tcu::getPixelSize(tcuFormat) * iExtent3D.x() * iExtent3D.y() * iExtent3D.z()); 400 const auto verifBufferCreateInfo = makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); 401 BufferWithMemory verifBuffer (vkd, device, alloc, verifBufferCreateInfo, MemoryRequirement::HostVisible); 402 auto& verifBufferAlloc = verifBuffer.getAllocation(); 403 void* verifBufferData = verifBufferAlloc.getHostPtr(); 404 405 // Create the condition buffer. 406 m_conditionBuffer.reset(new ConditionBuffer(vkd, device, alloc, m_params.condValue, m_params.bindWithOffset, m_params.condWithOffset)); 407 408 // Create the indirect buffers if needed. 409 initIndirectBuffers(vkd, device, alloc); 410 411 // Pipeline. 412 const auto pipelineLayout = makePipelineLayout(vkd, device); 413 const auto& binaries = m_context.getBinaryCollection(); 414 const auto taskModule = (binaries.contains("task") ? createShaderModule(vkd, device, binaries.get("task")) : Move<VkShaderModule>()); 415 const auto meshModule = createShaderModule(vkd, device, binaries.get("mesh")); 416 const auto fragModule = createShaderModule(vkd, device, binaries.get("frag")); 417 418 const std::vector<VkViewport> viewports (1u, makeViewport(colorExtent)); 419 const std::vector<VkRect2D> scissors (1u, makeRect2D(colorExtent)); 420 421 const auto pipeline = makeGraphicsPipeline( 422 vkd, device, pipelineLayout.get(), 423 taskModule.get(), meshModule.get(), fragModule.get(), 424 renderPass.get(), viewports, scissors); 425 426 // Command pool and command buffers. 427 const auto cmdPool = makeCommandPool(vkd, device, queueIndex); 428 const auto primaryCmdBuffer = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); 429 const auto secondaryCmdBuffer = (needsSecCmd ? allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY) : Move<VkCommandBuffer>()); 430 const auto primary = primaryCmdBuffer.get(); 431 const auto secondary = secondaryCmdBuffer.get(); 432 433 // Common conditional rendering begin info. 434 const auto conditionalRenderingFlags = (m_params.inverted 435 ? VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT 436 : static_cast<VkConditionalRenderingFlagBitsEXT>(0)); 437 const VkConditionalRenderingBeginInfoEXT conditionalRenderingBegin = 438 { 439 VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT, // VkStructureType sType; 440 nullptr, // const void* pNext; 441 m_conditionBuffer->getBuffer(), // VkBuffer buffer; 442 m_conditionBuffer->getCondOffset(), // VkDeviceSize offset; 443 conditionalRenderingFlags, // VkConditionalRenderingFlagsEXT flags; 444 }; 445 446 // Inheritance info for the secondary command buffer. 447 const auto conditionalRenderingEnable = ((m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE) 448 ? VK_TRUE 449 : VK_FALSE); 450 const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo = 451 { 452 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT, // VkStructureType sType; 453 nullptr, // const void* pNext; 454 conditionalRenderingEnable, // VkBool32 conditionalRenderingEnable; 455 }; 456 457 const VkCommandBufferInheritanceInfo inheritanceInfo = 458 { 459 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType; 460 &conditionalRenderingInheritanceInfo, // const void* pNext; 461 renderPass.get(), // VkRenderPass renderPass; 462 0u, // uint32_t subpass; 463 framebuffer.get(), // VkFramebuffer framebuffer; 464 VK_FALSE, // VkBool32 occlusionQueryEnable; 465 0u, // VkQueryControlFlags queryFlags; 466 0u, // VkQueryPipelineStatisticFlags pipelineStatistics; 467 }; 468 469 const VkCommandBufferUsageFlags cmdBufferUsageFlags = (VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT); 470 const VkCommandBufferBeginInfo secondaryBeginInfo = 471 { 472 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; 473 nullptr, // const void* pNext; 474 cmdBufferUsageFlags, // VkCommandBufferUsageFlags flags; 475 &inheritanceInfo, // const VkCommandBufferInheritanceInfo* pInheritanceInfo; 476 }; 477 478 beginCommandBuffer(vkd, primary); 479 480 if (m_params.cmdBufferType == CmdBufferType::PRIMARY) 481 { 482 // Do everything in the primary command buffer. 483 const auto cmdBuffer = primary; 484 485 vkd.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBegin); 486 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor); 487 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get()); 488 drawMeshTasks(vkd, cmdBuffer); 489 endRenderPass(vkd, cmdBuffer); 490 vkd.cmdEndConditionalRenderingEXT(cmdBuffer); 491 } 492 else if (m_params.cmdBufferType == CmdBufferType::SECONDARY) 493 { 494 // Do everything in the secondary command buffer. 495 // In addition, do the conditional rendering inside the render pass so it's a bit different from the primary case. 496 beginRenderPass(vkd, primary, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); 497 498 const auto cmdBuffer = secondaryCmdBuffer.get(); 499 500 vkd.beginCommandBuffer(secondary, &secondaryBeginInfo); 501 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get()); 502 vkd.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBegin); 503 drawMeshTasks(vkd, cmdBuffer); 504 vkd.cmdEndConditionalRenderingEXT(cmdBuffer); 505 endCommandBuffer(vkd, cmdBuffer); 506 507 vkd.cmdExecuteCommands(primary, 1u, &cmdBuffer); 508 endRenderPass(vkd, primary); 509 } 510 else if (m_params.cmdBufferType == CmdBufferType::SECONDARY_WITH_INHERITANCE) 511 { 512 // Inherit everything in the secondary command buffer. 513 vkd.beginCommandBuffer(secondary, &secondaryBeginInfo); 514 vkd.cmdBindPipeline(secondary, bindPoint, pipeline.get()); 515 drawMeshTasks(vkd, secondary); 516 endCommandBuffer(vkd, secondary); 517 518 vkd.cmdBeginConditionalRenderingEXT(primary, &conditionalRenderingBegin); 519 beginRenderPass(vkd, primary, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); 520 vkd.cmdExecuteCommands(primary, 1u, &secondary); 521 endRenderPass(vkd, primary); 522 vkd.cmdEndConditionalRenderingEXT(primary); 523 } 524 else 525 DE_ASSERT(false); 526 527 // Transfer color attachment to the verification buffer. 528 const auto postTransferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); 529 const auto copyRegion = makeBufferImageCopy(colorExtent, colorSRL); 530 const auto preTranferBarrier = makeImageMemoryBarrier( 531 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, 532 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 533 colorAtt.get(), colorSRR); 534 535 cmdPipelineImageMemoryBarrier(vkd, primary, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preTranferBarrier); 536 vkd.cmdCopyImageToBuffer(primary, colorAtt.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u, ©Region); 537 cmdPipelineMemoryBarrier(vkd, primary, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postTransferBarrier); 538 539 endCommandBuffer(vkd, primary); 540 submitCommandsAndWait(vkd, device, queue, primary); 541 542 invalidateAlloc(vkd, device, verifBufferAlloc); 543 544 const tcu::ConstPixelBufferAccess resultAccess (tcuFormat, iExtent3D, verifBufferData); 545 const bool expectDraw = ((m_params.condValue != 0u) != m_params.inverted); 546 const auto expectedColor = (expectDraw ? drawColor : clearColor); 547 const tcu::Vec4 threshold (0.0f, 0.0f, 0.0f, 0.0f); 548 549 auto& log = m_context.getTestContext().getLog(); 550 if (!tcu::floatThresholdCompare(log, "Result", "", expectedColor, resultAccess, threshold, tcu::COMPARE_LOG_ON_ERROR)) 551 TCU_FAIL("Check log for details"); 552 553 return tcu::TestStatus::pass("Pass"); 554} 555 556} // anonymous 557 558tcu::TestCaseGroup* createMeshShaderConditionalRenderingTestsEXT (tcu::TestContext& testCtx) 559{ 560 GroupPtr mainGroup (new tcu::TestCaseGroup(testCtx, "conditional_rendering")); 561 562 const struct 563 { 564 DrawType drawType; 565 const char* name; 566 } drawTypeCases[] = 567 { 568 { DrawType::DRAW, "draw" }, 569 { DrawType::DRAW_INDIRECT, "draw_indirect" }, 570 { DrawType::DRAW_INDIRECT_WITH_COUNT, "draw_indirect_count" }, 571 }; 572 573 const struct 574 { 575 CmdBufferType cmdBufferType; 576 const char* name; 577 } cmdBufferTypeCases[] = 578 { 579 { CmdBufferType::PRIMARY, "primary_cmd_buffer" }, 580 { CmdBufferType::SECONDARY, "secondary_cmd_buffer" }, 581 { CmdBufferType::SECONDARY_WITH_INHERITANCE, "secondary_cmd_buffer_inheritance" }, 582 }; 583 584 const struct 585 { 586 bool bindWithOffset; 587 const char* name; 588 } bindWithOffsetCases[] = 589 { 590 { false, "bind_without_offset" }, 591 { true, "bind_with_offset" }, 592 }; 593 594 const struct 595 { 596 bool condWithOffset; 597 const char* name; 598 } condWithOffsetCases[] = 599 { 600 { false, "cond_without_offset" }, 601 { true, "cond_with_offset" }, 602 }; 603 604 const struct 605 { 606 bool inverted; 607 const char* name; 608 } inversionCases[] = 609 { 610 { false, "normal_cond" }, 611 { true, "inverted_cond" }, 612 }; 613 614 const struct 615 { 616 bool useTask; 617 const char* name; 618 } useTaskCases[] = 619 { 620 { false, "mesh_only" }, 621 { true, "mesh_and_task" }, 622 }; 623 624 const auto condValues = getCondValues(); 625 626 for (const auto& drawTypeCase : drawTypeCases) 627 { 628 GroupPtr drawTypeGroup (new tcu::TestCaseGroup(testCtx, drawTypeCase.name)); 629 630 for (const auto& cmdBufferTypeCase : cmdBufferTypeCases) 631 { 632 GroupPtr cmdBufferTypeGroup (new tcu::TestCaseGroup(testCtx, cmdBufferTypeCase.name)); 633 634 for (const auto& bindWithOffsetCase : bindWithOffsetCases) 635 { 636 GroupPtr bindWithOffsetGroup (new tcu::TestCaseGroup(testCtx, bindWithOffsetCase.name)); 637 638 for (const auto& condWithOffsetCase : condWithOffsetCases) 639 { 640 GroupPtr condWithOffsetGroup (new tcu::TestCaseGroup(testCtx, condWithOffsetCase.name)); 641 642 for (const auto& inversionCase : inversionCases) 643 { 644 GroupPtr inversionGroup (new tcu::TestCaseGroup(testCtx, inversionCase.name)); 645 646 for (const auto& useTaskCase : useTaskCases) 647 { 648 GroupPtr useTaskGroup (new tcu::TestCaseGroup(testCtx, useTaskCase.name)); 649 650 for (const auto& condValue : condValues) 651 { 652 const auto testName = "value_" + paddedHex(condValue); 653 const TestParams params = 654 { 655 drawTypeCase.drawType, // DrawType drawType; 656 cmdBufferTypeCase.cmdBufferType, // CmdBufferType cmdBufferType; 657 bindWithOffsetCase.bindWithOffset, // bool bindWithOffset; 658 condWithOffsetCase.condWithOffset, // bool condWithOffset; 659 condValue, // uint32_t condValue; 660 inversionCase.inverted, // bool inverted; 661 useTaskCase.useTask, // bool useTask; 662 }; 663 useTaskGroup->addChild(new ConditionalRenderingCase(testCtx, testName, params)); 664 } 665 666 inversionGroup->addChild(useTaskGroup.release()); 667 } 668 669 condWithOffsetGroup->addChild(inversionGroup.release()); 670 } 671 672 bindWithOffsetGroup->addChild(condWithOffsetGroup.release()); 673 } 674 675 cmdBufferTypeGroup->addChild(bindWithOffsetGroup.release()); 676 } 677 678 drawTypeGroup->addChild(cmdBufferTypeGroup.release()); 679 } 680 681 mainGroup->addChild(drawTypeGroup.release()); 682 } 683 684 return mainGroup.release(); 685} 686 687} // MeshShader 688} // vkt 689