From e642e9dc3a1292b0fcb1abfc28f4df065e7df6c0 Mon Sep 17 00:00:00 2001 From: mklefrancois Date: Mon, 7 Jun 2021 14:02:45 +0200 Subject: [PATCH] Using Vulkan C API --- .clang-format | 8 +- common/obj_loader.cpp | 14 +- common/obj_loader.h | 2 +- docs/setup.md.html | 2 +- docs/vkrt_tuto_indirect_scissor.md.html | 446 +++---- docs/vkrt_tutorial.css | 2 +- docs/vkrt_tutorial.md.html | 635 +++++----- ray_tracing__advance/CMakeLists.txt | 7 +- ray_tracing__advance/hello_vulkan.cpp | 284 +++-- ray_tracing__advance/hello_vulkan.h | 28 +- ray_tracing__advance/main.cpp | 106 +- ray_tracing__advance/offscreen.cpp | 133 +-- ray_tracing__advance/offscreen.hpp | 44 +- ray_tracing__advance/raytrace.cpp | 420 +++---- ray_tracing__advance/raytrace.hpp | 56 +- ray_tracing__before/hello_vulkan.cpp | 357 +++--- ray_tracing__before/hello_vulkan.h | 47 +- ray_tracing__before/main.cpp | 70 +- ray_tracing__simple/CMakeLists.txt | 3 +- ray_tracing__simple/hello_vulkan.cpp | 707 ++++++----- ray_tracing__simple/hello_vulkan.h | 76 +- ray_tracing__simple/main.cpp | 87 +- ray_tracing_animation/CMakeLists.txt | 2 +- ray_tracing_animation/README.md | 102 +- ray_tracing_animation/hello_vulkan.cpp | 759 ++++++------ ray_tracing_animation/hello_vulkan.h | 84 +- ray_tracing_animation/main.cpp | 82 +- ray_tracing_anyhit/CMakeLists.txt | 2 +- ray_tracing_anyhit/README.md | 108 +- ray_tracing_anyhit/hello_vulkan.cpp | 781 ++++++------ ray_tracing_anyhit/hello_vulkan.h | 74 +- ray_tracing_anyhit/main.cpp | 86 +- ray_tracing_ao/README.md | 115 +- ray_tracing_ao/hello_vulkan.cpp | 594 +++++----- ray_tracing_ao/hello_vulkan.h | 71 +- ray_tracing_ao/main.cpp | 92 +- ray_tracing_callable/CMakeLists.txt | 2 +- ray_tracing_callable/README.md | 114 +- ray_tracing_callable/hello_vulkan.cpp | 729 ++++++------ ray_tracing_callable/hello_vulkan.h | 72 +- ray_tracing_callable/main.cpp | 93 +- ray_tracing_gltf/CMakeLists.txt | 2 +- ray_tracing_gltf/README.md | 92 +- ray_tracing_gltf/hello_vulkan.cpp | 665 ++++++----- ray_tracing_gltf/hello_vulkan.h | 70 +- ray_tracing_gltf/main.cpp | 91 +- ray_tracing_indirect_scissor/CMakeLists.txt | 2 +- ray_tracing_indirect_scissor/hello_vulkan.cpp | 1043 ++++++++--------- ray_tracing_indirect_scissor/hello_vulkan.h | 85 +- ray_tracing_indirect_scissor/main.cpp | 88 +- ray_tracing_instances/CMakeLists.txt | 2 +- ray_tracing_instances/hello_vulkan.cpp | 676 +++++------ ray_tracing_instances/hello_vulkan.h | 77 +- ray_tracing_instances/main.cpp | 103 +- ray_tracing_intersection/CMakeLists.txt | 2 +- ray_tracing_intersection/README.md | 176 ++- ray_tracing_intersection/hello_vulkan.cpp | 819 +++++++------ ray_tracing_intersection/hello_vulkan.h | 76 +- ray_tracing_intersection/main.cpp | 86 +- ray_tracing_jitter_cam/CMakeLists.txt | 2 +- ray_tracing_jitter_cam/hello_vulkan.cpp | 748 ++++++------ ray_tracing_jitter_cam/hello_vulkan.h | 78 +- ray_tracing_jitter_cam/main.cpp | 91 +- ray_tracing_manyhits/CMakeLists.txt | 4 +- ray_tracing_manyhits/README.md | 76 +- ray_tracing_manyhits/hello_vulkan.cpp | 743 ++++++------ ray_tracing_manyhits/hello_vulkan.h | 73 +- ray_tracing_manyhits/main.cpp | 99 +- ray_tracing_rayquery/CMakeLists.txt | 2 +- ray_tracing_rayquery/README.md | 24 +- ray_tracing_rayquery/hello_vulkan.cpp | 473 ++++---- ray_tracing_rayquery/hello_vulkan.h | 54 +- ray_tracing_rayquery/main.cpp | 196 ++-- ray_tracing_reflections/CMakeLists.txt | 4 +- ray_tracing_reflections/README.md | 5 +- ray_tracing_reflections/hello_vulkan.cpp | 740 ++++++------ ray_tracing_reflections/hello_vulkan.h | 72 +- ray_tracing_reflections/main.cpp | 94 +- ray_tracing_specialization/CMakeLists.txt | 3 +- ray_tracing_specialization/README.md | 88 +- ray_tracing_specialization/hello_vulkan.cpp | 696 ++++++----- ray_tracing_specialization/hello_vulkan.h | 73 +- ray_tracing_specialization/main.cpp | 89 +- 83 files changed, 8015 insertions(+), 8163 deletions(-) diff --git a/.clang-format b/.clang-format index 4ba3b60..cf274b6 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,4 @@ -BasedOnStyle: LLVM +BasedOnStyle: LLVM AccessModifierOffset: '-2' AlignAfterOpenBracket: Align AlignConsecutiveAssignments: 'true' @@ -21,7 +21,7 @@ BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BreakBeforeTernaryOperators: 'false' BreakConstructorInitializersBeforeComma: 'true' -ColumnLimit: '100' +ColumnLimit: '120' ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' Cpp11BracedListStyle: 'true' IndentCaseLabels: 'true' @@ -44,7 +44,7 @@ SpacesInSquareBrackets: 'false' Standard: Cpp11 TabWidth: '2' UseTab: Never -SortIncludes: 'true' +SortIncludes: 'false' ReflowComments: 'false' BraceWrapping: { AfterClass: 'true' @@ -58,7 +58,7 @@ BraceWrapping: { BeforeElse: 'true' IndentBraces: 'false' } -PenaltyExcessCharacter: 9999 +PenaltyExcessCharacter: 1 PenaltyBreakBeforeFirstCallParameter: 40 PenaltyBreakFirstLessLess: 1 PenaltyBreakComment: 30 diff --git a/common/obj_loader.cpp b/common/obj_loader.cpp index cf4ae85..d0fe0e4 100644 --- a/common/obj_loader.cpp +++ b/common/obj_loader.cpp @@ -38,12 +38,11 @@ void ObjLoader::loadModel(const std::string& filename) for(const auto& material : reader.GetMaterials()) { MaterialObj m; - m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]); - m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]); - m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]); - m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]); - m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1], - material.transmittance[2]); + m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]); + m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]); + m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]); + m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]); + m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1], material.transmittance[2]); m.dissolve = material.dissolve; m.ior = material.ior; m.shininess = material.shininess; @@ -67,8 +66,7 @@ void ObjLoader::loadModel(const std::string& filename) { m_vertices.reserve(shape.mesh.indices.size() + m_vertices.size()); m_indices.reserve(shape.mesh.indices.size() + m_indices.size()); - m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(), - shape.mesh.material_ids.end()); + m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(), shape.mesh.material_ids.end()); for(const auto& index : shape.mesh.indices) { diff --git a/common/obj_loader.h b/common/obj_loader.h index 15031ee..2f9591d 100644 --- a/common/obj_loader.h +++ b/common/obj_loader.h @@ -36,7 +36,7 @@ struct MaterialObj float shininess = 0.f; float ior = 1.0f; // index of refraction float dissolve = 1.f; // 1 == opaque; 0 == fully transparent - // illumination model (see http://www.fileformat.info/format/material/) + // illumination model (see http://www.fileformat.info/format/material/) int illum = 0; int textureID = -1; }; diff --git a/docs/setup.md.html b/docs/setup.md.html index 2edb65f..0c2167a 100644 --- a/docs/setup.md.html +++ b/docs/setup.md.html @@ -43,7 +43,7 @@ The directory structure should be looking like: ********************************************************** -!!! Warning +!!! Warning CMake **Run CMake** in vk_raytracing_tutorial_KHR. !!! Warning Beta Vulkan SDK diff --git a/docs/vkrt_tuto_indirect_scissor.md.html b/docs/vkrt_tuto_indirect_scissor.md.html index b649eaf..794a514 100644 --- a/docs/vkrt_tuto_indirect_scissor.md.html +++ b/docs/vkrt_tuto_indirect_scissor.md.html @@ -202,18 +202,18 @@ void HelloVulkan::createLanternIndirectBuffer() // m_alloc behind the scenes uses cmdBuf to transfer data to the buffer. nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - using Usage = vk::BufferUsageFlagBits; - m_lanternIndirectBuffer = - m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount, - Usage::eIndirectBuffer | Usage::eTransferDst - | Usage::eShaderDeviceAddress | Usage::eStorageBuffer, - vk::MemoryPropertyFlagBits::eDeviceLocal); + using Usage = VkBufferUsageFlagBits; + m_lanternIndirectBuffer = m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); std::vector entries(m_lanternCount); - for (size_t i = 0; i < m_lanternCount; ++i) entries[i].lantern = m_lanterns[i]; - cmdBuf.updateBuffer(m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data()); + for(size_t i = 0; i < m_lanternCount; ++i) + entries[i].lantern = m_lanterns[i]; + vkCmdUpdateBuffer(cmdBuf, m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data()); cmdBufGet.submitAndWait(cmdBuf); } @@ -370,12 +370,12 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes. `hello_vulkan.h`: ```` C - nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind; - vk::DescriptorPool m_lanternIndirectDescPool; - vk::DescriptorSetLayout m_lanternIndirectDescSetLayout; - vk::DescriptorSet m_lanternIndirectDescSet; - vk::PipelineLayout m_lanternIndirectCompPipelineLayout; - vk::Pipeline m_lanternIndirectCompPipeline; +nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind; +VkDescriptorPool m_lanternIndirectDescPool; +VkDescriptorSetLayout m_lanternIndirectDescSetLayout; +VkDescriptorSet m_lanternIndirectDescSet; +VkPipelineLayout m_lanternIndirectCompPipelineLayout; +VkPipeline m_lanternIndirectCompPipeline; ```` `hello_vulkan.cpp`: @@ -385,26 +385,25 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes. // The compute shader just needs read/write access to the buffer of LanternIndirectEntry. void HelloVulkan::createLanternIndirectDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - // Lantern buffer (binding = 0) - m_lanternIndirectDescSetLayoutBind.addBinding( // - vkDSLB(0, vkDT::eStorageBuffer, 1, vkSS::eCompute)); + m_lanternIndirectDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device); m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device); - m_lanternIndirectDescSet = - m_device.allocateDescriptorSets({m_lanternIndirectDescPool, 1, &m_lanternIndirectDescSetLayout})[0]; + + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_lanternIndirectDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_lanternIndirectDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_lanternIndirectDescSet); + assert(m_lanternIndirectBuffer.buffer); - vk::DescriptorBufferInfo lanternBufferInfo{ - m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)}; + VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)}; - std::vector writes; + std::vector writes; writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, &lanternBufferInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } // Create compute pipeline used to fill m_lanternIndirectBuffer with parameters @@ -412,32 +411,31 @@ void HelloVulkan::createLanternIndirectDescriptorSet() void HelloVulkan::createLanternIndirectCompPipeline() { // Compile compute shader and package as stage. - vk::ShaderModule computeShader = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/lanternIndirect.comp.spv", true, defaultSearchPaths, true)); - vk::PipelineShaderStageCreateInfo stageInfo; - stageInfo.setStage(vk::ShaderStageFlagBits::eCompute); - stageInfo.setModule(computeShader); - stageInfo.setPName("main"); + VkShaderModule computeShader = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true)); + VkPipelineShaderStageCreateInfo stageInfo{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stageInfo.module = computeShader; + stageInfo.pName = "main"; // Set up push constant and pipeline layout. - constexpr auto pushSize = static_cast(sizeof(m_lanternIndirectPushConstants)); - vk::PushConstantRange pushCRange = {vk::ShaderStageFlagBits::eCompute, 0, pushSize}; + constexpr auto pushSize = static_cast(sizeof(m_lanternIndirectPushConstants)); + VkPushConstantRange pushCRange = {VK_SHADER_STAGE_COMPUTE_BIT, 0, pushSize}; static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant"); - vk::PipelineLayoutCreateInfo layoutInfo; - layoutInfo.setSetLayoutCount(1); - layoutInfo.setPSetLayouts(&m_lanternIndirectDescSetLayout); - layoutInfo.setPushConstantRangeCount(1); - layoutInfo.setPPushConstantRanges(&pushCRange); - m_lanternIndirectCompPipelineLayout = m_device.createPipelineLayout(layoutInfo); + VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + layoutInfo.setLayoutCount = 1; + layoutInfo.pSetLayouts = &m_lanternIndirectDescSetLayout; + layoutInfo.pushConstantRangeCount = 1; + layoutInfo.pPushConstantRanges = &pushCRange; + vkCreatePipelineLayout(m_device, &layoutInfo, nullptr, &m_lanternIndirectCompPipelineLayout); // Create compute pipeline. - vk::ComputePipelineCreateInfo pipelineInfo; - pipelineInfo.setStage(stageInfo); - pipelineInfo.setLayout(m_lanternIndirectCompPipelineLayout); - m_lanternIndirectCompPipeline = static_cast(m_device.createComputePipeline({}, pipelineInfo)); + VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + pipelineInfo.stage = stageInfo; + pipelineInfo.layout = m_lanternIndirectCompPipelineLayout; + vkCreateComputePipelines(m_device, {}, 1, &pipelineInfo, nullptr, &m_lanternIndirectCompPipeline); - m_device.destroy(computeShader); + vkDestroyShaderModule(m_device, computeShader, nullptr); } ```` @@ -464,61 +462,72 @@ pipeline barrier synchronizing access to the `LanternIndirectEntry` array between the compute shader and indirect draw stages. ```` C -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +//-------------------------------------------------------------------------------------------------- +// Ray Tracing the scene +// +// The raytracing is split into multiple passes: +// +// First pass fills in the initial values for every pixel in the output image. +// Illumination and shadow rays come from the main light. +// +// Subsequently, one lantern pass is run for each lantern in the scene. We run +// a compute shader to calculate a bounding scissor rectangle for each lantern's light +// effect. This is stored in m_lanternIndirectBuffer. Then an indirect trace rays command +// is run for every lantern within its scissor rectangle. The lanterns' light +// contribution is additively blended into the output image. +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { // Before tracing rays, we need to dispatch the compute shaders that // fill in the ray trace indirect parameters for each lantern pass. // First, barrier before, ensure writes aren't visible to previous frame. - vk::BufferMemoryBarrier bufferBarrier; - bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eIndirectCommandRead); - bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderWrite); - bufferBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - bufferBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - bufferBarrier.setBuffer(m_lanternIndirectBuffer.buffer); - bufferBarrier.offset = 0; - bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0]; - cmdBuf.pipelineBarrier( // - vk::PipelineStageFlagBits::eDrawIndirect, // - vk::PipelineStageFlagBits::eComputeShader,// - vk::DependencyFlags(0), // - {}, {bufferBarrier}, {}); + VkBufferMemoryBarrier bufferBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.buffer = m_lanternIndirectBuffer.buffer; + bufferBarrier.offset = 0; + bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0]; + vkCmdPipelineBarrier(cmdBuf, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, // + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // + VkDependencyFlags(0), // + 0, nullptr, 1, &bufferBarrier, 0, nullptr); // Bind compute shader, update push constant and descriptors, dispatch compute. - cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipeline); - nvmath::mat4 view = getViewMatrix(); - m_lanternIndirectPushConstants.viewRowX = view.row(0); - m_lanternIndirectPushConstants.viewRowY = view.row(1); - m_lanternIndirectPushConstants.viewRowZ = view.row(2); - m_lanternIndirectPushConstants.proj = getProjMatrix(); - m_lanternIndirectPushConstants.nearZ = nearZ; - m_lanternIndirectPushConstants.screenX = m_size.width; - m_lanternIndirectPushConstants.screenY = m_size.height; - m_lanternIndirectPushConstants.lanternCount = m_lanternCount; - cmdBuf.pushConstants( - m_lanternIndirectCompPipelineLayout, - vk::ShaderStageFlagBits::eCompute, - 0, m_lanternIndirectPushConstants); - cmdBuf.bindDescriptorSets( - vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipelineLayout, 0, {m_lanternIndirectDescSet}, {}); - cmdBuf.dispatch(1, 1, 1); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipeline); + nvmath::mat4 view = getViewMatrix(); + m_lanternIndirectPushConstants.viewRowX = view.row(0); + m_lanternIndirectPushConstants.viewRowY = view.row(1); + m_lanternIndirectPushConstants.viewRowZ = view.row(2); + m_lanternIndirectPushConstants.proj = getProjMatrix(); + m_lanternIndirectPushConstants.nearZ = nearZ; + m_lanternIndirectPushConstants.screenX = m_size.width; + m_lanternIndirectPushConstants.screenY = m_size.height; + m_lanternIndirectPushConstants.lanternCount = int32_t(m_lanternCount); + vkCmdPushConstants(cmdBuf, m_lanternIndirectCompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, + sizeof(LanternIndirectPushConstants), &m_lanternIndirectPushConstants); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipelineLayout, 0, 1, + &m_lanternIndirectDescSet, 0, nullptr); + vkCmdDispatch(cmdBuf, 1, 1, 1); // Ensure compute results are visible when doing indirect ray trace. - bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); - bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eIndirectCommandRead); - cmdBuf.pipelineBarrier( // - vk::PipelineStageFlagBits::eComputeShader, // - vk::PipelineStageFlagBits::eDrawIndirect, // - vk::DependencyFlags(0), // - {}, {bufferBarrier}, {}); + bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + vkCmdPipelineBarrier(cmdBuf, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, // + VkDependencyFlags(0), // + 0, nullptr, 1, &bufferBarrier, 0, nullptr); // Now move on to the actual ray tracing. m_debug.beginLabel(cmdBuf, "Ray trace"); ```` -!!! TIP `eDrawIndirect` - `vk::PipelineStageFlagBits::eDrawIndirect` (`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`) +!!! TIP `VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT` + `VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT` covers the stage that sources indirect paramaters for compute and ray trace indirect commands, not just graphics draw indirect commands. @@ -542,7 +551,7 @@ they were factored out to common code in `hello_vulkan.h`. The function for updating the uniform buffer is tweaked to match. ```` C -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { const float aspectRatio = m_size.width / static_cast(m_size.height); @@ -579,40 +588,40 @@ In order to focus on the ray tracing, I omit the code for generating those verte buffers. The relevent code in `HelloVulkan::createLanternModel` for creating the `BlasInput` is ```` C - // Package vertex and index buffers as BlasInput. - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_lanternVertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_lanternIndexBuffer.buffer}); +// Package vertex and index buffers as BlasInput. +VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternVertexBuffer.buffer); +VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternIndexBuffer.buffer); - uint32_t maxPrimitiveCount = uint32_t(indices.size() / 3); +auto maxPrimitiveCount = uint32_t(indices.size() / 3); - // Describe buffer as packed array of float vec3. - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data. - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(nvmath::vec3f)); - // Describe index data (32-bit unsigned int) - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - // Indicate identity transform by setting transformData to null device pointer. - triangles.setTransformData({}); - triangles.setMaxVertex(vertices.size()); +// Describe buffer as packed array of float vec3. +VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; +triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. +triangles.vertexData.deviceAddress = vertexAddress; +triangles.vertexStride = sizeof(nvmath::vec3f); +// Describe index data (32-bit unsigned int) +triangles.indexType = VK_INDEX_TYPE_UINT32; +triangles.indexData.deviceAddress = indexAddress; +// Indicate identity transform by setting transformData to null device pointer. +//triangles.transformData = {}; +triangles.maxVertex = uint32_t(vertices.size()); - // Identify the above data as containing opaque triangles. - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); +// Identify the above data as containing opaque triangles. +VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; +asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; +asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; +asGeom.geometry.triangles = triangles; - // The entire array will be used to build the BLAS. - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(maxPrimitiveCount); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); +// The entire array will be used to build the BLAS. +VkAccelerationStructureBuildRangeInfoKHR offset; +offset.firstVertex = 0; +offset.primitiveCount = maxPrimitiveCount; +offset.primitiveOffset = 0; +offset.transformOffset = 0; - // Our blas is made from only one geometry, but could be made of many geometries - m_lanternBlasInput.asGeometry.emplace_back(asGeom); - m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset); +// Our blas is made from only one geometry, but could be made of many geometries +m_lanternBlasInput.asGeometry.emplace_back(asGeom); +m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset); ```` The principle difference from before is that the vertex array is now a packed array of @@ -647,7 +656,7 @@ void HelloVulkan::createBottomLevelAS() m_lanternBlasId = allBlas.size(); allBlas.emplace_back(m_lanternBlasInput); - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } ```` @@ -696,7 +705,7 @@ void HelloVulkan::createTopLevelAS() tlas.emplace_back(lanternInstance); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } ```` @@ -749,25 +758,21 @@ The last task is done in `HelloVulkan::createRtDescriptorSet` // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - // ... // Lantern buffer (binding = 2) - m_rtDescSetLayoutBind.addBinding( // - vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); + m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); assert(m_lanternCount > 0); // ... - std::vector writes; + std::vector writes; // ... writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &lanternBufferInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } ```` @@ -809,34 +814,36 @@ group after the OBJ hit group, to match the `hitGroupId`s assigned earlier in th TLAS build. ```` C - // OBJ Primary Ray Hit Group - Closest Hit + AnyHit (not used) - vk::ShaderModule chitSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); +enum StageIndices +{ + // ... + eClosestHit, + eClosestHitLantern, + eShaderGroupCount +}; +// ... - // Lantern Primary Ray Hit Group - vk::ShaderModule lanternChitSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/lantern.rchit.spv", true, paths, true)); +// OBJ Primary Ray Hit Group - Closest Hit +stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); +stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; +stages[eClosestHit] = stage; - vk::RayTracingShaderGroupCreateInfoKHR lanternHg{ - vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - lanternHg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"}); - m_rtShaderGroups.push_back(lanternHg); - - // ... - - m_device.destroy(lanternChitSM); +// Lantern Primary Ray Hit Group +stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true)); +stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; +stages[eClosestHitLantern] = stage; + +// ... + +// closest hit shader +group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; +group.generalShader = VK_SHADER_UNUSED_KHR; +group.closestHitShader = eClosestHit; +m_rtShaderGroups.push_back(group); + +group.closestHitShader = eClosestHitLantern; +m_rtShaderGroups.push_back(group); ```` We don't have to modify `HelloVulkan::createRtShaderBindingTable`. Changes to the number of @@ -1102,41 +1109,53 @@ groups for primary rays. Add the following code to `HelloVulkan::createRtPipelin after loading `raytraceShadow.rmiss.spv`. ```` C - // Miss shader 2 is invoked when a shadow ray for lantern lighting misses the - // lantern. It shouldn't be invoked, but I include it just in case. - vk::ShaderModule lanternmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("shaders/lanternShadow.rmiss.spv", true, paths, true)); +// Miss shader 2 is invoked when a shadow ray for lantern lighting misses the +// lantern. It shouldn't be invoked, but I include it just in case. +stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true)); +stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; +stages[eMissLantern] = stage; ```` and add this code for loading the last 2 closest hit shaders after loading `lantern.rchit.spv`: ```` C - // OBJ Lantern Shadow Ray Hit Group - vk::ShaderModule lanternShadowObjChitSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/lanternShadowObj.rchit.spv", true, paths, true)); +// Lantern Primary Ray Hit Group +stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true)); +stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; +stages[eClosestHitLantern] = stage; + +// OBJ Lantern Shadow Ray Hit Group +stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true)); +stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; +stages[eClosestHitLanternShdObj] = stage; + +// ... + +// Lantern Shadow Miss +group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; +group.generalShader = eMissLantern; +m_rtShaderGroups.push_back(group); + + +// closest hit shader +group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; +group.generalShader = VK_SHADER_UNUSED_KHR; +group.closestHitShader = eClosestHit; +m_rtShaderGroups.push_back(group); + +group.closestHitShader = eClosestHitLantern; +m_rtShaderGroups.push_back(group); + +group.closestHitShader = eClosestHitLanternShdObj; +m_rtShaderGroups.push_back(group); + +group.closestHitShader = eClosestHitLanternShd; +m_rtShaderGroups.push_back(group); - vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{ - vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - lanternShadowObjHg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"}); - m_rtShaderGroups.push_back(lanternShadowObjHg); - // Lantern Lantern Shadow Ray Hit Group - vk::ShaderModule lanternShadowLanternChitSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/lanternShadowLantern.rchit.spv", true, paths, true)); - vk::RayTracingShaderGroupCreateInfoKHR lanternShadowLanternHg{ - vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - lanternShadowLanternHg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"}); - m_rtShaderGroups.push_back(lanternShadowLanternHg); ```` We need to destroy the added shader modules at the end of the function. @@ -1386,7 +1405,7 @@ pass. There are minimal changes from before, we just have to to account for the added shaders. ```` C - using Stride = vk::StridedDeviceAddressRegionKHR; + using Stride = VkStridedDeviceAddressRegionKHR; std::array strideAddresses{ Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss @@ -1394,10 +1413,8 @@ pass. There are minimal changes from before, we just have to Stride{0u, 0u, 0u}}; // callable // First pass, illuminate scene with global light. - cmdBuf.traceRaysKHR( - &strideAddresses[0], &strideAddresses[1], // - &strideAddresses[2], &strideAddresses[3], // - m_size.width, m_size.height, 1); + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); ```` After that, we can open a loop for performing all lantern passes. @@ -1412,25 +1429,23 @@ Because the additive blending in the shader requires read-modify-write operation we need a barrier between every pass. ```` C - // Barrier to ensure previous pass finished. - vk::Image offscreenImage{m_offscreenColor.image}; - vk::ImageSubresourceRange colorRange( - vk::ImageAspectFlagBits::eColor, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS - ); - vk::ImageMemoryBarrier imageBarrier; - imageBarrier.setOldLayout(vk::ImageLayout::eGeneral); - imageBarrier.setNewLayout(vk::ImageLayout::eGeneral); - imageBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - imageBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - imageBarrier.setImage(offscreenImage); - imageBarrier.setSubresourceRange(colorRange); - imageBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); - imageBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - cmdBuf.pipelineBarrier( - vk::PipelineStageFlagBits::eRayTracingShaderKHR, // - vk::PipelineStageFlagBits::eRayTracingShaderKHR, // - vk::DependencyFlags(0), // - {}, {}, {imageBarrier}); +// Barrier to ensure previous pass finished. +VkImage offscreenImage{m_offscreenColor.image}; +VkImageSubresourceRange colorRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}; +VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; +imageBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; +imageBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; +imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; +imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; +imageBarrier.image = offscreenImage; +imageBarrier.subresourceRange = colorRange; +imageBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; +imageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; +vkCmdPipelineBarrier(cmdBuf, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, // + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, // + VkDependencyFlags(0), // + 0, nullptr, 0, nullptr, 1, &imageBarrier); ```` Then, we can pass the number of the lantern pass being performed (`i`), and look @@ -1443,17 +1458,18 @@ is the first member of `LanternIndirectEntry`. ```` C // Set lantern pass number. m_rtPushConstants.lanternPassNumber = i; - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + + + VkDeviceAddress indirectDeviceAddress = + nvvk::getBufferDeviceAddress(m_device, m_lanternIndirectBuffer.buffer) + i * sizeof(LanternIndirectEntry); // Execute lantern pass. - cmdBuf.traceRaysIndirectKHR( - &strideAddresses[0], &strideAddresses[1], // - &strideAddresses[2], &strideAddresses[3], // - m_device.getBufferAddress({m_lanternIndirectBuffer.buffer}) + i * sizeof(LanternIndirectEntry)); + vkCmdTraceRaysIndirectKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], // + &strideAddresses[2], &strideAddresses[3], // + indirectDeviceAddress); } ```` @@ -1480,10 +1496,10 @@ void HelloVulkan::destroyResources() // #VKRay // ... - m_device.destroy(m_lanternIndirectDescPool); - m_device.destroy(m_lanternIndirectDescSetLayout); - m_device.destroy(m_lanternIndirectCompPipeline); - m_device.destroy(m_lanternIndirectCompPipelineLayout); + vkDestroyDescriptorPool(m_device, m_lanternIndirectDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_lanternIndirectDescSetLayout, nullptr); + vkDestroyPipeline(m_device, m_lanternIndirectCompPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_lanternIndirectCompPipelineLayout, nullptr); m_alloc.destroy(m_lanternIndirectBuffer); m_alloc.destroy(m_lanternVertexBuffer); m_alloc.destroy(m_lanternIndexBuffer); diff --git a/docs/vkrt_tutorial.css b/docs/vkrt_tutorial.css index 5b41cfe..52f86c9 100644 --- a/docs/vkrt_tutorial.css +++ b/docs/vkrt_tutorial.css @@ -3,7 +3,7 @@ Licensed as public domain or BSD 2-clause, whichever is more convenient for you. Originally from https://github.com/aras-p/markdeep-docs-style */ body { - max-width: 50em; + max-width: 80em; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; text-align: left; /*margin: 1.5em;*/ diff --git a/docs/vkrt_tutorial.md.html b/docs/vkrt_tutorial.md.html index 4a06a56..675e57b 100644 --- a/docs/vkrt_tutorial.md.html +++ b/docs/vkrt_tutorial.md.html @@ -68,6 +68,11 @@ cd build cmake .. ~~~~~ +!!! Note Note + If you are not using Visual Studio 2019 and up, make sure to choose x64 platform. For 2019, it is the default + but not for previous versions. + + ## Tools Installation You need a graphics card with support for the `VK_KHR_ray_tracing_pipeline` extension. @@ -75,9 +80,10 @@ For NVIDIA graphics cards, you need a [Vulkan driver](https://developer.nvidia.c released in 2021 or later. The Vulkan SDK 1.2.161 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project. +This version was tested with 1.2.176.1. !!! Tip Visual Assist - To get auto-completion, edit vulkan.hpp and change two places from:
+ To get auto-completion with Vulkan CPP, edit vulkan.hpp and change two places from:
`namespace VULKAN_HPP_NAMESPACE` to `namespace vk` # Compiling & Running @@ -109,12 +115,10 @@ extensions will need to be added. ```` C // #VKRay: Activate the ray tracing extension -vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; -contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); -vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; -contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); +VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; +contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); +VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; +contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); @@ -123,33 +127,23 @@ contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); ```` Behind the scenes, the helper is selecting a physical device supporting the required `VK_KHR_*` extensions, -then placing the `vk::PhysicalDevice*FeaturesKHR` structs on the `pNext` chain of `VkDeviceCreateInfo` before +then placing the `VkPhysicalDevice*FeaturesKHR` structs on the `pNext` chain of `VkDeviceCreateInfo` before calling `vkCreateDevice`. This enables the ray tracing features and fills in the two structs with info on the -device's ray tracing capabilities. +device's ray tracing capabilities. If you are curious, this is done in the Vulkan context creation helper: +[`Context::initInstance()`](https://github.com/nvpro-samples/nvpro_core/blob/1c59039a1ab0d777c79a29b09879a2686ec286dc/nvvk/context_vk.cpp#L211). !!! NOTE Loading function pointers As in OpenGL, when using extensions in Vulkan, you need to manually load in function pointers for extensions, using `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr`. The `nvvk::Context` class that this sample depends on magically does - this for you, for the Vulkan C API. For the Vulkan C++ API, the `nvvk::AppBase::setup` function follows the instructions - at the vulkan.hpp Github page - to load the C++ entry points: - ```` C - // Initialize function pointers - vk::DynamicLoader dl; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = - dl.getProcAddress("vkGetInstanceProcAddr"); - VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); - VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); - VULKAN_HPP_DEFAULT_DISPATCHER.init(device); - ```` + this for you, for the Vulkan C API by calling `load_VK_EXTENSION_SUBSET`. In the `HelloVulkan` class in `hello_vulkan.h`, add an initialization function and a member storing the capabilities of the GPU for ray tracing: ```` C // #VKRay -void initRayTracing(); -vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; +void initRayTracing(); +VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; ```` At the end of `hello_vulkan.cpp`, add the body of `initRayTracing()`, which will query the ray tracing capabilities @@ -167,20 +161,12 @@ needed in a later section for creating the shader binding table. void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); } ```` -!!! Tip For readers unfamiliar with vulkan.hpp - The above code is creating a `pNext` structure chain consisting of a `VkPhysicalDeviceProperties2` followed - by `VkPhysicalDeviceRayTracingPipelinePropertiesKHR`, passing it to `vkGetPhysicalDeviceProperties2`, - then extracting the filled `VkPhysicalDeviceRayTracingPipelinePropertiesKHR` structure of the chain. - `auto` is a `C++11` feature for type deduction, allowing us to avoid redundantly specifying types - (specifically, `vk::StructureChain`). - ## main In `main.cpp`, in the `main()` function, we call the initialization method right after @@ -244,12 +230,15 @@ m_rtBuilder.setup(m_device, m_alloc, m_graphicsQueueIndex); ```` !!! Note Memory Management - The raytrace helper uses `"nvvk/resourceallocator_vk.hpp"` to avoid having to deal with vulkan memory management. + The raytrace helper uses [`"nvvk/resourceallocator_vk.hpp"`](https://github.com/nvpro-samples/nvpro_core/blob/master/nvvk/resourceallocator_vk.hpp) + to avoid having to deal with vulkan memory management. This provides the `nvvk::AccelKHR` type, which consists of a `VkAccelerationStructureKHR` paired - with info needed by the allocator to manage the buffer memory backing it. `"nvvk/resourceallocator_vk.hpp"` requires a macro to - be defined before inclusion to select its memory allocation strategy. In this tutorial, we defined `NVVK_ALLOC_DEDICATED`. - This selects the simple one-`VkDeviceMemory`-per-object strategy, which is easier to understand for - teaching purposes but not practical for production use. + with info needed by the allocator to manage the buffer memory backing it. The resource allocation can use different + memory allocation strategy (memory allocator). In this tutorial, we are using our own version + [DMA](https://github.com/nvpro-samples/nvpro_core/blob/master/nvvk/memallocator_dma_vk.hpp). + Other memory allocators can be selected, such as the [Vulkan Memory Allocator (VMA)](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) + and a dedicated memory allocator, which is the simple one-`VkDeviceMemory`-per-object strategy, + which is easiest to understand for teaching purposes but not practical for production use. ## Bottom-Level Acceleration Structure @@ -264,6 +253,12 @@ class: auto objectToVkGeometryKHR(const ObjModel& model); ```` +!!! Note Note + The `objectToVkGeometryKHR()` function is returning `nvvk::RaytracingBuilderKHR::BlasInput` but we are using the C++ `auto` as it is + automatically deducted by the compiler. + + + Its implementation will fill three structures that will eventually be passed to the AS builder (`vkCmdBuildAccelerationStructuresKHR`). * `VkAccelerationStructureGeometryTrianglesDataKHR`: device pointer to the buffers holding triangle vertex/index data, @@ -275,10 +270,6 @@ Its implementation will fill three structures that will eventually be passed to * `VkAccelerationStructureBuildRangeInfoKHR`: the indices within the vertex arrays to source input geometry for the BLAS. -!!! Tip C++ types - Although the code uses C++ types, in the above C types names are used to ease searching for them online. - Generally, replace `vk::` with `Vk` to convert C++ type names to C names (functions names are less uniform). - !!! Tip VkAccelerationStructureGeometryKHR / VkAccelerationStructureBuildRangeInfoKHR split A potential point of confusion is how `VkAccelerationStructureGeometryKHR` and `VkAccelerationStructureBuildRangeInfoKHR` are ultimately passed as separate arguments to the AS builder but work in concert to determine the actual memory to source @@ -302,35 +293,38 @@ potential optimization. (More specifically, this disables calls to the anyhit sh auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { // BLAS builder requires raw device addresses. - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); uint32_t maxPrimitiveCount = model.nbIndices / 3; // Describe buffer as array of VertexObj. - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data. - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); // Describe index data (32-bit unsigned int) - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; // Indicate identity transform by setting transformData to null device pointer. - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; // Identify the above data as containing opaque triangles. - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; // The entire array will be used to build the BLAS. - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(maxPrimitiveCount); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; @@ -377,7 +371,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } ```` @@ -467,7 +461,7 @@ so we keep track of the maximum scratch memory ever needed. Later, we'll allocat } ```` -Behind the scenes, `m_alloc->createAllocation` is creating a buffer of the size indicated by the acceleration structure +Behind the scenes, `m_alloc->createAcceleration` is creating a buffer of the size indicated by the acceleration structure size query, giving it the `VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR` and `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` usage bits (the latter is needed as the TLAS builder will need the raw address of the BLASes), and binding the acceleration structure to its allocated memory by filling in the `buffer` field of `VkAccelerationStructureCreateInfoKHR`. Unlike buffers and images, @@ -674,7 +668,7 @@ invoked upon hitting the object (`VkAccelerationStructureInstanceKHR::instanceSh This index and the notion of hit group are tied to the definition of the ray tracing pipeline and the Shader Binding Table, described later in this tutorial and used to select determine which shaders are invoked at runtime. For now it suffices to say that we will use only one hit group for the whole scene, and hence the hit group index is always 0. -Finally, the instance may indicate culling preferences, such as backface culling, using its `vk::GeometryInstanceFlagsKHR +Finally, the instance may indicate culling preferences, such as backface culling, using its `VkGeometryInstanceFlagsKHR flags` member. In our example we decide to disable culling altogether for simplicity and independence on the winding of the input models. @@ -696,7 +690,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } ```` @@ -925,10 +919,10 @@ In the header `hello_vulkan.h`, we declare the objects related to this additiona ```` C void createRtDescriptorSet(); - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; ```` The acceleration structure will be accessible by the Ray Generation shader, as we want to call `TraceRayEXT()` from this @@ -942,30 +936,31 @@ RayGen shader. // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } ```` @@ -979,47 +974,44 @@ descriptor set as they semantically fit the Scene descriptor set. ```` C // Camera matrices (binding = 0) -m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); -// Materials (binding = 1) -m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); -// Scene description (binding = 2) -m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); -// Textures (binding = 3) -m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); -// Materials (binding = 4) -m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); -// Storing vertices (binding = 5) -m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); -// Storing indices (binding = 6) -m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); + // Materials (binding = 1) + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + // Scene description (binding = 2) + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + // Textures (binding = 3) + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + // Materials (binding = 4) + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + // Storing vertices (binding = 5) + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + // Storing indices (binding = 6) + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); ```` We set the actual contents of the descriptor set by adding those buffers in `updateDescriptorSet()`: ```` C - // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(size_t i = 0; i < m_objModel.size(); ++i) - { - dbiMat.push_back({m_objModel[i].matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); - dbiMatIdx.push_back({m_objModel[i].matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); - dbiVert.push_back({m_objModel[i].vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); - dbiIdx.push_back({m_objModel[i].indexBuffer.buffer, 0, VK_WHOLE_SIZE}); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data())); - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); +// All material buffers, 1 buffer per OBJ +std::vector dbiMat; +std::vector dbiMatIdx; +std::vector dbiVert; +std::vector dbiIdx; +for(auto& m : m_objModel) +{ + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); +} +writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); +writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); +writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data())); +writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); ```` Originally the buffers containing the vertices and indices were only used by the rasterization pipeline. @@ -1032,14 +1024,11 @@ and `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` bits. We update the usage of the buffers in `loadModel`: ```` C -model.vertexBuffer = -m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); -model.indexBuffer = -m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); +VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; +model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); +model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + ```` !!! Note: Array of Buffers @@ -1067,16 +1056,18 @@ The implementation is straightforward, just update the output image reference: // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } ```` +!!! Note Note + We are using [`nvvk::DescriptorSetBindings`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkdescriptorsetbindings) + to help creating the descriptor sets. This removes a lot of duplacted code and potential errors. + + We can then add the update call to the `onResize()` method to link it to the resizing event: ```` C @@ -1087,8 +1078,8 @@ The resources created in this section need to be destroyed when closing the appl `destroyResources`: ```` C - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); +vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); +vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); ```` ## main @@ -1211,23 +1202,24 @@ In the header file, let's add the definition of the ray tracing pipeline buildin pipeline: ```` C -void createRtPipeline(); -std::vector m_rtShaderGroups; -vk::PipelineLayout m_rtPipelineLayout; -vk::Pipeline m_rtPipeline; +void createRtPipeline(); + +std::vector m_rtShaderGroups; +VkPipelineLayout m_rtPipelineLayout; +VkPipeline m_rtPipeline; ```` The pipeline will also use push constants to store global uniform values, namely the background color and the light source information: ```` C - struct RtPushConstant - { - nvmath::vec4f clearColor; - nvmath::vec3f lightPosition; - float lightIntensity; - int lightType; - } m_rtPushConstants; +struct RtPushConstant +{ + nvmath::vec4f clearColor; + nvmath::vec3f lightPosition; + float lightIntensity{100.0f}; + int lightType{0}; +} m_rtPushConstants; ```` Our implementation of the ray tracing pipeline generation starts by adding the ray generation and miss shader stages, @@ -1235,13 +1227,10 @@ followed by the closest hit shader. Note that this order is arbitrary, as the ex the pipeline in any order. The "stages" terminology is a holdover from the rasterization pipeline; in raytracing, we orchestrate the order that shaders are invoked and the data flow between them ourselves. -All stages are stored in an `std::vector` of `vk::PipelineShaderStageCreateInfo` objects. As mentioned, at this step, -indices within this vector will be used as unique identifiers for the shaders. These identifiers are stored in the -`RayTracingShaderGroupCreateInfoKHR` structure. This structure first specifies a `type`, which represents the kind of -shader group represented in the structure. Ray generation and miss shaders are called 'general' shaders. In this case the -type is `eGeneral`, and only the `generalShader` member of the structure is filled. The other ones are set to -`VK_SHADER_UNUSED_KHR`. This is also the case for the callable shaders, not used in this tutorial. In our layout the ray -generation comes first (0), followed by the miss shader (1). +All stages are stored in an `std::vector` of `VkPipelineShaderStageCreateInfo` objects. As mentioned, at this step, +indices within this vector will be used as unique identifiers for the shaders. The 3 stages will be using the +same entry point "main". Then we create a `vkCreateShaderModule` from the pre-compiled shader and defined which +stage it correspond to. ```` C //-------------------------------------------------------------------------------------------------- @@ -1249,94 +1238,121 @@ generation comes first (0), followed by the miss shader (1). // void HelloVulkan::createRtPipeline() { - std::vector paths = defaultSearchPaths; + enum StageIndices + { + eRaygen, + eMiss, + eClosestHit, + eShaderGroupCount + }; - vk::ShaderModule raygenSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); - vk::ShaderModule missSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; +```` - std::vector stages; +These identifiers are stored in the +`VkRayTracingShaderGroupCreateInfoKHR` structure. This structure first specifies a `type`, which represents the kind of +shader group represented in the structure. Ray generation and miss shaders are called 'general' shaders. In this case the +type is `VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR`, and only the `generalShader` member of the structure is filled. The other ones are set to +`VK_SHADER_UNUSED_KHR`. This is also the case for the callable shaders, not used in this tutorial. In our layout the ray +generation comes first (0), followed by the miss shader (1). + + ````C + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); ```` As detailed before, intersections are managed by 3 kinds of shaders: the intersection shader computes the ray-geometry intersections, the any-hit shader is run for every potential intersection, and the closest hit shader is applied to the closest hit point along the ray. Those 3 shaders are bound into a hit group. In our case the geometry is made of -triangles, so the `type` of the `RayTracingShaderGroupCreateInfoKHR` is `eTrianglesHitGroup`. Raytrace hardware therefore takes -the place of the intersection shader, so, we set the `intersectionShader` member to `VK_SHADER_UNUSED_KHR`. We do not use an any-hit +triangles, so the `type` of the `VkRayTracingShaderGroupCreateInfoKHR` is `VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR`. +We first reset the `generalShader` to `VK_SHADER_UNUSED_KHR`. +Raytrace hardware therefore takes +the place of the intersection shader, so, we leave the `intersectionShader` member to `VK_SHADER_UNUSED_KHR`. We do not use an any-hit shader, letting the system use a built-in pass-through shader. Therefore, we also leave the `anyHitShader` to `VK_SHADER_UNUSED_KHR`. The only shader we define is then the closest hit shader, by setting the `closestHitShader` -member to the index `2` (`stages.size()-1`), since the `stages` vector already contains the ray generation and miss +member to the index `2` (`chit`), since the `stages` vector already contains the ray generation and miss shaders. ```` C - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); +// closest hit shader +group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; +group.generalShader = VK_SHADER_UNUSED_KHR; +group.closestHitShader = eClosestHit; +m_rtShaderGroups.push_back(group); ```` -Note that if the geometry were not triangles, we would have set the `type` to `eProceduralHitGroup`, and would have to +Note that if the geometry were not triangles, we would have set the `type` to `VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR`, and would have to define an intersection shader. After creating the shader groups, we need to setup the pipeline layout that will describe how the pipeline will access external data: ```` C - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; ```` We first add the push constant range to allow the ray tracing shaders to access the global uniform values: ```` C - // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); +// Push constant: we want to be able to update constants used by the shaders +VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + +VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; +pipelineLayoutCreateInfo.pushConstantRangeCount = 1; +pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; ```` As described earlier, the pipeline uses two descriptor sets: `set=0` is specific to the ray tracing pipeline (TLAS and output image), and `set=1` is shared with the rasterization (scene data): ```` C - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); +// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline +std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; +pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); +pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); ```` The pipeline layout information is now complete, allowing us to create the layout itself. ```` C - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); +vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); ```` The creation of the ray tracing pipeline is different from the classical graphics pipeline. In the graphics pipeline we @@ -1346,19 +1362,20 @@ contain an arbitrary number of stages depending on the number of active shaders We first provide all the stages that will be used: ```` C - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); +// Assemble the shader stages and recursion depth info into the ray tracing pipeline +VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; +rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders +rayPipelineInfo.pStages = stages.data(); ```` Then, we indicate how the shaders can be assembled into groups. A ray generation or miss shader is a group by itself, but hit groups can comprise up to 3 shaders (intersection, any hit, closest hit). ```` C - rayPipelineInfo.setGroupCount( - static_cast(m_rtShaderGroups.size())); - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); +// In this case, m_rtShaderGroups.size() == 3: we have one raygen group, +// one miss shader group, and one hit group. +rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); +rayPipelineInfo.pGroups = m_rtShaderGroups.data(); ```` The ray generation and closest hit shaders can trace rays, making the ray tracing a potentially recursive process. To @@ -1368,18 +1385,17 @@ recursion at all (i.e. a hit shader calling `TraceRayEXT()`). Note that it is pr as low as possible, replacing it by a loop formulation instead. ```` C - rayPipelineInfo.setMaxPipelineRayRecursionDepth(1); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = static_cast( - m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); +rayPipelineInfo.maxPipelineRayRecursionDepth = 1; // Ray depth +rayPipelineInfo.layout = m_rtPipelineLayout; + +vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); ```` Once the pipeline has been created we discard the shader modules: ```` C - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(chitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } ```` @@ -1387,8 +1403,8 @@ The pipeline layout and the pipeline itself also have to be cleaned up upon clos `destroyResources`: ```` C - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); +vkDestroyPipeline(m_device, m_rtPipeline, nullptr); +vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); ```` ## main @@ -1450,6 +1466,7 @@ In this function, we start by computing the size of the binding table from the n aligned handle size so that we can allocate the SBT buffer. ```` C +//-------------------------------------------------------------------------------------------------- // The Shader Binding Table (SBT) // - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this @@ -1457,12 +1474,10 @@ aligned handle size so that we can allocate the SBT buffer. // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = - static_cast(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier + auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit + uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = - nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; ```` @@ -1473,19 +1488,18 @@ allocate the device memory and copy the handles into the SBT. Note that SBT buff of SBT buffer, therefore the buffer need also the `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` flag. ```` C - // Fetch all the shader handles used in the pipeline. This is opaque data, + // Fetch all the shader handles used in the pipeline. This is opaque data, // so we store it in a vector of bytes. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + + assert(result == VK_SUCCESS); // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer( - sbtSize, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress - | vk::BufferUsageFlagBits::eShaderBindingTableKHR, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Map the SBT buffer and write in the handles. @@ -1499,6 +1513,7 @@ of SBT buffer, therefore the buffer need also the `VK_BUFFER_USAGE_SHADER_DEVICE m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } + ```` As with other resources, we destroy the SBT in `destroyResources`: @@ -1528,6 +1543,13 @@ As with other resources, we destroy the SBT in `destroyResources`: array used to build the pipeline. In general though, the order of the SBT need not match the pipeline shader stage order. +!!! Tip SBTWrapper + To avoid potential issues in the contruction of the SBT, we have a wrapper that uses the information + sent to the creation of the ray tracing pipeline to allocate the SBT. In further tutorials + we might use the [`nnvk::SBTWrapper`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#sbtwrapper_vkhpp) + instead of manually describing all steps. + + ## main In the `main` function, we now add the construction of the Shader Binding Table: @@ -1541,32 +1563,36 @@ In the `main` function, we now add the construction of the Shader Binding Table: Let's create a function that will record commands to call the ray trace shaders. First, add the declaration to the header ```` C -void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); +void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); ```` We first bind the pipeline and its layout, and set the push constants that will be available throughout the pipeline: ```` C +m_alloc.unmap(m_rtSBTBuffer); +m_alloc.finalizeAndReleaseStaging(); +} + //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_rtPushConstants.clearColor = clearColor; - m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; - m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; - m_rtPushConstants.lightType = m_pushConstant.lightType; +m_debug.beginLabel(cmdBuf, "Ray trace"); +// Initializing push constant values +m_rtPushConstants.clearColor = clearColor; +m_rtPushConstants.lightPosition = m_pushConstant.lightPosition; +m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; +m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + +std::vector descSets{m_rtDescSet, m_descSet}; +vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); +vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); +vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); ```` Since the structure of the Shader Binding Table is up to the developer, we need to indicate the ray tracing pipeline how @@ -1584,18 +1610,19 @@ The location for each array of the SBT is passed as a `VkStridedDeviceAddressReg * The size in bytes of the entire array ```` C - // Size of a program identifier - uint32_t groupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); +// Size of a program identifier +uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); +uint32_t groupStride = groupSize; - using Stride = vk::StridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 1}, // miss - Stride{sbtAddress + 2u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable +VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; +info.buffer = m_rtSBTBuffer.buffer; +VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + +using Stride = VkStridedDeviceAddressRegionKHR; +std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen + Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 1}, // miss + Stride{sbtAddress + 2u * groupSize, groupStride, groupSize * 1}, // hit + Stride{0u, 0u, 0u}}; // callable ```` !!! NOTE Separate Arrays @@ -1610,9 +1637,8 @@ three parameters are equivalent to the grid size of a compute launch, and repres we want to trace one ray per pixel, the grid size has the width and height of the output image, and a depth of 1. ```` C - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - &strideAddresses[3], // - m_size.width, m_size.height, 1); // + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); } @@ -1622,6 +1648,13 @@ we want to trace one ray per pixel, the grid size has the width and height of th If you built a pipeline with multiple raygen shaders, the raygen shader can be selected by changing the device address of the first `VkStridedDeviceAddressRegionKHR` structure (change the `0u` in `sbtAddress + 0u * groupSize`). +!!! TIP SBTWrapper + When using the SBTWrapper, the above could be replaced by + ``` + auto& regions = m_stbWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1); + ``` + # Let's Ray Trace Now we have everything set up to be able to trace rays: the acceleration structure, the descriptor sets, the ray tracing @@ -1647,17 +1680,17 @@ A few lines below, you can find a block containing the `helloVk.rasterize` call. render modes, we replace that block by ```` C - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuff, clearColor); - } - else - { - cmdBuff.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); - helloVk.rasterize(cmdBuff); - cmdBuff.endRenderPass(); - } +// Rendering Scene +if(useRaytracer) +{ + helloVk.raytrace(cmdBuf, clearColor); +} +else +{ + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + helloVk.rasterize(cmdBuf); + vkCmdEndRenderPass(cmdBuf); +} ```` Note that the ray tracing behaves more like a compute shader than a graphics task, and is then outside of a render pass. @@ -1701,8 +1734,7 @@ hostUBO.projInverse = nvmath::invert(hostUBO.proj); We also have to indicate that the UBO will be used in the raytracing shaders. ```` C - auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader - | vk::PipelineStageFlagBits::eRayTracingShaderKHR; +auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; ```` ## Ray generation (raytrace.rgen) @@ -2126,21 +2158,33 @@ the GLSL file. In the body of `createRtPipeline`, we need to define the new miss shader right after the previous miss shader: ```` C - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = - nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); +enum StageIndices +{ + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eShaderGroupCount +}; +```` +And create the stage + +```` C +// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found +stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); +stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; +stages[eMiss2] = stage; ```` After pushing the miss shader `missSM`, we also push the miss shader for the shadow rays: ```` C - // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); +// Shadow Miss +group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; +group.generalShader = eMiss2; +m_rtShaderGroups.push_back(group); ```` The pipeline now has to allow shooting rays from the closest hit program, which requires increasing the recursion level to 2: @@ -2150,19 +2194,14 @@ The pipeline now has to allow shooting rays from the closest hit program, which // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop // in the ray generation to avoid deep recursion. - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth ```` -At the end of the method, we destroy the shader module for the shadow miss shader: - -```` C - m_device.destroy(shadowmissSM); -```` !!! WARNING Recursion Limit The spec does not guarantee a recursion check at runtime. If you exceed either the recursion depth you reported in the raytrace pipeline create info, or the - physical device recursion limit, undefined behaviour results. + physical device recursion limit, undefined behavior results. The KHR raytracing spec lowers the minimum guaranteed recursion limit from 31 (in the original NV spec) to the much more modest limit of 1 (i.e. no @@ -2203,19 +2242,19 @@ This also points out that in real-world applications the SBT should be embedded automatically. ```` C - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the raygen and 2 miss shaders +Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Jump over the raygen and 2 miss shaders ```` ## `createRtDescriptorSet` For each resource entry in the descriptor set, we indicated which shader stage would be able to use it. Since shadow -rays will be traced from the closest hit shader, we add `vkSS::eClosestHitKHR` to the acceleration structure binding: +rays will be traced from the closest hit shader, we add `VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR` to the acceleration structure binding: ```` C // Top-level acceleration structure, usable by both the ray generation and the closest hit (to // shoot shadow rays) - m_rtDescSetLayoutBind.emplace_back( - vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS ```` ## `raytrace.rchit` diff --git a/ray_tracing__advance/CMakeLists.txt b/ray_tracing__advance/CMakeLists.txt index 6ce489c..8587db8 100644 --- a/ray_tracing__advance/CMakeLists.txt +++ b/ray_tracing__advance/CMakeLists.txt @@ -7,8 +7,8 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) -Project(${PROJNAME}) +set(PROJNAME vk_${PROJNAME}_KHR) +project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") @@ -28,11 +28,12 @@ file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) include_directories(${TUTO_KHR_DIR}/common) + #-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build compile_glsl_directory( SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" + DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" VULKAN_TARGET "vulkan1.2" ) diff --git a/ray_tracing__advance/hello_vulkan.cpp b/ray_tracing__advance/hello_vulkan.cpp index 265dbe1..cbedb4c 100644 --- a/ray_tracing__advance/hello_vulkan.cpp +++ b/ray_tracing__advance/hello_vulkan.cpp @@ -19,9 +19,7 @@ #include -#include -extern std::vector defaultSearchPaths; #define VMA_IMPLEMENTATION @@ -29,6 +27,7 @@ extern std::vector defaultSearchPaths; #include "obj_loader.h" #include "stb_image.h" + #include "hello_vulkan.h" #include "nvh/cameramanipulator.hpp" #include "nvvk/descriptorsets_vk.hpp" @@ -40,6 +39,9 @@ extern std::vector defaultSearchPaths; #include "nvvk/renderpasses_vk.hpp" +extern std::vector defaultSearchPaths; + + // Holding the camera matrices struct CameraMatrices { @@ -50,16 +52,14 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); @@ -71,46 +71,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -118,39 +118,33 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj + 1, // Adding Implicit mat too - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj + 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT + | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT + | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, - vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing implicit obj (binding = 7) - m_descSetLayoutBind.addBinding( // - vkDS(7, vkDT::eStorageBuffer, 1, - vkSS::eClosestHitKHR | vkSS::eIntersectionKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR + | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -163,78 +157,76 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& model : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(model.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(model.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(model.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(model.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } - dbiMat.emplace_back(m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE); // Adding implicit mat + dbiMat.push_back({m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE}); // Adding implicit mat writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); - vk::DescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiImplDesc)); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstants)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstants)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass()); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -246,8 +238,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -271,18 +261,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -298,17 +284,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -320,11 +304,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -333,15 +316,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -349,18 +332,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the VKImage - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + // Creating the dummy texture + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -373,8 +355,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -387,16 +368,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -411,10 +391,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_implObjects.implBuf); @@ -445,32 +426,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstants.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstants); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstants), &m_pushConstants); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -511,7 +491,7 @@ void HelloVulkan::initRayTracing() //-------------------------------------------------------------------------------------------------- // Ray trace the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { updateFrame(); if(m_pushConstants.frame >= m_maxFrames) @@ -580,7 +560,7 @@ void HelloVulkan::addImplMaterial(const MaterialObj& mat) // void HelloVulkan::createImplictBuffers() { - using vkBU = vk::BufferUsageFlagBits; + using vkBU = VkBufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); // Not allowing empty buffers @@ -589,11 +569,11 @@ void HelloVulkan::createImplictBuffers() if(m_implObjects.implMat.empty()) m_implObjects.implMat.push_back({}); - auto cmdBuf = cmdGen.createCommandBuffer(); - m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl, - vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); - m_implObjects.implMatBuf = - m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, vkBU::eStorageBuffer); + auto cmdBuf = cmdGen.createCommandBuffer(); + m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR + | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + m_implObjects.implMatBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj"); diff --git a/ray_tracing__advance/hello_vulkan.h b/ray_tracing__advance/hello_vulkan.h index 5da7063..fe138a0 100644 --- a/ray_tracing__advance/hello_vulkan.h +++ b/ray_tracing__advance/hello_vulkan.h @@ -19,7 +19,7 @@ #pragma once -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/resourceallocator_vk.hpp" @@ -56,25 +56,21 @@ using Allocator = nvvk::ResourceAllocatorDedicated; // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); Offscreen& offscreen() { return m_offscreen; } Raytracer& raytracer() { return m_raytrace; } @@ -87,12 +83,12 @@ public: // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; int m_maxFrames{10}; void resetFrame(); @@ -115,7 +111,7 @@ public: Raytracer m_raytrace; void initRayTracing(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); // Implicit ImplInst m_implObjects; diff --git a/ray_tracing__advance/main.cpp b/ray_tracing__advance/main.cpp index b4a3478..6eb565c 100644 --- a/ray_tracing__advance/main.cpp +++ b/ray_tracing__advance/main.cpp @@ -23,21 +23,18 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" #include "hello_vulkan.h" +#include "imgui/imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" -#include "imgui/imgui_camera_widget.h" #include ////////////////////////////////////////////////////////////////////////// @@ -47,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -70,18 +68,15 @@ void renderUI(HelloVulkan& helloVk) if(helloVk.m_pushConstants.lightType < 2) { - changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, - -20.f, 20.f); + changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, -20.f, 20.f); } if(helloVk.m_pushConstants.lightType > 0) { - changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, - -1.f, 1.f); + changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, -1.f, 1.f); } if(helloVk.m_pushConstants.lightType < 2) { - changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, - 500.f); + changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f); } if(helloVk.m_pushConstants.lightType == 1) { @@ -121,8 +116,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -151,7 +145,7 @@ int main(int argc, char** argv) contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); -#ifdef WIN32 +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -163,18 +157,16 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -189,11 +181,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -202,14 +193,13 @@ int main(int argc, char** argv) // Setup Imgui helloVk.initGUI(0); // Using sub-pass 0 - // Creating scene + // Creation of the example helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), - nvmath::scale_mat4(nvmath::vec3f(0.5f)) - * nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f))); + nvmath::scale_mat4(nvmath::vec3f(0.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f))); - std::random_device rd; // Will be used to obtain a seed for the random number engine + std::random_device rd; // Will be used to obtain a seed for the random number engine std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::normal_distribution dis(2.0f, 2.0f); std::normal_distribution disn(0.5f, 0.2f); @@ -278,11 +268,12 @@ int main(int argc, char** argv) // Start the Dear ImGui frame ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { - ImGui::NewFrame(); ImGuiH::Panel::Begin(); bool changed = false; // Edit 3 floats representing a color @@ -292,11 +283,8 @@ int main(int argc, char** argv) if(changed) helloVk.resetFrame(); - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -305,28 +293,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(offscreen.renderPass()); - offscreenRenderPassBeginInfo.setFramebuffer(offscreen.frameBuffer()); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = offscreen.renderPass(); + offscreenRenderPassBeginInfo.framebuffer = offscreen.frameBuffer(); + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -335,40 +324,41 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); offscreen.draw(cmdBuf, helloVk.getSize()); + // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing__advance/offscreen.cpp b/ray_tracing__advance/offscreen.cpp index 3a804f1..0f8c3b3 100644 --- a/ray_tracing__advance/offscreen.cpp +++ b/ray_tracing__advance/offscreen.cpp @@ -32,10 +32,7 @@ extern std::vector defaultSearchPaths; // Post-processing ////////////////////////////////////////////////////////////////////////// -void Offscreen::setup(const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - nvvk::ResourceAllocator* allocator, - uint32_t queueFamily) +void Offscreen::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily) { m_device = device; m_alloc = allocator; @@ -46,14 +43,14 @@ void Offscreen::setup(const vk::Device& device, void Offscreen::destroy() { - m_device.destroy(m_pipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_dsetLayout); + vkDestroyPipeline(m_device, m_pipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_dsetLayout, nullptr); + vkDestroyRenderPass(m_device, m_renderPass, nullptr); + vkDestroyFramebuffer(m_device, m_framebuffer, nullptr); m_alloc->destroy(m_colorTexture); m_alloc->destroy(m_depthTexture); - m_device.destroy(m_renderPass); - m_device.destroy(m_framebuffer); } //-------------------------------------------------------------------------------------------------- @@ -66,30 +63,28 @@ void Offscreen::createFramebuffer(VkExtent2D& size) // Creating the color image { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(size, m_colorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + auto colorCreateInfo = nvvk::makeImage2DCreateInfo( + size, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc->createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_colorTexture = m_alloc->createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc->createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_colorTexture = m_alloc->createTexture(image, ivInfo, sampler); m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer { - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(size, m_depthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); - nvvk::Image image = m_alloc->createImage(depthCreateInfo); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(size, m_depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + nvvk::Image image = m_alloc->createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_depthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_depthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_depthTexture = m_alloc->createTexture(image, depthStencilView); } @@ -98,11 +93,9 @@ void Offscreen::createFramebuffer(VkExtent2D& size) { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -111,50 +104,46 @@ void Offscreen::createFramebuffer(VkExtent2D& size) if(!m_renderPass) { m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true, - vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } // Creating the frame buffer for offscreen - std::vector attachments = {m_colorTexture.descriptor.imageView, - m_depthTexture.descriptor.imageView}; + std::vector attachments = {m_colorTexture.descriptor.imageView, m_depthTexture.descriptor.imageView}; - m_device.destroy(m_framebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_renderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(size.width); - info.setHeight(size.height); - info.setLayers(1); - m_framebuffer = m_device.createFramebuffer(info); + vkDestroyFramebuffer(m_device, m_framebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_renderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = size.width; + info.height = size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_framebuffer); } //-------------------------------------------------------------------------------------------------- // The pipeline is how things are rendered, which shaders, type of primitives, depth test and more // The incoming render pass, is in which rendering pass it will be displayed (framebuffer) // -void Offscreen::createPipeline(vk::RenderPass& renderPass) +void Offscreen::createPipeline(VkRenderPass& renderPass) { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_dsetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.setLayoutCount = 1; + pipelineLayoutCreateInfo.pSetLayouts = &m_dsetLayout; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_pipelineLayout); // Pipeline: completely generic, no vertices nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_pipeline = pipelineGenerator.createPipeline(); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_pipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_pipeline, "post"); } @@ -164,11 +153,7 @@ void Offscreen::createPipeline(vk::RenderPass& renderPass) // void Offscreen::createDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_dsetLayoutBinding.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_dsetLayoutBinding.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device); m_descPool = m_dsetLayoutBinding.createPool(m_device); m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout); @@ -179,26 +164,28 @@ void Offscreen::createDescriptor() // void Offscreen::updateDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void Offscreen::draw(vk::CommandBuffer cmdBuf, VkExtent2D& size) +void Offscreen::draw(VkCommandBuffer cmdBuf, VkExtent2D& size) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)size.width, (float)size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {size.width, size.height}}}); + VkViewport viewport{0, 0, (float)size.width, (float)size.height, 0, 1}; + vkCmdSetViewport(cmdBuf, 0, 1, &viewport); + VkRect2D scissor{{0, 0}, {size.width, size.height}}; + vkCmdSetScissor(cmdBuf, 0, 1, &scissor); + auto aspectRatio = static_cast(size.width) / static_cast(size.height); - cmdBuf.pushConstants(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_pipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_pipelineLayout, 0, m_dset, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_dset, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing__advance/offscreen.hpp b/ray_tracing__advance/offscreen.hpp index ef18b25..61bc16a 100644 --- a/ray_tracing__advance/offscreen.hpp +++ b/ray_tracing__advance/offscreen.hpp @@ -18,8 +18,6 @@ */ -#include - #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/resourceallocator_vk.hpp" @@ -33,40 +31,36 @@ class Offscreen { public: - void setup(const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - nvvk::ResourceAllocator* allocator, - uint32_t queueFamily); + void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily); void destroy(); void createFramebuffer(VkExtent2D& size); - void createPipeline(vk::RenderPass& renderPass); + void createPipeline(VkRenderPass& renderPass); void createDescriptor(); void updateDescriptorSet(); - void draw(vk::CommandBuffer cmdBuf, VkExtent2D& size); + void draw(VkCommandBuffer cmdBuf, VkExtent2D& size); - const vk::RenderPass& renderPass() { return m_renderPass; } - const vk::Framebuffer& frameBuffer() { return m_framebuffer; } - const nvvk::Texture& colorTexture() { return m_colorTexture; } + const VkRenderPass& renderPass() { return m_renderPass; } + const VkFramebuffer& frameBuffer() { return m_framebuffer; } + const nvvk::Texture& colorTexture() { return m_colorTexture; } private: nvvk::DescriptorSetBindings m_dsetLayoutBinding; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_dsetLayout; - vk::DescriptorSet m_dset; - vk::Pipeline m_pipeline; - vk::PipelineLayout m_pipelineLayout; - vk::RenderPass m_renderPass; - vk::Framebuffer m_framebuffer; + VkDescriptorPool m_descPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_dsetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_dset{VK_NULL_HANDLE}; + VkPipeline m_pipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_renderPass{VK_NULL_HANDLE}; + VkFramebuffer m_framebuffer{VK_NULL_HANDLE}; nvvk::Texture m_colorTexture; - vk::Format m_colorFormat{vk::Format::eR32G32B32A32Sfloat}; + VkFormat m_colorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; nvvk::Texture m_depthTexture; - vk::Format m_depthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_depthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - nvvk::ResourceAllocator* m_alloc{ - nullptr}; // Allocator for buffer, images, acceleration structures - vk::Device m_device; - int m_graphicsQueueIndex{0}; - nvvk::DebugUtil m_debug; // Utility to name objects + nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures + VkDevice m_device; + int m_graphicsQueueIndex{0}; + nvvk::DebugUtil m_debug; // Utility to name objects }; diff --git a/ray_tracing__advance/raytrace.cpp b/ray_tracing__advance/raytrace.cpp index 492107e..94a15e3 100644 --- a/ray_tracing__advance/raytrace.cpp +++ b/ray_tracing__advance/raytrace.cpp @@ -25,14 +25,12 @@ #include "nvh/alignment.hpp" #include "nvvk/shaders_vk.hpp" #include "obj_loader.h" +#include "nvvk/buffers_vk.hpp" extern std::vector defaultSearchPaths; -void Raytracer::setup(const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - nvvk::ResourceAllocator* allocator, - uint32_t queueFamily) +void Raytracer::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily) { m_device = device; m_physicalDevice = physicalDevice; @@ -40,12 +38,11 @@ void Raytracer::setup(const vk::Device& device, m_graphicsQueueIndex = queueFamily; // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); - m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex); m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties); m_debug.setup(device); } @@ -55,10 +52,10 @@ void Raytracer::destroy() { m_sbtWrapper.destroy(); m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); m_alloc->destroy(m_rtSBTBuffer); } @@ -68,30 +65,30 @@ void Raytracer::destroy() auto Raytracer::objectToVkGeometryKHR(const ObjModel& model) { // Building part - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); + VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit - asGeom.geometry.setTriangles(triangles); + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit + asGeom.geometry.triangles = triangles; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = model.nbIndices / 3; // Nb triangles + offset.primitiveOffset = 0; + offset.transformOffset = 0; nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); @@ -105,11 +102,11 @@ auto Raytracer::objectToVkGeometryKHR(const ObjModel& model) // auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj) { - vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer}); + VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, implicitObj.implBuf.buffer); - vk::AccelerationStructureGeometryAabbsDataKHR aabbs; - aabbs.setData(dataAddress); - aabbs.setStride(sizeof(ObjImplicit)); + VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR}; + aabbs.data.deviceAddress = dataAddress; + aabbs.stride = sizeof(ObjImplicit); // Setting up the build info of the acceleration VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; @@ -118,11 +115,11 @@ auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj) asGeom.geometry.aabbs = aabbs; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(static_cast(implicitObj.objImpl.size())); // Nb aabb - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = static_cast(implicitObj.objImpl.size()); // Nb aabb + offset.primitiveOffset = 0; + offset.transformOffset = 0; nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); @@ -153,8 +150,8 @@ void Raytracer::createBottomLevelAS(std::vector& models, ImplInst& imp } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace - | vk::BuildAccelerationStructureFlagBitsKHR::eAllowCompaction); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR + | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR); } void Raytracer::createTopLevelAS(std::vector& instances, ImplInst& implicitObj) @@ -176,46 +173,48 @@ void Raytracer::createTopLevelAS(std::vector& instances, ImplInst& if(!implicitObj.objImpl.empty()) { nvvk::RaytracingBuilderKHR::Instance rayInst; - rayInst.transform = implicitObj.transform; // Position of the instance - rayInst.instanceCustomId = - static_cast(implicitObj.blasId); // Same for material index - rayInst.blasId = static_cast(implicitObj.blasId); - rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one) - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + rayInst.transform = implicitObj.transform; // Position of the instance + rayInst.instanceCustomId = static_cast(implicitObj.blasId); // Same for material index + rayInst.blasId = static_cast(implicitObj.blasId); + rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one) + rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); } //-------------------------------------------------------------------------------------------------- // This descriptor set holds the Acceleration structure and the output image // -void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage) +void Raytracer::createRtDescriptorSet(const VkImageView& outputImage) { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; + using vkDSLB = VkDescriptorSetLayoutBinding; - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL}; + + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -223,169 +222,188 @@ void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage) // Writes the output image to the descriptor set // - Required when changing resolution // -void Raytracer::updateRtDescriptorSet(const vk::ImageView& outputImage) +void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage) { - using vkDT = vk::DescriptorType; - - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Pipeline for the ray tracer: all shaders, raygen, chit, miss // -void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) +void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout) { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eAnyHit, + eClosestHit1, + eAnyHit1, + eIntersect, + eCall0, + eCall1, + eCall2, + eShaderGroupCount + }; + + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + stages[eAnyHit] = stage; + // Hit Group - 1 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit1] = stage; + // Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + stages[eAnyHit1] = stage; + // Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; + stages[eIntersect] = stage; + + // Call0 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall0] = stage; + // Call1 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall1] = stage; + // Call2 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall2] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); // 0 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); // 1 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); // 2 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group0 - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - vk::ShaderModule ahitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true)); + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + group.anyHitShader = eAnyHit; + m_rtShaderGroups.push_back(group); - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - hg.setAnyHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); - m_rtShaderGroups.push_back(hg); // 3 - - - // Hit Group1 - Closest Hit + Intersection (procedural) - vk::ShaderModule chit2SM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); - vk::ShaderModule ahit2SM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true)); - vk::ShaderModule rintSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); - { - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); - hg.setAnyHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit2SM, "main"}); - hg.setIntersectionShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); - m_rtShaderGroups.push_back(hg); // 4 - } + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit1; + group.anyHitShader = eAnyHit1; + group.intersectionShader = eIntersect; + m_rtShaderGroups.push_back(group); // Callable shaders - vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; + group.generalShader = eCall0; + m_rtShaderGroups.push_back(group); + group.generalShader = eCall1; + m_rtShaderGroups.push_back(group); + group.generalShader = eCall2; + m_rtShaderGroups.push_back(group); - vk::ShaderModule call0 = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); - vk::ShaderModule call1 = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); - vk::ShaderModule call2 = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); - - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); - m_rtShaderGroups.push_back(callGroup); // 5 - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); - m_rtShaderGroups.push_back(callGroup); // 6 - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); - m_rtShaderGroups.push_back(callGroup); //7 - - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR - | vk::ShaderStageFlagBits::eCallableKHR, - 0, sizeof(RtPushConstants)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR + | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR, + 0, sizeof(RtPushConstants)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); - m_device.destroy(ahitSM); - m_device.destroy(chit2SM); - m_device.destroy(ahit2SM); - m_device.destroy(rintSM); - m_device.destroy(call0); - m_device.destroy(call1); - m_device.destroy(call2); + + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf, - const nvmath::vec4f& clearColor, - vk::DescriptorSet& sceneDescSet, - vk::Extent2D& size, - ObjPushConstants& sceneConstants) +void Raytracer::raytrace(const VkCommandBuffer& cmdBuf, + const nvmath::vec4f& clearColor, + VkDescriptorSet& sceneDescSet, + VkExtent2D& size, + ObjPushConstants& sceneConstants) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -398,19 +416,19 @@ void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf, m_rtPushConstants.lightType = sceneConstants.lightType; m_rtPushConstants.frame = sceneConstants.frame; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, sceneDescSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR - | vk::ShaderStageFlagBits::eCallableKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, sceneDescSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR + | VK_SHADER_STAGE_CALLABLE_BIT_KHR, + 0, sizeof(RtPushConstants), &m_rtPushConstants); - auto regions = m_sbtWrapper.getRegions(); - cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], size.width, size.height, 1); + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1); m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing__advance/raytrace.hpp b/ray_tracing__advance/raytrace.hpp index 82a35ac..b7ce768 100644 --- a/ray_tracing__advance/raytrace.hpp +++ b/ray_tracing__advance/raytrace.hpp @@ -18,8 +18,6 @@ */ -#include - #include "nvmath/nvmath.h" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp" @@ -29,44 +27,40 @@ class Raytracer { public: - void setup(const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - nvvk::ResourceAllocator* allocator, - uint32_t queueFamily); + void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily); void destroy(); auto objectToVkGeometryKHR(const ObjModel& model); auto implicitToVkGeometryKHR(const ImplInst& implicitObj); void createBottomLevelAS(std::vector& models, ImplInst& implicitObj); void createTopLevelAS(std::vector& instances, ImplInst& implicitObj); - void createRtDescriptorSet(const vk::ImageView& outputImage); - void updateRtDescriptorSet(const vk::ImageView& outputImage); - void createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout); - void raytrace(const vk::CommandBuffer& cmdBuf, - const nvmath::vec4f& clearColor, - vk::DescriptorSet& sceneDescSet, - vk::Extent2D& size, - ObjPushConstants& sceneConstants); + void createRtDescriptorSet(const VkImageView& outputImage); + void updateRtDescriptorSet(const VkImageView& outputImage); + void createRtPipeline(VkDescriptorSetLayout& sceneDescLayout); + void raytrace(const VkCommandBuffer& cmdBuf, + const nvmath::vec4f& clearColor, + VkDescriptorSet& sceneDescSet, + VkExtent2D& size, + ObjPushConstants& sceneConstants); private: - nvvk::ResourceAllocator* m_alloc{ - nullptr}; // Allocator for buffer, images, acceleration structures - vk::PhysicalDevice m_physicalDevice; - vk::Device m_device; - int m_graphicsQueueIndex{0}; - nvvk::DebugUtil m_debug; // Utility to name objects - nvvk::SBTWrapper m_sbtWrapper; + nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures + VkPhysicalDevice m_physicalDevice; + VkDevice m_device; + int m_graphicsQueueIndex{0}; + nvvk::DebugUtil m_debug; // Utility to name objects + nvvk::SBTWrapper m_sbtWrapper; - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::Buffer m_rtSBTBuffer; struct RtPushConstants { diff --git a/ray_tracing__before/hello_vulkan.cpp b/ray_tracing__before/hello_vulkan.cpp index 731588f..7485fb3 100644 --- a/ray_tracing__before/hello_vulkan.cpp +++ b/ray_tracing__before/hello_vulkan.cpp @@ -19,23 +19,24 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" +#include "nvh/alignment.hpp" #include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" +#include "nvvk/shaders_vk.hpp" + +extern std::vector defaultSearchPaths; // Holding the camera matrices @@ -50,13 +51,10 @@ struct CameraMatrices // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -64,43 +62,44 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -108,25 +107,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); // Textures (binding = 3) - m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment)); - + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT); // Materials (binding = 4) - m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -139,27 +132,27 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - for(auto &m : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -167,7 +160,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -176,32 +169,29 @@ void HelloVulkan::updateDescriptorSet() // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -213,8 +203,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -239,11 +227,11 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform // Create the buffers on Device and copy vertices, indices and materials nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, vkBU::eVertexBuffer); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, vkBU::eIndexBuffer); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -266,11 +254,8 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -282,11 +267,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -295,15 +279,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -311,18 +295,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -335,8 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -349,16 +331,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -373,10 +354,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -394,14 +376,14 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); m_alloc.deinit(); } @@ -409,33 +391,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); - + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -466,29 +446,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -497,11 +476,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -509,25 +486,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -536,26 +511,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -565,11 +537,7 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); @@ -581,28 +549,25 @@ void HelloVulkan::createPostDescriptor() // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); + m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing__before/hello_vulkan.h b/ray_tracing__before/hello_vulkan.h index b54f1e2..e429d1e 100644 --- a/ray_tracing__before/hello_vulkan.h +++ b/ray_tracing__before/hello_vulkan.h @@ -18,9 +18,8 @@ */ #pragma once -#include -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" @@ -33,25 +32,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -88,12 +83,12 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances @@ -109,18 +104,18 @@ public: void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; }; diff --git a/ray_tracing__before/main.cpp b/ray_tracing__before/main.cpp index c4a2e05..dac10d6 100644 --- a/ray_tracing__before/main.cpp +++ b/ray_tracing__before/main.cpp @@ -23,8 +23,6 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -89,14 +86,12 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0), - nvmath::vec3f(0, 1, 0)); + CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0), nvmath::vec3f(0, 1, 0)); // Setup Vulkan if(!glfwVulkanSupported()) @@ -147,11 +142,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -196,8 +190,7 @@ int main(int argc, char** argv) ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -206,62 +199,63 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); - // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); vkctx.deinit(); diff --git a/ray_tracing__simple/CMakeLists.txt b/ray_tracing__simple/CMakeLists.txt index 24e1da2..8587db8 100644 --- a/ray_tracing__simple/CMakeLists.txt +++ b/ray_tracing__simple/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") @@ -76,4 +76,3 @@ _finalize_target( ${PROJNAME} ) install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") - diff --git a/ray_tracing__simple/hello_vulkan.cpp b/ray_tracing__simple/hello_vulkan.cpp index 3d491cb..bb64a80 100644 --- a/ray_tracing__simple/hello_vulkan.cpp +++ b/ray_tracing__simple/hello_vulkan.cpp @@ -19,9 +19,7 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" @@ -38,6 +36,8 @@ extern std::vector defaultSearchPaths; #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -54,13 +54,10 @@ struct CameraMatrices // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -68,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -115,33 +112,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -154,25 +145,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -180,7 +171,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -188,40 +179,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -233,8 +222,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -258,18 +245,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -285,17 +268,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -307,11 +288,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -320,15 +300,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -336,18 +316,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -360,8 +339,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -374,16 +352,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -398,10 +375,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -419,21 +397,22 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.destroy(m_rtSBTBuffer); m_alloc.deinit(); @@ -442,32 +421,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -482,10 +460,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -497,29 +477,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -528,11 +507,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -540,24 +517,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -566,26 +542,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -595,43 +568,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -646,10 +612,10 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } @@ -659,35 +625,38 @@ void HelloVulkan::initRayTracing() auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { // BLAS builder requires raw device addresses. - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); uint32_t maxPrimitiveCount = model.nbIndices / 3; // Describe buffer as array of VertexObj. - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data. - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); // Describe index data (32-bit unsigned int) - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; // Indicate identity transform by setting transformData to null device pointer. - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; // Identify the above data as containing opaque triangles. - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; // The entire array will be used to build the BLAS. - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(maxPrimitiveCount); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; @@ -712,7 +681,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -729,7 +698,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -737,30 +706,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -770,13 +742,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -785,94 +754,111 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, // two miss shader groups, and one hit group. - rayPipelineInfo.setGroupCount(static_cast(m_rtShaderGroups.size())); - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. if(m_rtProperties.maxRayRecursionDepth <= 1) { - throw std::runtime_error( - "Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); + throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); } - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -883,28 +869,25 @@ void HelloVulkan::createRtPipeline() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = - static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier + auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit + uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = - nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; - // Fetch all the shader handles used in the pipeline. This is opaque data, - // so we store it in a vector of bytes. + // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. + // The order of handles follow the stage entry. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + + assert(result == VK_SUCCESS); // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer( - sbtSize, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress - | vk::BufferUsageFlagBits::eShaderBindingTableKHR, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Map the SBT buffer and write in the handles. @@ -922,7 +905,7 @@ void HelloVulkan::createRtShaderBindingTable() //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -931,31 +914,33 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + // Size of a program identifier - uint32_t groupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); + uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; - using Stride = vk::StridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_rtSBTBuffer.buffer; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - &strideAddresses[3], // - m_size.width, m_size.height, 1); // + using Stride = VkStridedDeviceAddressRegionKHR; + std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen + Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss + Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit + Stride{0u, 0u, 0u}}; // callable + + + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing__simple/hello_vulkan.h b/ray_tracing__simple/hello_vulkan.h index 80ac1e6..0702a8d 100644 --- a/ray_tracing__simple/hello_vulkan.h +++ b/ray_tracing__simple/hello_vulkan.h @@ -18,12 +18,12 @@ */ #pragma once -#include -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -35,25 +35,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -90,39 +86,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -133,25 +131,25 @@ public: void updateRtDescriptorSet(); void createRtPipeline(); void createRtShaderBindingTable(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::Buffer m_rtSBTBuffer; struct RtPushConstant { nvmath::vec4f clearColor; nvmath::vec3f lightPosition; - float lightIntensity; - int lightType; + float lightIntensity{100.0f}; + int lightType{0}; } m_rtPushConstants; }; diff --git a/ray_tracing__simple/main.cpp b/ray_tracing__simple/main.cpp index cffadb5..912c6c4 100644 --- a/ray_tracing__simple/main.cpp +++ b/ray_tracing__simple/main.cpp @@ -23,8 +23,6 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -87,8 +86,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -117,7 +115,7 @@ int main(int argc, char** argv) contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); -#ifdef WIN32 +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -127,19 +125,19 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // Creating Vulkan base application nvvk::Context vkctx{}; vkctx.initInstance(contextInfo); @@ -149,16 +147,14 @@ int main(int argc, char** argv) // Use a compatible device vkctx.initDevice(compatibleDevices[0], contextInfo); - // Create example HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -219,9 +215,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -230,28 +224,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -260,40 +255,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_animation/CMakeLists.txt b/ray_tracing_animation/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_animation/CMakeLists.txt +++ b/ray_tracing_animation/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_animation/README.md b/ray_tracing_animation/README.md index 5aa0bff..7a89f71 100644 --- a/ray_tracing_animation/README.md +++ b/ray_tracing_animation/README.md @@ -62,17 +62,20 @@ void HelloVulkan::animationInstances(float time) Next, we update the buffer that describes the scene, which is used by the rasterizer to set each object's position, and also by the ray tracer to compute shading normals. ~~~~ C++ // Update the buffer - vk::DeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance); - nvvkBuffer stagingBuffer = m_alloc.createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible); + VkDeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance); + nvvk::Buffer stagingBuffer = + m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); // Copy data to staging buffer auto* gInst = m_alloc.map(stagingBuffer); memcpy(gInst, m_objInstance.data(), bufferSize); m_alloc.unmap(stagingBuffer); // Copy staging buffer to the Scene Description buffer nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - cmdBuf.copyBuffer(stagingBuffer.buffer, m_sceneDesc.buffer, vk::BufferCopy(0, 0, bufferSize)); + VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); + + VkBufferCopy region{0, 0, bufferSize}; + vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_sceneDesc.buffer, 1, ®ion); + m_debug.endLabel(cmdBuf); genCmdBuf.submitAndWait(cmdBuf); m_alloc.destroy(stagingBuffer); @@ -115,7 +118,7 @@ std::vector m_tlas; Make sure to rename it to `m_tlas`, instead of `tlas`. -One important point is that we need to set the TLAS build flags to allow updates, by adding the`vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate` flag. +One important point is that we need to set the TLAS build flags to allow updates, by adding the`VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR` flag. This is absolutely needed, since otherwise the TLAS cannot be updated. ~~~~ C++ @@ -124,16 +127,17 @@ void HelloVulkan::createTopLevelAS() m_tlas.reserve(m_objInstance.size()); for(uint32_t i = 0; i < static_cast(m_objInstance.size()); i++) { - nvvk::RaytracingBuilder::Instance rayInst; + nvvk::RaytracingBuilderKHR::Instance rayInst; rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT rayInst.blasId = m_objInstance[i].objIndex; - rayInst.hitGroupId = m_objInstance[i].hitgroup; - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV; + rayInst.hitGroupId = 0; + rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; m_tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(m_tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace - | vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate); + + m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; + m_rtBuilder.buildTlas(m_tlas, m_rtFlags); } ~~~~ @@ -203,11 +207,11 @@ Add all of the following members to the `HelloVulkan` class: void createCompPipelines(); nvvk::DescriptorSetBindings m_compDescSetLayoutBind; - vk::DescriptorPool m_compDescPool; - vk::DescriptorSetLayout m_compDescSetLayout; - vk::DescriptorSet m_compDescSet; - vk::Pipeline m_compPipeline; - vk::PipelineLayout m_compPipelineLayout; + VkDescriptorPool m_compDescPool; + VkDescriptorSetLayout m_compDescSetLayout; + VkDescriptorSet m_compDescSet; + VkPipeline m_compPipeline; + VkPipelineLayout m_compPipelineLayout; ~~~~ The compute shader will work on a single `VertexObj` buffer. @@ -215,8 +219,7 @@ The compute shader will work on a single `VertexObj` buffer. ~~~~ C++ void HelloVulkan::createCompDescriptors() { - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( - 0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute)); + m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); @@ -227,12 +230,12 @@ void HelloVulkan::createCompDescriptors() `updateCompDescriptors` will set the set the descriptor to the buffer of `VertexObj` objects to which the animation will be applied. ~~~~ C++ -void HelloVulkan::updateCompDescriptors(nvvkBuffer& vertex) +void HelloVulkan::updateCompDescriptors(nvvk::Buffer& vertex) { - std::vector writes; - vk::DescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, dbiUnif)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + std::vector writes; + VkDescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE}; + writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &dbiUnif)); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } ~~~~ @@ -243,27 +246,37 @@ to set the animation time. void HelloVulkan::createCompPipelines() { // pushing time - vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(float)}; - vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants}; - m_compPipelineLayout = m_device.createPipelineLayout(layout_info); - vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; + VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float)}; + + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_compDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &push_constants; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_compPipelineLayout); + + + VkComputePipelineCreateInfo computePipelineCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + computePipelineCreateInfo.layout = m_compPipelineLayout; computePipelineCreateInfo.stage = - nvvk::createShaderStageInfo(m_device, - nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths), + nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_COMPUTE_BIT); - m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo, nullptr); - m_device.destroy(computePipelineCreateInfo.stage.module); + + vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_compPipeline); + + vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr); } ~~~~ Finally, destroy the resources in `HelloVulkan::destroyResources()`: ~~~~ C++ - m_device.destroy(m_compDescPool); - m_device.destroy(m_compDescSetLayout); - m_device.destroy(m_compPipeline); - m_device.destroy(m_compPipelineLayout); + // #VK_compute + vkDestroyPipeline(m_device, m_compPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr); ~~~~ ### `anim.comp` @@ -338,14 +351,13 @@ void HelloVulkan::animationObject(float time) updateCompDescriptors(model.vertexBuffer); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); + VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); + + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); + vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time); + vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0, - {m_compDescSet}, {}); - cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(float), - &time); - cmdBuf.dispatch(model.nbVertices, 1, 1); genCmdBuf.submitAndWait(cmdBuf); } ~~~~ @@ -450,15 +462,15 @@ void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry m_blas.reserve(m_objModel.size()); - for(const auto & obj : m_objModel) + for(const auto& obj : m_objModel) { auto blas = objectToVkGeometryKHR(obj); // We could add more geometry in each BLAS, but we add only one for now m_blas.push_back(blas); } - m_rtBuilder.buildBlas(m_blas, vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate - | vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastBuild); + m_rtBuilder.buildBlas(m_blas, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR + | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); } ~~~~ diff --git a/ray_tracing_animation/hello_vulkan.cpp b/ray_tracing_animation/hello_vulkan.cpp index 6b3ece9..287ac4f 100644 --- a/ray_tracing_animation/hello_vulkan.cpp +++ b/ray_tracing_animation/hello_vulkan.cpp @@ -19,26 +19,25 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" +#include "nvh/alignment.hpp" #include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/alignment.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -50,16 +49,14 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); @@ -68,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -115,33 +112,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -154,25 +145,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -180,7 +171,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -188,40 +179,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -233,8 +222,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -258,18 +245,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -285,17 +268,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -307,11 +288,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -320,15 +300,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -336,18 +316,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -360,8 +339,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -374,16 +352,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -398,10 +375,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -419,62 +397,62 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); m_sbtWrapper.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); + // #VK_compute - m_device.destroy(m_compDescPool); - m_device.destroy(m_compDescSetLayout); - m_device.destroy(m_compPipeline); - m_device.destroy(m_compPipelineLayout); + vkDestroyPipeline(m_device, m_compPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr); m_alloc.deinit(); } - //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -489,10 +467,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -504,29 +484,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -535,11 +514,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -547,24 +524,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -573,26 +549,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -602,43 +575,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -653,48 +619,64 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } +//-------------------------------------------------------------------------------------------------- +// +// void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry @@ -706,8 +688,8 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now m_blas.push_back(blas); } - m_rtBuilder.buildBlas(m_blas, vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate - | vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastBuild); + m_rtBuilder.buildBlas(m_blas, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR + | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -724,8 +706,7 @@ void HelloVulkan::createTopLevelAS() m_tlas.emplace_back(rayInst); } - m_rtFlags = vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace - | vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate; + m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; m_rtBuilder.buildTlas(m_tlas, m_rtFlags); } @@ -734,30 +715,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -767,13 +751,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -782,93 +763,112 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; - - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; + + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -877,19 +877,18 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); - auto regions = m_sbtWrapper.getRegions(); - cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], m_size.width, m_size.height, - 1); + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); } @@ -909,8 +908,7 @@ void HelloVulkan::animationInstances(float time) { int wusonIdx = i + 1; ObjInstance& inst = m_objInstance[wusonIdx]; - inst.transform = nvmath::rotation_mat4_y(i * deltaAngle + offset) - * nvmath::translation_mat4(radius, 0.f, 0.f); + inst.transform = nvmath::rotation_mat4_y(i * deltaAngle + offset) * nvmath::translation_mat4(radius, 0.f, 0.f); inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform)); nvvk::RaytracingBuilderKHR::Instance& tinst = m_tlas[wusonIdx]; @@ -918,18 +916,20 @@ void HelloVulkan::animationInstances(float time) } // Update the buffer - vk::DeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance); - nvvk::Buffer stagingBuffer = - m_alloc.createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible); + VkDeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance); + nvvk::Buffer stagingBuffer = + m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); // Copy data to staging buffer auto* gInst = m_alloc.map(stagingBuffer); memcpy(gInst, m_objInstance.data(), bufferSize); m_alloc.unmap(stagingBuffer); // Copy staging buffer to the Scene Description buffer nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - cmdBuf.copyBuffer(stagingBuffer.buffer, m_sceneDesc.buffer, vk::BufferCopy(0, 0, bufferSize)); + VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); + + VkBufferCopy region{0, 0, bufferSize}; + vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_sceneDesc.buffer, 1, ®ion); + m_debug.endLabel(cmdBuf); genCmdBuf.submitAndWait(cmdBuf); m_alloc.destroy(stagingBuffer); @@ -944,14 +944,13 @@ void HelloVulkan::animationObject(float time) updateCompDescriptors(model.vertexBuffer); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); + VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); + + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); + vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time); + vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0, - {m_compDescSet}, {}); - cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(float), - &time); - cmdBuf.dispatch(model.nbVertices, 1, 1); genCmdBuf.submitAndWait(cmdBuf); m_rtBuilder.updateBlas(2); } @@ -960,8 +959,7 @@ void HelloVulkan::animationObject(float time) // #VK_compute void HelloVulkan::createCompDescriptors() { - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( - 0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute)); + m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); @@ -970,24 +968,33 @@ void HelloVulkan::createCompDescriptors() void HelloVulkan::updateCompDescriptors(nvvk::Buffer& vertex) { - std::vector writes; - vk::DescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE}; + std::vector writes; + VkDescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &dbiUnif)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } void HelloVulkan::createCompPipelines() { // pushing time - vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(float)}; - vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants}; - m_compPipelineLayout = m_device.createPipelineLayout(layout_info); - vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; + VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float)}; - computePipelineCreateInfo.stage = nvvk::createShaderStageInfo( - m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true), - VK_SHADER_STAGE_COMPUTE_BIT); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_compDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &push_constants; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_compPipelineLayout); - m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo).value; - m_device.destroy(computePipelineCreateInfo.stage.module); + + VkComputePipelineCreateInfo computePipelineCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + computePipelineCreateInfo.layout = m_compPipelineLayout; + + computePipelineCreateInfo.stage = + nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true), + VK_SHADER_STAGE_COMPUTE_BIT); + + vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_compPipeline); + + vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr); } diff --git a/ray_tracing_animation/hello_vulkan.h b/ray_tracing_animation/hello_vulkan.h index b9f07f4..1e868ee 100644 --- a/ray_tracing_animation/hello_vulkan.h +++ b/ray_tracing_animation/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -36,25 +36,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -91,39 +87,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -133,19 +131,19 @@ public: void createRtDescriptorSet(); void updateRtDescriptorSet(); void createRtPipeline(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::SBTWrapper m_sbtWrapper; std::vector m_tlas; std::vector m_blas; @@ -168,11 +166,11 @@ public: void createCompPipelines(); nvvk::DescriptorSetBindings m_compDescSetLayoutBind; - vk::DescriptorPool m_compDescPool; - vk::DescriptorSetLayout m_compDescSetLayout; - vk::DescriptorSet m_compDescSet; - vk::Pipeline m_compPipeline; - vk::PipelineLayout m_compPipelineLayout; + VkDescriptorPool m_compDescPool; + VkDescriptorSetLayout m_compDescSetLayout; + VkDescriptorSet m_compDescSet; + VkPipeline m_compPipeline; + VkPipelineLayout m_compPipelineLayout; - vk::BuildAccelerationStructureFlagsKHR m_rtFlags; + VkBuildAccelerationStructureFlagsKHR m_rtFlags; }; diff --git a/ray_tracing_animation/main.cpp b/ray_tracing_animation/main.cpp index 538d8d0..1acd8d1 100644 --- a/ray_tracing_animation/main.cpp +++ b/ray_tracing_animation/main.cpp @@ -23,7 +23,6 @@ // at the top of imgui.cpp. #include -#include #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -33,13 +32,10 @@ #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE - ////////////////////////////////////////////////////////////////////////// #define UNUSED(x) (void)(x) ////////////////////////////////////////////////////////////////////////// @@ -47,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -74,6 +71,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -88,12 +86,11 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(nvmath::vec3f(4, 4, 4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0)); + CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0)); // Setup Vulkan if(!glfwVulkanSupported()) @@ -131,16 +128,14 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -155,11 +150,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -229,8 +223,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -244,28 +237,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -274,40 +268,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_anyhit/CMakeLists.txt b/ray_tracing_anyhit/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_anyhit/CMakeLists.txt +++ b/ray_tracing_anyhit/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_anyhit/README.md b/ray_tracing_anyhit/README.md index cb3b77f..bfa40a3 100644 --- a/ray_tracing_anyhit/README.md +++ b/ray_tracing_anyhit/README.md @@ -108,25 +108,30 @@ The any hit shader will be part of the hit shader group. Currently, the hit shad In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahit.spv` ~~~~ C++ - vk::ShaderModule ahitSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rahit.spv", true, paths)); + enum StageIndices + { + ... + eAnyHit, + eShaderGroupCount + }; + + // Hit Group - Any Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + stages[eAnyHit] = stage; ~~~~ -add the any hit shader to the hit group +The Any Hit goes in the same Hit group as the Closest Hit, so we need to +add the Any Hit stage index and push back the shader module to the stages. ~~~~ C++ - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - hg.setAnyHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); - m_rtShaderGroups.push_back(hg); -~~~~ - -and at the end, delete it: - -~~~~ C++ -m_device.destroy(ahitSM); + // closest hit shader + // Payload 0 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + group.anyHitShader = eAnyHit; + m_rtShaderGroups.push_back(group); ~~~~ ## Give access of the buffers to the Any Hit shader @@ -137,38 +142,37 @@ This is the case for the material and scene description buffers ~~~~ C++ // Materials (binding = 1) - m_descSetLayoutBind.emplace_back( - vkDS(1, vkDT::eStorageBuffer, nbObj, - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT + | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.emplace_back( // - vkDS(2, vkDT::eStorageBuffer, 1, - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT + | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); ~~~~ and also for the vertex, index and material index buffers: ~~~~ C++ // Materials (binding = 4) - m_descSetLayoutBind.emplace_back( // - vkDS(4, vkDT::eStorageBuffer, nbObj, - vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.emplace_back( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.emplace_back( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); ~~~~ ## Opaque Flag -In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `vk::GeometryFlagBitsKHR::eOpaque`. However, this avoided invoking the any hit shader. +In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `VK_GEOMETRY_OPAQUE_BIT_KHR`. However, this avoided invoking the any hit shader. -We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `eNoDuplicateAnyHitInvocation` flag: +We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR` flag: ~~~~ C++ -geometry.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); +asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // Avoid double hits; ~~~~ ## Ray Generation Shader @@ -364,8 +368,6 @@ traceRayEXT(topLevelAS, // acceleration structure ~~~~ - - ### Ray tracing Pipeline The final step is to add the new Hit Group. This is a change in `HelloVulkan::createRtPipeline()`. @@ -373,22 +375,42 @@ We need to load the new any hit shader and create a new Hit Group. Replace the `"shaders/raytrace.rahit.spv"` for `"shaders/raytrace_0.rahit.spv"` +Load the new shader module. + +~~~~ C + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eAnyHit, + eAnyHit2, + eShaderGroupCount + }; + + // Hit Group - Any Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_0.rahit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + stages[eAnyHit] = stage; + // + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + stages[eAnyHit2] = stage; +~~~~ + Then, after the creating of the first Hit Group, create a new one, where only the any hit using payload 1 is added. We are skipping the closest hit shader in the trace call, so we can ignore it in the Hit Group. ~~~~ C -// Payload 1 -vk::ShaderModule ahit1SM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths)); -hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped) -hg.setAnyHitShader(static_cast(stages.size())); -stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"}); -m_rtShaderGroups.push_back(hg); + // Payload 1 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.anyHitShader = eAnyHit2; + m_rtShaderGroups.push_back(group); ~~~~ -At the end of the function, delete the shader module `ahit1SM`. - **Note:** Re-Run Everything should work as before, but now it does it right. diff --git a/ray_tracing_anyhit/hello_vulkan.cpp b/ray_tracing_anyhit/hello_vulkan.cpp index da83c0c..6b33283 100644 --- a/ray_tracing_anyhit/hello_vulkan.cpp +++ b/ray_tracing_anyhit/hello_vulkan.cpp @@ -19,26 +19,25 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" +#include "nvh/alignment.hpp" #include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/alignment.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -50,17 +49,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -68,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -115,36 +112,31 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT + | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT + | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( // - vkDS(4, vkDT::eStorageBuffer, nbObj, - vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -157,25 +149,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -183,7 +175,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -191,40 +183,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -236,8 +226,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -261,18 +249,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -288,17 +272,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -310,11 +292,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -323,15 +304,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -339,18 +320,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -363,8 +343,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -377,16 +356,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -401,10 +379,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -422,21 +401,22 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.destroy(m_rtSBTBuffer); m_alloc.deinit(); @@ -445,32 +425,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -486,10 +465,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) resetFrame(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -501,29 +482,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -532,11 +512,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -544,24 +522,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -570,26 +547,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -599,43 +573,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -650,47 +617,63 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // Avoid double hits - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // Avoid double hits; + asGeom.geometry.triangles = triangles; + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } +//-------------------------------------------------------------------------------------------------- +// +// void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry @@ -703,7 +686,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -720,7 +703,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -728,30 +711,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -761,13 +747,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -776,146 +759,171 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eAnyHit, + eAnyHit2, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; + // Hit Group - Any Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_0.rahit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + stages[eAnyHit] = stage; + // + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + stages[eAnyHit2] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); - // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); - // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit + // Miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + + // Shadow Miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); + + // closest hit shader // Payload 0 - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - vk::ShaderModule ahitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true)); - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - hg.setAnyHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); - m_rtShaderGroups.push_back(hg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + group.anyHitShader = eAnyHit; + m_rtShaderGroups.push_back(group); // Payload 1 - vk::ShaderModule ahit1SM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true)); - hg.setClosestHitShader(VK_SHADER_UNUSED_KHR); // Not used by shadow (skipped) - hg.setAnyHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit1SM, "main"}); - m_rtShaderGroups.push_back(hg); - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.anyHitShader = eAnyHit2; + m_rtShaderGroups.push_back(group); + // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); - m_device.destroy(ahitSM); - m_device.destroy(ahit1SM); + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); + + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // The Shader Binding Table (SBT) -// - getting all shader handles and writing them in a SBT buffer +// - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this // See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = - static_cast(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit, 2 ahit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - uint32_t groupSizeAligned = - nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - - // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT + auto groupCount = static_cast(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit, 2 ahit + uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier + // Compute the actual size needed per SBT entry (round-up to alignment needed). + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; + // Fetch all the shader handles used in the pipeline. This is opaque data, + // so we store it in a vector of bytes. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); - // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer( - sbtSize, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR - | vk::BufferUsageFlagBits::eShaderBindingTableKHR, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + assert(result == VK_SUCCESS); + + // Allocate a buffer for storing the SBT. Give it a debug name for NSight. + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); - // Write the handles in the SBT + // Map the SBT buffer and write in the handles. void* mapped = m_alloc.map(m_rtSBTBuffer); auto* pData = reinterpret_cast(mapped); for(uint32_t g = 0; g < groupCount; g++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen + memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); - - m_alloc.finalizeAndReleaseStaging(); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { updateFrame(); if(m_rtPushConstants.frame >= m_maxFrames) @@ -928,32 +936,33 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + // Size of a program identifier - uint32_t groupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); + uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; - using Stride = vk::StridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_rtSBTBuffer.buffer; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - &strideAddresses[3], // - m_size.width, m_size.height, - 1); // + using Stride = VkStridedDeviceAddressRegionKHR; + std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen + Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss + Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 2}, // hit + Stride{0u, 0u, 0u}}; // callable + + + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_anyhit/hello_vulkan.h b/ray_tracing_anyhit/hello_vulkan.h index 215b3b1..9d11ec8 100644 --- a/ray_tracing_anyhit/hello_vulkan.h +++ b/ray_tracing_anyhit/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -35,25 +35,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -90,39 +86,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -133,21 +131,21 @@ public: void updateRtDescriptorSet(); void createRtPipeline(); void createRtShaderBindingTable(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void resetFrame(); void updateFrame(); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; - int m_maxFrames{10000}; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::Buffer m_rtSBTBuffer; + int m_maxFrames{10000}; struct RtPushConstant { diff --git a/ray_tracing_anyhit/main.cpp b/ray_tracing_anyhit/main.cpp index 65d516a..3158978 100644 --- a/ray_tracing_anyhit/main.cpp +++ b/ray_tracing_anyhit/main.cpp @@ -23,7 +23,6 @@ // at the top of imgui.cpp. #include -#include #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -33,11 +32,9 @@ #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE ////////////////////////////////////////////////////////////////////////// #define UNUSED(x) (void)(x) @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -87,8 +86,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -117,7 +115,7 @@ int main(int argc, char** argv) contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); -#ifdef WIN32 +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -131,13 +129,10 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); - + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); @@ -156,11 +151,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -172,8 +166,7 @@ int main(int argc, char** argv) // Creation of the example helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true), - nvmath::scale_mat4(nvmath::vec3f(1.5f)) - * nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f))); + nvmath::scale_mat4(nvmath::vec3f(1.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f))); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); @@ -215,6 +208,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -223,8 +217,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -233,28 +226,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -263,40 +257,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_ao/README.md b/ray_tracing_ao/README.md index ae7b5c9..62a3df1 100644 --- a/ray_tracing_ao/README.md +++ b/ray_tracing_ao/README.md @@ -36,35 +36,33 @@ The following are the buffers are they can be seen in [NSight Graphics](https:// ## G-Buffer -The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `vk::Format::eR32G32B32A32Sfloat` to store the position and normal and one `vk::Format::eR32Sfloat` for the ambient occlusion. +The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion. ~~~~ C++ // The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed) { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler); m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_debug.setObjectName(m_gBuffer.image, "G-Buffer"); } // The ambient occlusion result (r32) { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler); m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_debug.setObjectName(m_aoBuffer.image, "aoBuffer"); } @@ -76,9 +74,9 @@ The render pass for the fragment shader will need two color buffers, therefore w ``` // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_gBuffer.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; + std::vector attachments = {m_offscreenColor.descriptor.imageView, + m_gBuffer.descriptor.imageView, + m_offscreenDepth.descriptor.imageView}; ``` ### Renderpass @@ -86,7 +84,7 @@ The render pass for the fragment shader will need two color buffers, therefore w This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth) ``` - vk::ClearValue clearValues[3]; + std::array clearValues{}; ``` Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section. @@ -94,14 +92,14 @@ Since the clear value will be re-used by the offscreen (3 attachments) and the p ``` // Offscreen render pass { - clearValues[1].setColor(std::array{0, 0, 0, 0}); - clearValues[2].setDepthStencil({1.0f, 0}); + clearValues[1].color = {{0, 0, 0, 0}}; + clearValues[2].depthStencil = {1.0f, 0}; ``` ``` // 2nd rendering pass: tone mapper, UI { - clearValues[1].setDepthStencil({1.0f, 0}); + clearValues[1].depthStencil = {1.0f, 0}; ``` ### Fragment shader @@ -138,12 +136,9 @@ The shader takes two inputs, the G-Buffer and the TLAS, and has one output, the // void HelloVulkan::createCompDescriptors() { - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer - 0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute)); - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO - 1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute)); - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS - 2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute)); + m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer + m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO + m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); @@ -162,15 +157,17 @@ when resizing the window and the G-Buffer and AO buffer are resized. // void HelloVulkan::updateCompDescriptors() { - std::vector writes; + std::vector writes; writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor)); - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas}; + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } ~~~~ @@ -200,40 +197,38 @@ struct AoControl The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)). This sets the current frame index, which allows us to accumulate AO samples over time. -Next, we are adding a `vk::ImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader. +Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader. ~~~~ C++ // Adding a barrier to be sure the fragment has finished writing to the G-Buffer // before the compute shader is using the buffer - vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; - vk::ImageMemoryBarrier imgMemBarrier; - imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); - imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - imgMemBarrier.setImage(m_gBuffer.image); - imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setSubresourceRange(range); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader, - vk::PipelineStageFlagBits::eComputeShader, - vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier}); + VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imgMemBarrier.image = m_gBuffer.image; + imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + imgMemBarrier.subresourceRange = range; + + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); ~~~~ Folowing is the call to dispatch the compute shader ~~~~ C++ // Preparing for the compute shader - cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0, - {m_compDescSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); + // Sending the push constant information aoControl.frame = m_frame; - cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, - sizeof(AoControl), &aoControl); + vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl); // Dispatching the shader - cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, - (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1); + vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1); ~~~~ Then we are adding a final barrier to make sure the compute shader is done @@ -242,13 +237,9 @@ writing the AO so that the fragment shader (post) can use it. ~~~~ C++ // Adding a barrier to be sure the compute shader has finished // writing to the AO buffer before the post shader is using it - imgMemBarrier.setImage(m_aoBuffer.image); - imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setSubresourceRange(range); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, - vk::PipelineStageFlagBits::eFragmentShader, - vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier}); + imgMemBarrier.image = m_aoBuffer.image; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); ~~~~ ## Update Frame @@ -450,9 +441,9 @@ We have also have added `AoControl aoControl;` somwhere in main() and passing th ~~~~ // Rendering Scene { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); helloVk.runCompute(cmdBuf, aoControl); } ~~~~ @@ -463,10 +454,10 @@ The post shader will combine the result of the fragment (color) and the result o In `createPostDescriptor` we will need to add the descriptor ~~~~ -m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); +m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); ~~~~ -And the equivalent in `updatePostDescriptorSet` +And the equivalent in `updatePostDescriptorSet()` ~~~~ writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor)); diff --git a/ray_tracing_ao/hello_vulkan.cpp b/ray_tracing_ao/hello_vulkan.cpp index 0c25097..f573c10 100644 --- a/ray_tracing_ao/hello_vulkan.cpp +++ b/ray_tracing_ao/hello_vulkan.cpp @@ -19,25 +19,25 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" +#include "nvh/alignment.hpp" #include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -45,21 +45,17 @@ struct CameraMatrices nvmath::mat4f view; nvmath::mat4f proj; nvmath::mat4f viewInverse; - // #VKRay - nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -67,46 +63,44 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); - // #VKRay - hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -114,22 +108,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); // Materials (binding = 1) - m_descSetLayoutBind.addBinding(vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eFragment)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding(vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); // Textures (binding = 3) - m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT); // Materials (binding = 4) - m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -142,40 +133,39 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); - // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -183,37 +173,34 @@ void HelloVulkan::updateDescriptorSet() // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); - vk::PipelineColorBlendAttachmentState res; - res.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG - | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA; + VkPipelineColorBlendAttachmentState res{}; + res.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + res.colorBlendOp = VK_BLEND_OP_ADD; gpb.addBlendAttachmentState(res); m_graphicsPipeline = gpb.createPipeline(); @@ -225,8 +212,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -250,18 +235,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -277,17 +258,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -299,11 +278,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -312,15 +290,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -328,18 +306,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the VKImage - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + // Creating the dummy texture + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -352,8 +329,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -366,16 +342,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -390,10 +365,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -411,22 +387,22 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_gBuffer); m_alloc.destroy(m_aoBuffer); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); // Compute - m_device.destroy(m_compDescPool); - m_device.destroy(m_compDescSetLayout); - m_device.destroy(m_compPipeline); - m_device.destroy(m_compPipelineLayout); + vkDestroyPipeline(m_device, m_compPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr); // #VKRay m_rtBuilder.destroy(); @@ -436,32 +412,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -491,64 +466,62 @@ void HelloVulkan::createOffscreenRender() m_alloc.destroy(m_aoBuffer); m_alloc.destroy(m_offscreenDepth); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_debug.setObjectName(m_offscreenColor.image, "offscreen"); } // The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed) { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler); m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_debug.setObjectName(m_gBuffer.image, "G-Buffer"); } // The ambient occlusion result (r32) { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler); m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_debug.setObjectName(m_aoBuffer.image, "aoBuffer"); } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -557,15 +530,11 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -574,26 +543,23 @@ void HelloVulkan::createOffscreenRender() if(!m_offscreenRenderPass) { m_offscreenRenderPass = - nvvk::createRenderPass(m_device, - {m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer - m_offscreenDepthFormat, 1, true, true, vk::ImageLayout::eGeneral, - vk::ImageLayout::eGeneral); + nvvk::createRenderPass(m_device, {m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer + m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_gBuffer.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_gBuffer.descriptor.imageView, + m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(static_cast(attachments.size())); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = static_cast(attachments.size()); + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -602,26 +568,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -631,12 +594,8 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); - m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); @@ -647,36 +606,32 @@ void HelloVulkan::createPostDescriptor() // void HelloVulkan::updatePostDescriptorSet() { - std::vector writes; - writes.emplace_back( - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor)); + std::vector writes; + writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor)); writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } ////////////////////////////////////////////////////////////////////////// -// Raytracing, creation of BLAS and TLAS +////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// //-------------------------------------------------------------------------------------------------- @@ -685,45 +640,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - // Building part - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - // The primitive itself - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; - // Our blas is only one geometry, but could be made of many geometries + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); @@ -746,7 +709,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -763,7 +726,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } @@ -776,12 +739,9 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createCompDescriptors() { - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer - 0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute)); - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO - 1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute)); - m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS - 2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute)); + m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer + m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO + m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); @@ -793,15 +753,17 @@ void HelloVulkan::createCompDescriptors() // void HelloVulkan::updateCompDescriptors() { - std::vector writes; + std::vector writes; writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor)); - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas}; + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -810,24 +772,29 @@ void HelloVulkan::updateCompDescriptors() void HelloVulkan::createCompPipelines() { // pushing time - vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(AoControl)}; - vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants}; - m_compPipelineLayout = m_device.createPipelineLayout(layout_info); - vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; + VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl)}; + VkPipelineLayoutCreateInfo plCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + plCreateInfo.setLayoutCount = 1; + plCreateInfo.pSetLayouts = &m_compDescSetLayout; + plCreateInfo.pushConstantRangeCount = 1; + plCreateInfo.pPushConstantRanges = &push_constants; + vkCreatePipelineLayout(m_device, &plCreateInfo, nullptr, &m_compPipelineLayout); - computePipelineCreateInfo.stage = - nvvk::createShaderStageInfo(m_device, - nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true), - VK_SHADER_STAGE_COMPUTE_BIT); - m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo).value; - m_device.destroy(computePipelineCreateInfo.stage.module); + VkComputePipelineCreateInfo cpCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + cpCreateInfo.layout = m_compPipelineLayout; + cpCreateInfo.stage = nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true), + VK_SHADER_STAGE_COMPUTE_BIT); + + vkCreateComputePipelines(m_device, {}, 1, &cpCreateInfo, nullptr, &m_compPipeline); + + vkDestroyShaderModule(m_device, cpCreateInfo.stage.module, nullptr); } //-------------------------------------------------------------------------------------------------- // Running compute shader // #define GROUP_SIZE 16 // Same group size as in compute shader -void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl) +void HelloVulkan::runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl) { updateFrame(); @@ -839,43 +806,38 @@ void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl) // Adding a barrier to be sure the fragment has finished writing to the G-Buffer // before the compute shader is using the buffer - vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; - vk::ImageMemoryBarrier imgMemBarrier; - imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); - imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - imgMemBarrier.setImage(m_gBuffer.image); - imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setSubresourceRange(range); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader, - vk::PipelineStageFlagBits::eComputeShader, - vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier}); + VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imgMemBarrier.image = m_gBuffer.image; + imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + imgMemBarrier.subresourceRange = range; + + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); // Preparing for the compute shader - cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0, - {m_compDescSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); + // Sending the push constant information aoControl.frame = m_frame; - cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, - sizeof(AoControl), &aoControl); + vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl); // Dispatching the shader - cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, - (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1); + vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1); // Adding a barrier to be sure the compute shader has finished // writing to the AO buffer before the post shader is using it - imgMemBarrier.setImage(m_aoBuffer.image); - imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); - imgMemBarrier.setSubresourceRange(range); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, - vk::PipelineStageFlagBits::eFragmentShader, - vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier}); + imgMemBarrier.image = m_aoBuffer.image; + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); + m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing_ao/hello_vulkan.h b/ray_tracing_ao/hello_vulkan.h index e498199..031ef2f 100644 --- a/ray_tracing_ao/hello_vulkan.h +++ b/ray_tracing_ao/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -46,25 +46,21 @@ struct AoControl // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -89,7 +85,7 @@ public: // Information pushed at each draw call struct ObjPushConstant { - nvmath::vec3f lightPosition{3.5f, 8.f, 5.f}; + nvmath::vec3f lightPosition{10.f, 15.f, 8.f}; int instanceId{0}; // To retrieve the transformation matrix float lightIntensity{100.f}; int lightType{0}; // 0: point, 1: infinite @@ -101,41 +97,43 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; + nvvk::Texture m_offscreenDepth; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; nvvk::Texture m_gBuffer; nvvk::Texture m_aoBuffer; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; - nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; // #Tuto_rayquery void initRayTracing(); @@ -143,22 +141,23 @@ public: void createBottomLevelAS(); void createTopLevelAS(); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; + + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; // #Tuto_animation void createCompDescriptors(); void updateCompDescriptors(); void createCompPipelines(); - void runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl); + void runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl); nvvk::DescriptorSetBindings m_compDescSetLayoutBind; - vk::DescriptorPool m_compDescPool; - vk::DescriptorSetLayout m_compDescSetLayout; - vk::DescriptorSet m_compDescSet; - vk::Pipeline m_compPipeline; - vk::PipelineLayout m_compPipelineLayout; + VkDescriptorPool m_compDescPool; + VkDescriptorSetLayout m_compDescSetLayout; + VkDescriptorSet m_compDescSet; + VkPipeline m_compPipeline; + VkPipelineLayout m_compPipelineLayout; // #Tuto_jitter_cam void updateFrame(); diff --git a/ray_tracing_ao/main.cpp b/ray_tracing_ao/main.cpp index c5073f2..f3a5533 100644 --- a/ray_tracing_ao/main.cpp +++ b/ray_tracing_ao/main.cpp @@ -25,9 +25,6 @@ #include #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE - #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -36,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -48,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -75,6 +72,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -89,8 +87,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -117,9 +114,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -129,19 +126,20 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeatures); - vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures; + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeatures); + VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR}; contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures); - // Creating Vulkan base application nvvk::Context vkctx{}; vkctx.initInstance(contextInfo); @@ -151,16 +149,14 @@ int main(int argc, char** argv) // Use a compatible device vkctx.initDevice(compatibleDevices[0], contextInfo); - // Create example HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -241,8 +237,7 @@ int main(int argc, char** argv) helloVk.resetFrame(); } - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -251,66 +246,67 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; // Offscreen render pass { - clearValues[1].setColor(std::array{0, 0, 0, 0}); - clearValues[2].setDepthStencil({1.0f, 0}); - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(3); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + clearValues[1].color = {{0, 0, 0, 0}}; + clearValues[2].depthStencil = {1.0f, 0}; + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = (uint32_t)clearValues.size(); + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); helloVk.runCompute(cmdBuf, aoControl); } } // 2nd rendering pass: tone mapper, UI { - clearValues[1].setDepthStencil({1.0f, 0}); - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + clearValues[1].depthStencil = {1.0f, 0}; + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } catch(const std::system_error& e) { - if(e.code() == vk::Result::eErrorDeviceLost) + if(e.code().value() == VK_ERROR_DEVICE_LOST) { #if _WIN32 MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1); @@ -322,10 +318,10 @@ int main(int argc, char** argv) } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_callable/CMakeLists.txt b/ray_tracing_callable/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_callable/CMakeLists.txt +++ b/ray_tracing_callable/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_callable/README.md b/ray_tracing_callable/README.md index 2f76db6..0d75992 100644 --- a/ray_tracing_callable/README.md +++ b/ray_tracing_callable/README.md @@ -63,39 +63,50 @@ executeCallableEXT(pushC.lightType, 0); In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit shader, we will add 3 callable shaders, for each type of light. +First create the shader modules +~~~~ C++ + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eCall0, + eCall1, + eCall2, + eShaderGroupCount + }; + + ... + // Call0 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall0] = stage; + // Call1 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall1] = stage; + // Call2 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall2] = stage; +~~~~ + +Then 3 groups of callable shaders and the stages that goes with it. + ~~~~ C++ // Callable shaders - vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - - vk::ShaderModule call0 = - nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/light_point.rcall.spv", true, paths)); - vk::ShaderModule call1 = - nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/light_spot.rcall.spv", true, paths)); - vk::ShaderModule call2 = - nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths)); - - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); - m_rtShaderGroups.push_back(callGroup); - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); - m_rtShaderGroups.push_back(callGroup); - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); - m_rtShaderGroups.push_back(callGroup); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = eCall0; + m_rtShaderGroups.push_back(group); + group.generalShader = eCall1; + m_rtShaderGroups.push_back(group); + group.generalShader = eCall2; + m_rtShaderGroups.push_back(group); ~~~~ -And at the end of the function, delete the shaders. -~~~~ C++ -m_device.destroy(call0); -m_device.destroy(call1); -m_device.destroy(call2); -~~~~ #### Shaders @@ -106,29 +117,44 @@ Here are the source of all shaders * [light_inf.rcall](shaders/light_inf.rcall) -### Passing Callable to traceRaysKHR +### Shading Binding Table + +In this example, we will use the `nvvk::SBTWrapper`. It is using the information to create the ray tracing pipeline, to +create the buffers for the shading binding table. + +In the `hello_vulkan.h` header, include the wrapper and add a new member. + +~~~~C +#include "nvvk/sbtwrapper_vk.hpp" +... +nvvk::SBTWrapper m_sbtWrapper; +~~~~ + +In `HelloVulkan::initRayTracing()`, initialize it the following way. + +~~~~C +m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); +~~~~ + +In `HelloVulkan::createRtPipeline()`, immediately after creating the pipeline call to `vkCreateRayTracingPipelinesKHR()`, +create the SBT with the following command. + +~~~~C + m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); +~~~~ + + In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Since they were added after the hit shader, we have in the SBT the following. ![SBT](images/sbt.png) - -Therefore, the callable starts at `4 * progSize` +The SBT wrapper class give back the information we need. So instead of computing the various offsets, we can get directly the +`VkStridedDeviceAddressRegionKHR` for each group type. ~~~~ C++ - std::array strideAddresses{ - stride{sbtAddress + 0u * progSize, progSize, progSize * 1}, // raygen - stride{sbtAddress + 1u * progSize, progSize, progSize * 2}, // miss - stride{sbtAddress + 3u * progSize, progSize, progSize * 1}, // hit - stride{sbtAddress + 4u * progSize, progSize, progSize * 1}}; // callable -~~~~ - -Then we can call `traceRaysKHR` - -~~~~ C++ - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - &strideAddresses[3], // - m_size.width, m_size.height, 1); // + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); ~~~~ ## Calling the Callable Shaders diff --git a/ray_tracing_callable/hello_vulkan.cpp b/ray_tracing_callable/hello_vulkan.cpp index 415268c..a882a88 100644 --- a/ray_tracing_callable/hello_vulkan.cpp +++ b/ray_tracing_callable/hello_vulkan.cpp @@ -19,26 +19,25 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" -#include "nvh//cameramanipulator.hpp" +#include "nvh/alignment.hpp" +#include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/alignment.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -50,17 +49,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -68,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -115,33 +112,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -154,25 +145,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -180,7 +171,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -188,40 +179,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -233,8 +222,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -258,18 +245,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -285,17 +268,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -307,11 +288,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -320,15 +300,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -336,18 +316,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -360,8 +339,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -374,16 +352,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -398,10 +375,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -419,23 +397,23 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_sbtWrapper.destroy(); m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); - m_alloc.destroy(m_rtSBTBuffer); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.deinit(); } @@ -443,32 +421,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -498,29 +475,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -529,11 +505,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -541,24 +515,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -567,26 +540,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -596,11 +566,7 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); @@ -611,28 +577,24 @@ void HelloVulkan::createPostDescriptor() // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -647,51 +609,65 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - // Consider the geometry opaque for optimization - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } +//-------------------------------------------------------------------------------------------------- +// +// void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry @@ -704,7 +680,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -721,7 +697,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -729,30 +705,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -762,13 +741,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -777,121 +753,139 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eCall0, + eCall1, + eCall2, + eShaderGroupCount + }; + + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; + // Call0 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall0] = stage; + // Call1 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall1] = stage; + // Call2 + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; + stages[eCall2] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); // Callable shaders - vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = eCall0; + m_rtShaderGroups.push_back(group); + group.generalShader = eCall1; + m_rtShaderGroups.push_back(group); + group.generalShader = eCall2; + m_rtShaderGroups.push_back(group); - vk::ShaderModule call0 = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); - vk::ShaderModule call1 = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); - vk::ShaderModule call2 = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); - - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); - m_rtShaderGroups.push_back(callGroup); - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); - m_rtShaderGroups.push_back(callGroup); - callGroup.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); - m_rtShaderGroups.push_back(callGroup); - - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR - | vk::ShaderStageFlagBits::eCallableKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR + | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); - - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); - m_device.destroy(call0); - m_device.destroy(call1); - m_device.destroy(call2); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -903,20 +897,19 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightSpotOuterCutoff = m_pushConstant.lightSpotOuterCutoff; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR - | vk::ShaderStageFlagBits::eCallableKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR + | VK_SHADER_STAGE_CALLABLE_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); - auto regions = m_sbtWrapper.getRegions(); - cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], // - m_size.width, m_size.height, 1); // + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_callable/hello_vulkan.h b/ray_tracing_callable/hello_vulkan.h index 9288e53..2e1dc7f 100644 --- a/ray_tracing_callable/hello_vulkan.h +++ b/ray_tracing_callable/hello_vulkan.h @@ -19,17 +19,16 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/sbtwrapper_vk.hpp" - //-------------------------------------------------------------------------------------------------- // Simple rasterizer of OBJ objects // - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` @@ -37,25 +36,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -95,39 +90,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -137,19 +134,18 @@ public: void createRtDescriptorSet(); void updateRtDescriptorSet(); void createRtPipeline(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; struct RtPushConstant { diff --git a/ray_tracing_callable/main.cpp b/ray_tracing_callable/main.cpp index eb8d591..4dcd750 100644 --- a/ray_tracing_callable/main.cpp +++ b/ray_tracing_callable/main.cpp @@ -23,18 +23,15 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE - #include "backends/imgui_impl_glfw.h" -#include "hello_vulkan.h" #include "imgui.h" + +#include "hello_vulkan.h" #include "imgui/imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -56,7 +54,7 @@ static void onErrorCallback(int error, const char* description) void renderUI(HelloVulkan& helloVk) { ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen)) + if(ImGui::CollapsingHeader("Light")) { ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::SameLine(); @@ -104,8 +102,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -132,12 +129,13 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); + contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); #ifdef _WIN32 - contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, false); + contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else - contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, false); - contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, false); + contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME); #endif contextInfo.addInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); @@ -145,18 +143,16 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); - // Creating Vulkan base application nvvk::Context vkctx{}; @@ -171,11 +167,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -234,8 +229,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -244,28 +238,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -274,40 +269,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_gltf/CMakeLists.txt b/ray_tracing_gltf/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_gltf/CMakeLists.txt +++ b/ray_tracing_gltf/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_gltf/README.md b/ray_tracing_gltf/README.md index df21454..2a18b14 100644 --- a/ray_tracing_gltf/README.md +++ b/ray_tracing_gltf/README.md @@ -128,9 +128,10 @@ attributes, we will store the offsets information of that geometry. // The following is used to find the primitive mesh information in the CHIT std::vector primLookup; for(auto& primMesh : m_gltfScene.m_primMeshes) + { primLookup.push_back({primMesh.firstIndex, primMesh.vertexOffset, primMesh.materialIndex}); - m_rtPrimLookup = - m_alloc.createBuffer(cmdBuf, primLookup, vk::BufferUsageFlagBits::eStorageBuffer); + } + m_rtPrimLookup = m_alloc.createBuffer(cmdBuf, primLookup, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); ~~~~ @@ -145,35 +146,45 @@ The function is similar, only the input is different. // auto HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim) { - // Building part - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = m_indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(nvmath::vec3f)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(prim.vertexCount); + uint32_t maxPrimitiveCount = prim.indexCount / 3; - // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(nvmath::vec3f); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = prim.vertexCount; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(prim.vertexOffset); - offset.setPrimitiveCount(prim.indexCount / 3); - offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t)); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit + asGeom.geometry.triangles = triangles; - nvvk::RaytracingBuilderKHR::Blas blas; - blas.asGeometry.emplace_back(asGeom); - blas.asBuildOffsetInfo.emplace_back(offset); - return blas; + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = prim.vertexOffset; + offset.primitiveCount = prim.indexCount / 3; + offset.primitiveOffset = prim.firstIndex * sizeof(uint32_t); + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries + nvvk::RaytracingBuilderKHR::BlasInput input; + input.asGeometry.emplace_back(asGeom); + input.asBuildOffsetInfo.emplace_back(offset); + + return input; } ~~~~ @@ -207,11 +218,9 @@ each node, we will be pushing the instance Id (retrieve the matrix) and the mate don't have a scene graph, we could loop over all drawable nodes. ~~~~C - std::vector vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer, - m_uvBuffer.buffer}; - cmdBuf.bindVertexBuffers(0, static_cast(vertexBuffers.size()), vertexBuffers.data(), - offsets.data()); - cmdBuf.bindIndexBuffer(m_indexBuffer.buffer, 0, vk::IndexType::eUint32); + std::vector vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer, m_uvBuffer.buffer}; + vkCmdBindVertexBuffers(cmdBuf, 0, static_cast(vertexBuffers.size()), vertexBuffers.data(), offsets.data()); + vkCmdBindIndexBuffer(cmdBuf, m_indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); uint32_t idxNode = 0; for(auto& node : m_gltfScene.m_nodes) @@ -220,10 +229,9 @@ don't have a scene graph, we could loop over all drawable nodes. m_pushConstant.instanceId = idxNode++; m_pushConstant.materialId = primitive.materialIndex; - cmdBuf.pushConstants( - m_pipelineLayout, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, - m_pushConstant); - cmdBuf.drawIndexed(primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdDrawIndexed(cmdBuf, primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0); } ~~~~ @@ -234,12 +242,12 @@ In `createRtDescriptorSet()`, the only change we will add is the primitive info the data when hitting a triangle. ~~~~C -m_rtDescSetLayoutBind.addBinding( - vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eClosestHitNV | vkSS::eAnyHitNV)); // Primitive info -.... -vk::DescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE}; -.... -writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &primitiveInfoDesc)); + m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Primitive info +// ... + VkDescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE}; +// ... + writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &primitiveInfoDesc)); ~~~~ diff --git a/ray_tracing_gltf/hello_vulkan.cpp b/ray_tracing_gltf/hello_vulkan.cpp index 0685f89..07d06f6 100644 --- a/ray_tracing_gltf/hello_vulkan.cpp +++ b/ray_tracing_gltf/hello_vulkan.cpp @@ -19,9 +19,7 @@ #include -#include -extern std::vector defaultSearchPaths; #define TINYGLTF_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION @@ -44,6 +42,7 @@ extern std::vector defaultSearchPaths; #include "shaders/binding.glsl" #include "shaders/gltf.glsl" +extern std::vector defaultSearchPaths; // Holding the camera matrices struct CameraMatrices @@ -55,17 +54,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -73,46 +70,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -120,27 +117,20 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - auto& bind = m_descSetLayoutBind; // Camera matrices (binding = 0) - bind.addBinding(vkDS(B_CAMERA, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); - bind.addBinding( - vkDS(B_VERTICES, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); - bind.addBinding( - vkDS(B_INDICES, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); - bind.addBinding(vkDS(B_NORMALS, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR)); - bind.addBinding(vkDS(B_TEXCOORDS, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR)); - bind.addBinding(vkDS(B_MATERIALS, vkDT::eStorageBuffer, 1, - vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); - bind.addBinding(vkDS(B_MATRICES, vkDT::eStorageBuffer, 1, - vkSS::eVertex | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); + bind.addBinding(B_CAMERA, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); + bind.addBinding(B_VERTICES, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); + bind.addBinding(B_INDICES, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); + bind.addBinding(B_NORMALS, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + bind.addBinding(B_TEXCOORDS, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + bind.addBinding(B_MATERIALS, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); + bind.addBinding(B_MATRICES, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); auto nbTextures = static_cast(m_textures.size()); - bind.addBinding(vkDS(B_TEXTURES, vkDT::eCombinedImageSampler, nbTextures, - vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); - + bind.addBinding(B_TEXTURES, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTextures, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descPool = m_descSetLayoutBind.createPool(m_device, 1); @@ -152,16 +142,16 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; - vk::DescriptorBufferInfo vertexDesc{m_vertexBuffer.buffer, 0, VK_WHOLE_SIZE}; - vk::DescriptorBufferInfo indexDesc{m_indexBuffer.buffer, 0, VK_WHOLE_SIZE}; - vk::DescriptorBufferInfo normalDesc{m_normalBuffer.buffer, 0, VK_WHOLE_SIZE}; - vk::DescriptorBufferInfo uvDesc{m_uvBuffer.buffer, 0, VK_WHOLE_SIZE}; - vk::DescriptorBufferInfo materialDesc{m_materialBuffer.buffer, 0, VK_WHOLE_SIZE}; - vk::DescriptorBufferInfo matrixDesc{m_matrixBuffer.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo vertexDesc{m_vertexBuffer.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo indexDesc{m_indexBuffer.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo normalDesc{m_normalBuffer.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo uvDesc{m_uvBuffer.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo materialDesc{m_materialBuffer.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo matrixDesc{m_matrixBuffer.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, B_CAMERA, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, B_VERTICES, &vertexDesc)); @@ -172,46 +162,43 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, B_MATRICES, &matrixDesc)); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) diit.emplace_back(texture.descriptor); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, B_TEXTURES, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); - gpb.addBindingDescriptions( - {{0, sizeof(nvmath::vec3)}, {1, sizeof(nvmath::vec3)}, {2, sizeof(nvmath::vec2)}}); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + gpb.addBindingDescriptions({{0, sizeof(nvmath::vec3)}, {1, sizeof(nvmath::vec3)}, {2, sizeof(nvmath::vec2)}}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, 0}, // Position - {1, 1, vk::Format::eR32G32B32Sfloat, 0}, // Normal - {2, 2, vk::Format::eR32G32Sfloat, 0}, // Texcoord0 + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}, // Position + {1, 1, VK_FORMAT_R32G32B32_SFLOAT, 0}, // Normal + {2, 2, VK_FORMAT_R32G32_SFLOAT, 0}, // Texcoord0 }); m_graphicsPipeline = gpb.createPipeline(); m_debug.setObjectName(m_graphicsPipeline, "Graphics"); @@ -222,7 +209,7 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadScene(const std::string& filename) { - using vkBU = vk::BufferUsageFlagBits; + using vkBU = VkBufferUsageFlagBits; tinygltf::Model tmodel; tinygltf::TinyGLTF tcontext; std::string warn, error; @@ -237,34 +224,30 @@ void HelloVulkan::loadScene(const std::string& filename) m_gltfScene.importMaterials(tmodel); - m_gltfScene.importDrawableNodes(tmodel, - nvh::GltfAttributes::Normal | nvh::GltfAttributes::Texcoord_0); + m_gltfScene.importDrawableNodes(tmodel, nvh::GltfAttributes::Normal | nvh::GltfAttributes::Texcoord_0); // Create the buffers on Device and copy vertices, indices and materials nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - m_vertexBuffer = - m_alloc.createBuffer(cmdBuf, m_gltfScene.m_positions, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - m_indexBuffer = - m_alloc.createBuffer(cmdBuf, m_gltfScene.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); + m_vertexBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_positions, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); + m_indexBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_indices, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); m_normalBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_normals, - vkBU::eVertexBuffer | vkBU::eStorageBuffer); + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); m_uvBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_texcoords0, - vkBU::eVertexBuffer | vkBU::eStorageBuffer); + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Copying all materials, only the elements we need std::vector shadeMaterials; for(auto& m : m_gltfScene.m_materials) { - shadeMaterials.emplace_back( - GltfShadeMaterial{m.baseColorFactor, m.baseColorTexture, m.emissiveFactor}); + shadeMaterials.emplace_back(GltfShadeMaterial{m.baseColorFactor, m.baseColorTexture, m.emissiveFactor}); } - m_materialBuffer = m_alloc.createBuffer(cmdBuf, shadeMaterials, vkBU::eStorageBuffer); + m_materialBuffer = m_alloc.createBuffer(cmdBuf, shadeMaterials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Instance Matrices used by rasterizer std::vector nodeMatrices; @@ -272,7 +255,7 @@ void HelloVulkan::loadScene(const std::string& filename) { nodeMatrices.emplace_back(node.worldMatrix); } - m_matrixBuffer = m_alloc.createBuffer(cmdBuf, nodeMatrices, vkBU::eStorageBuffer); + m_matrixBuffer = m_alloc.createBuffer(cmdBuf, nodeMatrices, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // The following is used to find the primitive mesh information in the CHIT std::vector primLookup; @@ -280,8 +263,7 @@ void HelloVulkan::loadScene(const std::string& filename) { primLookup.push_back({primMesh.firstIndex, primMesh.vertexOffset, primMesh.materialIndex}); } - m_rtPrimLookup = - m_alloc.createBuffer(cmdBuf, primLookup, vk::BufferUsageFlagBits::eStorageBuffer); + m_rtPrimLookup = m_alloc.createBuffer(cmdBuf, primLookup, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found @@ -304,32 +286,31 @@ void HelloVulkan::loadScene(const std::string& filename) // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, tinygltf::Model& gltfModel) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, tinygltf::Model& gltfModel) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; auto addDefaultTexture = [this]() { // Make dummy image(1,1), needed as we cannot have an empty array nvvk::ScopeCommandBuffer cmdBuf(m_device, m_graphicsQueueIndex); std::array white = {255, 255, 255, 255}; - m_textures.emplace_back(m_alloc.createTexture( - cmdBuf, 4, white.data(), nvvk::makeImage2DCreateInfo(vk::Extent2D{1, 1}), {})); + + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_textures.emplace_back(m_alloc.createTexture(cmdBuf, 4, white.data(), nvvk::makeImage2DCreateInfo(VkExtent2D{1, 1}), sampler)); m_debug.setObjectName(m_textures.back().image, "dummy"); }; @@ -345,7 +326,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, tinygltf: auto& gltfimage = gltfModel.images[i]; void* buffer = &gltfimage.image[0]; VkDeviceSize bufferSize = gltfimage.image.size(); - auto imgSize = vk::Extent2D(gltfimage.width, gltfimage.height); + auto imgSize = VkExtent2D{(uint32_t)gltfimage.width, (uint32_t)gltfimage.height}; if(bufferSize == 0 || gltfimage.width == -1 || gltfimage.height == -1) { @@ -353,12 +334,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, tinygltf: continue; } - vk::ImageCreateInfo imageCreateInfo = - nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkImageCreateInfo imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, buffer, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); m_textures.emplace_back(m_alloc.createTexture(image, ivInfo, samplerCreateInfo)); m_debug.setObjectName(m_textures[i].image, std::string("Txt" + std::to_string(i)).c_str()); @@ -370,10 +350,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, tinygltf: // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_vertexBuffer); @@ -390,22 +371,23 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); // #VKRay m_rtBuilder.destroy(); m_sbtWrapper.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); + m_alloc.deinit(); } @@ -413,26 +395,24 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; + using vkPBP = VkPipelineBindPoint; - std::vector offsets = {0, 0, 0}; + std::vector offsets = {0, 0, 0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); - std::vector vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer, - m_uvBuffer.buffer}; - cmdBuf.bindVertexBuffers(0, static_cast(vertexBuffers.size()), vertexBuffers.data(), - offsets.data()); - cmdBuf.bindIndexBuffer(m_indexBuffer.buffer, 0, vk::IndexType::eUint32); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + std::vector vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer, m_uvBuffer.buffer}; + vkCmdBindVertexBuffers(cmdBuf, 0, static_cast(vertexBuffers.size()), vertexBuffers.data(), offsets.data()); + vkCmdBindIndexBuffer(cmdBuf, m_indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); uint32_t idxNode = 0; for(auto& node : m_gltfScene.m_nodes) @@ -441,10 +421,9 @@ void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) m_pushConstant.instanceId = idxNode++; m_pushConstant.materialId = primitive.materialIndex; - cmdBuf.pushConstants( - m_pipelineLayout, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, - m_pushConstant); - cmdBuf.drawIndexed(primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdDrawIndexed(cmdBuf, primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0); } m_debug.endLabel(cmdBuf); @@ -461,10 +440,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) resetFrame(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -476,29 +457,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -507,11 +487,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -519,24 +497,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -545,26 +522,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -574,43 +548,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -625,10 +592,10 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); } @@ -638,34 +605,44 @@ void HelloVulkan::initRayTracing() // auto HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim) { - // Building part - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = m_indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(nvmath::vec3f)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(prim.vertexCount); + uint32_t maxPrimitiveCount = prim.indexCount / 3; - // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(nvmath::vec3f); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = prim.vertexCount; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(prim.vertexOffset); - offset.setPrimitiveCount(prim.indexCount / 3); - offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t)); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit + asGeom.geometry.triangles = triangles; + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = prim.vertexOffset; + offset.primitiveCount = prim.indexCount / 3; + offset.primitiveOffset = prim.firstIndex * sizeof(uint32_t); + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } @@ -682,7 +659,7 @@ void HelloVulkan::createBottomLevelAS() auto geo = primitiveToGeometry(primMesh); allBlas.push_back({geo}); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -699,7 +676,7 @@ void HelloVulkan::createTopLevelAS() rayInst.hitGroupId = 0; // We will use the same hit group for all objects tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -707,34 +684,37 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image - m_rtDescSetLayoutBind.addBinding(vkDSLB( - 2, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); // Primitive info + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image + m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Primitive info m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::DescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkDescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &primitiveInfoDesc)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -744,13 +724,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -759,97 +736,116 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/pathtrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/pathtrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pathtrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pathtrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pathtrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/pathtrace.rchit.spv", true, defaultSearchPaths, true)); + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); - - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); // Creating the SBT m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { updateFrame(); @@ -860,19 +856,18 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); - auto regions = m_sbtWrapper.getRegions(); - cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], // - m_size.width, m_size.height, 1); + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_gltf/hello_vulkan.h b/ray_tracing_gltf/hello_vulkan.h index c087608..2a73041 100644 --- a/ray_tracing_gltf/hello_vulkan.h +++ b/ray_tracing_gltf/hello_vulkan.h @@ -18,13 +18,12 @@ */ #pragma once -#include - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvh/gltfscene.hpp" @@ -38,23 +37,20 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadScene(const std::string& filename); void updateDescriptorSet(); void createUniformBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, tinygltf::Model& gltfModel); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, tinygltf::Model& gltfModel); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // Structure used for retrieving the primitive information in the closest hit // The gl_InstanceCustomIndexNV @@ -87,12 +83,12 @@ public: ObjPushConstant m_pushConstant; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices std::vector m_textures; // vector of all textures of the scene @@ -105,20 +101,20 @@ public: void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay auto primitiveToGeometry(const nvh::GltfPrimMesh& prim); @@ -128,20 +124,20 @@ public: void createRtDescriptorSet(); void updateRtDescriptorSet(); void createRtPipeline(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void updateFrame(); void resetFrame(); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::SBTWrapper m_sbtWrapper; struct RtPushConstant { diff --git a/ray_tracing_gltf/main.cpp b/ray_tracing_gltf/main.cpp index bdebee0..3abd531 100644 --- a/ray_tracing_gltf/main.cpp +++ b/ray_tracing_gltf/main.cpp @@ -23,8 +23,6 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -87,8 +86,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -115,9 +113,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -127,20 +125,20 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - vk::PhysicalDeviceShaderClockFeaturesKHR clockFeature; + VkPhysicalDeviceShaderClockFeaturesKHR clockFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR}; contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_EXTENSION_NAME, false, &clockFeature); - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); - // Creating Vulkan base application nvvk::Context vkctx{}; @@ -151,16 +149,14 @@ int main(int argc, char** argv) // Use a compatible device vkctx.initDevice(compatibleDevices[0], contextInfo); - // Create example HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -209,6 +205,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -217,8 +214,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -227,28 +223,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -257,40 +254,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_indirect_scissor/CMakeLists.txt b/ray_tracing_indirect_scissor/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_indirect_scissor/CMakeLists.txt +++ b/ray_tracing_indirect_scissor/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_indirect_scissor/hello_vulkan.cpp b/ray_tracing_indirect_scissor/hello_vulkan.cpp index 385a117..fc27dcc 100644 --- a/ray_tracing_indirect_scissor/hello_vulkan.cpp +++ b/ray_tracing_indirect_scissor/hello_vulkan.cpp @@ -19,9 +19,7 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" @@ -37,6 +35,9 @@ extern std::vector defaultSearchPaths; #include "nvvk/pipeline_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +#include "nvvk/buffers_vk.hpp" + +extern std::vector defaultSearchPaths; // Holding the camera matrices @@ -54,13 +55,10 @@ struct CameraMatrices // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -68,81 +66,74 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; - hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.view = getViewMatrix(); + hostUBO.proj = getProjMatrix(); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } - //-------------------------------------------------------------------------------------------------- // Describing the layout pushed when rendering // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -155,25 +146,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -181,7 +172,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -189,40 +180,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -234,8 +223,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -259,18 +246,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -300,11 +283,8 @@ void HelloVulkan::addLantern(nvmath::vec3f pos, nvmath::vec3f color, float brigh // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -316,11 +296,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -329,15 +308,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -345,18 +324,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -369,8 +347,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -383,16 +360,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -407,10 +383,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -428,27 +405,27 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); // #VKRay m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.destroy(m_rtSBTBuffer); - m_device.destroy(m_lanternIndirectDescPool); - m_device.destroy(m_lanternIndirectDescSetLayout); - m_device.destroy(m_lanternIndirectCompPipeline); - m_device.destroy(m_lanternIndirectCompPipelineLayout); + vkDestroyDescriptorPool(m_device, m_lanternIndirectDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_lanternIndirectDescSetLayout, nullptr); + vkDestroyPipeline(m_device, m_lanternIndirectCompPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_lanternIndirectCompPipelineLayout, nullptr); m_alloc.destroy(m_lanternIndirectBuffer); m_alloc.destroy(m_lanternVertexBuffer); m_alloc.destroy(m_lanternIndexBuffer); @@ -459,32 +436,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -499,10 +475,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -514,29 +492,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -545,11 +522,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -557,24 +532,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -583,26 +557,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -612,43 +583,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -663,10 +627,10 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } @@ -676,35 +640,35 @@ void HelloVulkan::initRayTracing() auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { // BLAS builder requires raw device addresses. - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); + VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); uint32_t maxPrimitiveCount = model.nbIndices / 3; // Describe buffer as array of VertexObj. - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data. - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); // Describe index data (32-bit unsigned int) - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; // Indicate identity transform by setting transformData to null device pointer. - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; // Identify the above data as containing opaque triangles. - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; // The entire array will be used to build the BLAS. - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(maxPrimitiveCount); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; @@ -716,8 +680,7 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) // Tesselate a sphere as a list of triangles; return its // vertices and indices as reference arguments. -void HelloVulkan::fillLanternVerts(std::vector& vertices, - std::vector& indices) +void HelloVulkan::fillLanternVerts(std::vector& vertices, std::vector& indices) { // Create a spherical lantern model by recursively tesselating an octahedron. struct VertexIndex @@ -739,9 +702,8 @@ void HelloVulkan::fillLanternVerts(std::vector& vertices, uint32_t vertexCount = 6; // Initial triangle list is octahedron. - std::vector triangles{{posX, posY, posZ}, {posX, posY, negZ}, {posX, negY, posZ}, - {posX, negY, negZ}, {negX, posY, posZ}, {negX, posY, negZ}, - {negX, negY, posZ}, {negX, negY, negZ}}; + std::vector triangles{{posX, posY, posZ}, {posX, posY, negZ}, {posX, negY, posZ}, {posX, negY, negZ}, + {negX, posY, posZ}, {negX, posY, negZ}, {negX, negY, posZ}, {negX, negY, negZ}}; // Recursion: every iteration, convert the current model to a new // model by breaking each triangle into 4 triangles. @@ -753,12 +715,9 @@ void HelloVulkan::fillLanternVerts(std::vector& vertices, // Split each of three edges in half, then fixup the // length of the midpoint to match m_lanternModelRadius. // Record the index the new vertices will eventually have in vertices. - VertexIndex v01{m_lanternModelRadius * nvmath::normalize(t.vert0.vertex + t.vert1.vertex), - vertexCount++}; - VertexIndex v12{m_lanternModelRadius * nvmath::normalize(t.vert1.vertex + t.vert2.vertex), - vertexCount++}; - VertexIndex v02{m_lanternModelRadius * nvmath::normalize(t.vert0.vertex + t.vert2.vertex), - vertexCount++}; + VertexIndex v01{m_lanternModelRadius * nvmath::normalize(t.vert0.vertex + t.vert1.vertex), vertexCount++}; + VertexIndex v12{m_lanternModelRadius * nvmath::normalize(t.vert1.vertex + t.vert2.vertex), vertexCount++}; + VertexIndex v02{m_lanternModelRadius * nvmath::normalize(t.vert0.vertex + t.vert2.vertex), vertexCount++}; // Old triangle becomes 4 new triangles. new_triangles.push_back({t.vert0, v01, v02}); @@ -791,7 +750,7 @@ void HelloVulkan::fillLanternVerts(std::vector& vertices, // m_lanternIndexBuffer: packed VkBuffer of 32-bit indices // m_lanternBlasInput: BLAS for spherical lantern // -// NOTE: A more elegant way to do this is to use a procedular hit group instead, +// NOTE: A more elegant way to do this is to use a procedural hit group instead, // then, this BLAS can just be one AABB. I wanted to avoid introducing the new // concept of intersection shaders here. void HelloVulkan::createLanternModel() @@ -801,10 +760,8 @@ void HelloVulkan::createLanternModel() fillLanternVerts(vertices, indices); // Upload vertex and index data to buffers. - auto usageFlags = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR - | vk::BufferUsageFlagBits::eShaderDeviceAddress; - auto memFlags = - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + auto usageFlags = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + auto memFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; auto vertexBytes = vertices.size() * sizeof vertices[0]; m_lanternVertexBuffer = m_alloc.createBuffer(vertexBytes, usageFlags, memFlags); @@ -819,35 +776,35 @@ void HelloVulkan::createLanternModel() m_alloc.unmap(m_lanternIndexBuffer); // Package vertex and index buffers as BlasInput. - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_lanternVertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_lanternIndexBuffer.buffer}); + VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternVertexBuffer.buffer); + VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternIndexBuffer.buffer); auto maxPrimitiveCount = uint32_t(indices.size() / 3); // Describe buffer as packed array of float vec3. - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data. - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(nvmath::vec3f)); + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(nvmath::vec3f); // Describe index data (32-bit unsigned int) - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; // Indicate identity transform by setting transformData to null device pointer. - triangles.setTransformData({}); - triangles.setMaxVertex(uint32_t(vertices.size())); + //triangles.transformData = {}; + triangles.maxVertex = uint32_t(vertices.size()); // Identify the above data as containing opaque triangles. - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; // The entire array will be used to build the BLAS. - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(maxPrimitiveCount); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; // Our blas is made from only one geometry, but could be made of many geometries m_lanternBlasInput.asGeometry.emplace_back(asGeom); @@ -879,7 +836,7 @@ void HelloVulkan::createBottomLevelAS() m_lanternBlasId = allBlas.size(); allBlas.emplace_back(m_lanternBlasInput); - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } // Build the TLAS in m_rtBuilder. Requires that the BLASes were already built and @@ -920,7 +877,7 @@ void HelloVulkan::createTopLevelAS() tlas.emplace_back(lanternInstance); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -928,40 +885,39 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - // TLAS (binding = 0) - m_rtDescSetLayoutBind.addBinding( - vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); - // Output image (binding = 1) - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image - + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image // Lantern buffer (binding = 2) - m_rtDescSetLayoutBind.addBinding( // - vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); + m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); assert(m_lanternCount > 0); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::DescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, - m_lanternCount * sizeof(LanternIndirectEntry)}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &lanternBufferInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -971,13 +927,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -1032,138 +985,150 @@ void HelloVulkan::updateRtDescriptorSet() // 8 ===================================================================================== void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMissShd, + eMissLantern, + eClosestHit, + eClosestHitLantern, + eClosestHitLanternShdObj, + eClosestHitLanternShd, + eShaderGroupCount + }; + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; // Miss shader 0 invoked when a primary ray doesn't hit geometry. Fills in clear color. - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; // Miss shader 1 is invoked when a shadow ray (for the main scene light) // misses the geometry. It simply indicates that no occlusion has been found. - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMissShd] = stage; // Miss shader 2 is invoked when a shadow ray for lantern lighting misses the // lantern. It shouldn't be invoked, but I include it just in case. - vk::ShaderModule lanternmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true)); - - std::vector stages; - - // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); - // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); - - // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); - - // Lantern Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, lanternmissSM, "main"}); - m_rtShaderGroups.push_back(mg); - - // OBJ Primary Ray Hit Group - Closest Hit + AnyHit (not used) - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMissLantern] = stage; + // OBJ Primary Ray Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; // Lantern Primary Ray Hit Group - vk::ShaderModule lanternChitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR lanternHg{ - vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - lanternHg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"}); - m_rtShaderGroups.push_back(lanternHg); + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHitLantern] = stage; // OBJ Lantern Shadow Ray Hit Group - vk::ShaderModule lanternShadowObjChitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true)); + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHitLanternShdObj] = stage; - vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{ - vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - lanternShadowObjHg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"}); - m_rtShaderGroups.push_back(lanternShadowObjHg); // Lantern Lantern Shadow Ray Hit Group - vk::ShaderModule lanternShadowLanternChitSM = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowLantern.rchit.spv", true, - defaultSearchPaths, true)); + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowLantern.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHitLanternShd] = stage; - vk::RayTracingShaderGroupCreateInfoKHR lanternShadowLanternHg{ - vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - lanternShadowLanternHg.setClosestHitShader(static_cast(stages.size())); - stages.push_back( - {{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"}); - m_rtShaderGroups.push_back(lanternShadowLanternHg); - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; + + // Raygen + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + + // Miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + + // Shadow Miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMissShd; + m_rtShaderGroups.push_back(group); + + // Lantern Shadow Miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMissLantern; + m_rtShaderGroups.push_back(group); + + + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); + + + group.closestHitShader = eClosestHitLantern; + m_rtShaderGroups.push_back(group); + + group.closestHitShader = eClosestHitLanternShdObj; + m_rtShaderGroups.push_back(group); + + group.closestHitShader = eClosestHitLanternShd; + m_rtShaderGroups.push_back(group); + // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - // In this case, m_rtShaderGroups.size() == 8: we have one raygen group, - // three miss shader groups, and four hit groups. - rayPipelineInfo.setGroupCount(static_cast(m_rtShaderGroups.size())); - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); - - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(lanternmissSM); - m_device.destroy(chitSM); - m_device.destroy(lanternChitSM); - m_device.destroy(lanternShadowObjChitSM); - m_device.destroy(lanternShadowLanternChitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -1179,24 +1144,22 @@ void HelloVulkan::createRtShaderBindingTable() uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = - nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; // Fetch all the shader handles used in the pipeline. This is opaque data, // so we store it in a vector of bytes. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + + assert(result == VK_SUCCESS); // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer( - sbtSize, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress - | vk::BufferUsageFlagBits::eShaderBindingTableKHR, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Map the SBT buffer and write in the handles. @@ -1216,27 +1179,25 @@ void HelloVulkan::createRtShaderBindingTable() // The compute shader just needs read/write access to the buffer of LanternIndirectEntry. void HelloVulkan::createLanternIndirectDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - // Lantern buffer (binding = 0) - m_lanternIndirectDescSetLayoutBind.addBinding( // - vkDSLB(0, vkDT::eStorageBuffer, 1, vkSS::eCompute)); + m_lanternIndirectDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device); m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device); - m_lanternIndirectDescSet = m_device.allocateDescriptorSets( - {m_lanternIndirectDescPool, 1, &m_lanternIndirectDescSetLayout})[0]; + + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_lanternIndirectDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_lanternIndirectDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_lanternIndirectDescSet); + assert(m_lanternIndirectBuffer.buffer); - vk::DescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, - m_lanternCount * sizeof(LanternIndirectEntry)}; + VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)}; - std::vector writes; - writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, - &lanternBufferInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + std::vector writes; + writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, &lanternBufferInfo)); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } // Create compute pipeline used to fill m_lanternIndirectBuffer with parameters @@ -1244,32 +1205,31 @@ void HelloVulkan::createLanternIndirectDescriptorSet() void HelloVulkan::createLanternIndirectCompPipeline() { // Compile compute shader and package as stage. - vk::ShaderModule computeShader = nvvk::createShaderModule( - m_device, // - nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true)); - vk::PipelineShaderStageCreateInfo stageInfo; - stageInfo.setStage(vk::ShaderStageFlagBits::eCompute); - stageInfo.setModule(computeShader); - stageInfo.setPName("main"); + VkShaderModule computeShader = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true)); + VkPipelineShaderStageCreateInfo stageInfo{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stageInfo.module = computeShader; + stageInfo.pName = "main"; // Set up push constant and pipeline layout. - constexpr auto pushSize = static_cast(sizeof(m_lanternIndirectPushConstants)); - vk::PushConstantRange pushCRange = {vk::ShaderStageFlagBits::eCompute, 0, pushSize}; + constexpr auto pushSize = static_cast(sizeof(m_lanternIndirectPushConstants)); + VkPushConstantRange pushCRange = {VK_SHADER_STAGE_COMPUTE_BIT, 0, pushSize}; static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant"); - vk::PipelineLayoutCreateInfo layoutInfo; - layoutInfo.setSetLayoutCount(1); - layoutInfo.setPSetLayouts(&m_lanternIndirectDescSetLayout); - layoutInfo.setPushConstantRangeCount(1); - layoutInfo.setPPushConstantRanges(&pushCRange); - m_lanternIndirectCompPipelineLayout = m_device.createPipelineLayout(layoutInfo); + VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + layoutInfo.setLayoutCount = 1; + layoutInfo.pSetLayouts = &m_lanternIndirectDescSetLayout; + layoutInfo.pushConstantRangeCount = 1; + layoutInfo.pPushConstantRanges = &pushCRange; + vkCreatePipelineLayout(m_device, &layoutInfo, nullptr, &m_lanternIndirectCompPipelineLayout); // Create compute pipeline. - vk::ComputePipelineCreateInfo pipelineInfo; - pipelineInfo.setStage(stageInfo); - pipelineInfo.setLayout(m_lanternIndirectCompPipelineLayout); - m_lanternIndirectCompPipeline = m_device.createComputePipeline({}, pipelineInfo).value; + VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + pipelineInfo.stage = stageInfo; + pipelineInfo.layout = m_lanternIndirectCompPipelineLayout; + vkCreateComputePipelines(m_device, {}, 1, &pipelineInfo, nullptr, &m_lanternIndirectCompPipeline); - m_device.destroy(computeShader); + vkDestroyShaderModule(m_device, computeShader, nullptr); } // Allocate the buffer used to pass lantern info + ray trace indirect parameters to ray tracer. @@ -1284,20 +1244,18 @@ void HelloVulkan::createLanternIndirectBuffer() // m_alloc behind the scenes uses cmdBuf to transfer data to the buffer. nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - using Usage = vk::BufferUsageFlagBits; - m_lanternIndirectBuffer = - m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount, - Usage::eIndirectBuffer | Usage::eTransferDst - | Usage::eShaderDeviceAddress | Usage::eStorageBuffer, - vk::MemoryPropertyFlagBits::eDeviceLocal); + using Usage = VkBufferUsageFlagBits; + m_lanternIndirectBuffer = m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount, + VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); std::vector entries(m_lanternCount); for(size_t i = 0; i < m_lanternCount; ++i) entries[i].lantern = m_lanterns[i]; - cmdBuf.updateBuffer(m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], - entries.data()); + vkCmdUpdateBuffer(cmdBuf, m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data()); cmdBufGet.submitAndWait(cmdBuf); } @@ -1315,28 +1273,28 @@ void HelloVulkan::createLanternIndirectBuffer() // effect. This is stored in m_lanternIndirectBuffer. Then an indirect trace rays command // is run for every lantern within its scissor rectangle. The lanterns' light // contribution is additively blended into the output image. -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { // Before tracing rays, we need to dispatch the compute shaders that // fill in the ray trace indirect parameters for each lantern pass. // First, barrier before, ensure writes aren't visible to previous frame. - vk::BufferMemoryBarrier bufferBarrier; - bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eIndirectCommandRead); - bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderWrite); - bufferBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - bufferBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - bufferBarrier.setBuffer(m_lanternIndirectBuffer.buffer); - bufferBarrier.offset = 0; - bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0]; - cmdBuf.pipelineBarrier( // - vk::PipelineStageFlagBits::eDrawIndirect, // - vk::PipelineStageFlagBits::eComputeShader, // - vk::DependencyFlags(0), // - {}, {bufferBarrier}, {}); + VkBufferMemoryBarrier bufferBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.buffer = m_lanternIndirectBuffer.buffer; + bufferBarrier.offset = 0; + bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0]; + vkCmdPipelineBarrier(cmdBuf, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, // + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // + VkDependencyFlags(0), // + 0, nullptr, 1, &bufferBarrier, 0, nullptr); // Bind compute shader, update push constant and descriptors, dispatch compute. - cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipeline); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipeline); nvmath::mat4 view = getViewMatrix(); m_lanternIndirectPushConstants.viewRowX = view.row(0); m_lanternIndirectPushConstants.viewRowY = view.row(1); @@ -1346,21 +1304,20 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_lanternIndirectPushConstants.screenX = m_size.width; m_lanternIndirectPushConstants.screenY = m_size.height; m_lanternIndirectPushConstants.lanternCount = int32_t(m_lanternCount); - cmdBuf.pushConstants(m_lanternIndirectCompPipelineLayout, - vk::ShaderStageFlagBits::eCompute, 0, - m_lanternIndirectPushConstants); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipelineLayout, 0, - {m_lanternIndirectDescSet}, {}); - cmdBuf.dispatch(1, 1, 1); + vkCmdPushConstants(cmdBuf, m_lanternIndirectCompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, + sizeof(LanternIndirectPushConstants), &m_lanternIndirectPushConstants); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipelineLayout, 0, 1, + &m_lanternIndirectDescSet, 0, nullptr); + vkCmdDispatch(cmdBuf, 1, 1, 1); // Ensure compute results are visible when doing indirect ray trace. - bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); - bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eIndirectCommandRead); - cmdBuf.pipelineBarrier( // - vk::PipelineStageFlagBits::eComputeShader, // - vk::PipelineStageFlagBits::eDrawIndirect, // - vk::DependencyFlags(0), // - {}, {bufferBarrier}, {}); + bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + vkCmdPipelineBarrier(cmdBuf, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, // + VkDependencyFlags(0), // + 0, nullptr, 1, &bufferBarrier, 0, nullptr); // Now move on to the actual ray tracing. @@ -1376,67 +1333,67 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.screenY = m_size.height; m_rtPushConstants.lanternDebug = m_lanternDebug; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + // Size of a program identifier - uint32_t groupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); + uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; + + VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); + + using Stride = VkStridedDeviceAddressRegionKHR; + std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen + Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss + Stride{sbtAddress + 4u * groupSize, groupStride, groupSize * 4}, // hit + Stride{0u, 0u, 0u}}; // callable - using Stride = vk::StridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss - Stride{sbtAddress + 4u * groupSize, groupStride, groupSize * 4}, // hit - Stride{0u, 0u, 0u}}; // callable // First pass, illuminate scene with global light. - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], // - &strideAddresses[2], &strideAddresses[3], // - m_size.width, m_size.height, 1); + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); // Lantern passes, ensure previous pass completed, then add light contribution from each lantern. for(int i = 0; i < static_cast(m_lanternCount); ++i) { // Barrier to ensure previous pass finished. - vk::Image offscreenImage{m_offscreenColor.image}; - vk::ImageSubresourceRange colorRange(vk::ImageAspectFlagBits::eColor, 0, - VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); - vk::ImageMemoryBarrier imageBarrier; - imageBarrier.setOldLayout(vk::ImageLayout::eGeneral); - imageBarrier.setNewLayout(vk::ImageLayout::eGeneral); - imageBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - imageBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); - imageBarrier.setImage(offscreenImage); - imageBarrier.setSubresourceRange(colorRange); - imageBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); - imageBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eRayTracingShaderKHR, // - vk::PipelineStageFlagBits::eRayTracingShaderKHR, // - vk::DependencyFlags(0), // - {}, {}, {imageBarrier}); + VkImage offscreenImage{m_offscreenColor.image}; + VkImageSubresourceRange colorRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}; + VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + imageBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imageBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageBarrier.image = offscreenImage; + imageBarrier.subresourceRange = colorRange; + imageBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + vkCmdPipelineBarrier(cmdBuf, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, // + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, // + VkDependencyFlags(0), // + 0, nullptr, 0, nullptr, 1, &imageBarrier); // Set lantern pass number. m_rtPushConstants.lanternPassNumber = i; - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + + + VkDeviceAddress indirectDeviceAddress = + nvvk::getBufferDeviceAddress(m_device, m_lanternIndirectBuffer.buffer) + i * sizeof(LanternIndirectEntry); // Execute lantern pass. - cmdBuf.traceRaysIndirectKHR(&strideAddresses[0], &strideAddresses[1], // - &strideAddresses[2], &strideAddresses[3], // - m_device.getBufferAddress({m_lanternIndirectBuffer.buffer}) - + i * sizeof(LanternIndirectEntry)); + vkCmdTraceRaysIndirectKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], // + &strideAddresses[2], &strideAddresses[3], // + indirectDeviceAddress); } m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_indirect_scissor/hello_vulkan.h b/ray_tracing_indirect_scissor/hello_vulkan.h index 86c7f5c..179722e 100644 --- a/ray_tracing_indirect_scissor/hello_vulkan.h +++ b/ray_tracing_indirect_scissor/hello_vulkan.h @@ -18,13 +18,12 @@ */ #pragma once -#include - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -36,13 +35,10 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); @@ -50,8 +46,7 @@ public: void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); nvmath::mat4 getViewMatrix() { return CameraManip.getMatrix(); } @@ -62,10 +57,10 @@ public: return nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, nearZ, 1000.0f); } - void updateUniformBuffer(const vk::CommandBuffer&); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -130,39 +125,41 @@ public: std::vector m_lanterns; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -183,7 +180,7 @@ public: void createRtShaderBindingTable(); void createLanternIndirectBuffer(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); // Used to store lantern model, generated at runtime. const float m_lanternModelRadius = 0.125; @@ -194,22 +191,22 @@ public: // Index of lantern's BLAS in the BLAS array stored in m_rtBuilder. size_t m_lanternBlasId; - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind; - vk::DescriptorPool m_lanternIndirectDescPool; - vk::DescriptorSetLayout m_lanternIndirectDescSetLayout; - vk::DescriptorSet m_lanternIndirectDescSet; - vk::PipelineLayout m_lanternIndirectCompPipelineLayout; - vk::Pipeline m_lanternIndirectCompPipeline; - nvvk::Buffer m_rtSBTBuffer; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind; + VkDescriptorPool m_lanternIndirectDescPool; + VkDescriptorSetLayout m_lanternIndirectDescSetLayout; + VkDescriptorSet m_lanternIndirectDescSet; + VkPipelineLayout m_lanternIndirectCompPipelineLayout; + VkPipeline m_lanternIndirectCompPipeline; + nvvk::Buffer m_rtSBTBuffer; // Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color, // position, etc. from when doing lantern lighting passes. diff --git a/ray_tracing_indirect_scissor/main.cpp b/ray_tracing_indirect_scissor/main.cpp index 4e80346..231855f 100644 --- a/ray_tracing_indirect_scissor/main.cpp +++ b/ray_tracing_indirect_scissor/main.cpp @@ -23,8 +23,6 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -74,6 +72,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -88,8 +87,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -118,7 +116,7 @@ int main(int argc, char** argv) contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); -#ifdef WIN32 +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -128,19 +126,19 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // Creating Vulkan base application nvvk::Context vkctx{}; vkctx.initInstance(contextInfo); @@ -150,16 +148,14 @@ int main(int argc, char** argv) // Use a compatible device vkctx.initDevice(compatibleDevices[0], contextInfo); - // Create example HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -223,6 +219,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -231,9 +228,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -242,28 +237,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -272,40 +268,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_instances/CMakeLists.txt b/ray_tracing_instances/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_instances/CMakeLists.txt +++ b/ray_tracing_instances/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_instances/hello_vulkan.cpp b/ray_tracing_instances/hello_vulkan.cpp index 7ed0a23..8ae104a 100644 --- a/ray_tracing_instances/hello_vulkan.cpp +++ b/ray_tracing_instances/hello_vulkan.cpp @@ -19,9 +19,7 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" @@ -40,6 +38,8 @@ extern std::vector defaultSearchPaths; #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -51,16 +51,14 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); @@ -69,46 +67,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -116,33 +114,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -155,25 +147,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -181,7 +173,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -189,40 +181,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -234,8 +224,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -259,18 +247,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -286,17 +270,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -308,11 +290,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -321,15 +302,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -337,18 +318,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -361,8 +341,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -375,16 +354,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -399,10 +377,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -420,22 +399,23 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); m_sbtWrapper.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.deinit(); } @@ -443,32 +423,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -483,10 +462,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -498,29 +479,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -529,11 +509,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -541,24 +519,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -567,26 +544,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -596,43 +570,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -647,48 +614,64 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } +//-------------------------------------------------------------------------------------------------- +// +// void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry @@ -701,7 +684,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -718,7 +701,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -726,30 +709,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -759,13 +745,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -774,94 +757,118 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); - - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); + // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. + if(m_rtProperties.maxRayRecursionDepth <= 1) + { + throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); + } - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -870,19 +877,18 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); - auto regions = m_sbtWrapper.getRegions(); - cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], m_size.width, m_size.height, - 1); + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_instances/hello_vulkan.h b/ray_tracing_instances/hello_vulkan.h index 7f540cc..53bf2da 100644 --- a/ray_tracing_instances/hello_vulkan.h +++ b/ray_tracing_instances/hello_vulkan.h @@ -22,9 +22,9 @@ // #VKRay // // Choosing the allocator to use -//#define ALLOC_DMA +#define ALLOC_DMA //#define ALLOC_DEDICATED -#define ALLOC_VMA +//#define ALLOC_VMA #include #if defined(ALLOC_DMA) @@ -37,7 +37,7 @@ using Allocator = nvvk::ResourceAllocatorVma; using Allocator = nvvk::ResourceAllocatorDedicated; #endif -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" @@ -52,25 +52,21 @@ using Allocator = nvvk::ResourceAllocatorDedicated; // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -107,12 +103,12 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances @@ -123,25 +119,26 @@ public: nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -151,25 +148,25 @@ public: void createRtDescriptorSet(); void updateRtDescriptorSet(); void createRtPipeline(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::SBTWrapper m_sbtWrapper; struct RtPushConstant { nvmath::vec4f clearColor; nvmath::vec3f lightPosition; - float lightIntensity; - int lightType; + float lightIntensity{100.0f}; + int lightType{0}; } m_rtPushConstants; }; diff --git a/ray_tracing_instances/main.cpp b/ray_tracing_instances/main.cpp index bd1eb93..c0c011d 100644 --- a/ray_tracing_instances/main.cpp +++ b/ray_tracing_instances/main.cpp @@ -24,8 +24,6 @@ #include #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -35,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -56,9 +53,8 @@ struct MilliTimer void reset() { startTime = std::chrono::high_resolution_clock::now(); } double elapse() { - auto now = std::chrono::high_resolution_clock::now(); - auto t = - std::chrono::duration_cast(now - startTime).count() / 1000.0; + auto now = std::chrono::high_resolution_clock::now(); + auto t = std::chrono::duration_cast(now - startTime).count() / 1000.0; startTime = now; return t; } @@ -75,6 +71,7 @@ struct MilliTimer // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -102,6 +99,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -116,8 +114,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -144,9 +141,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -158,17 +155,16 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -183,11 +179,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -199,7 +194,7 @@ int main(int argc, char** argv) MilliTimer timer; // Creation of the example - std::random_device rd; //Will be used to obtain a seed for the random number engine + std::random_device rd; //Will be used to obtain a seed for the random number engine std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd() std::normal_distribution dis(1.0f, 1.0f); std::normal_distribution disn(0.05f, 0.05f); @@ -209,12 +204,11 @@ int main(int argc, char** argv) HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back(); float scale = fabsf(disn(gen)); - nvmath::mat4f mat = - nvmath::translation_mat4(nvmath::vec3f{dis(gen), 2.0f + dis(gen), dis(gen)}); - mat = mat * nvmath::rotation_mat4_x(dis(gen)); - mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale)); - inst.transform = mat; - inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform))); + nvmath::mat4f mat = nvmath::translation_mat4(nvmath::vec3f{dis(gen), 2.0f + dis(gen), dis(gen)}); + mat = mat * nvmath::rotation_mat4_x(dis(gen)); + mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale)); + inst.transform = mat; + inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform))); } helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); @@ -259,6 +253,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -267,8 +262,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -277,28 +271,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -307,40 +302,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_intersection/CMakeLists.txt b/ray_tracing_intersection/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_intersection/CMakeLists.txt +++ b/ray_tracing_intersection/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_intersection/README.md b/ray_tracing_intersection/README.md index 1dfe993..5a27e68 100644 --- a/ray_tracing_intersection/README.md +++ b/ray_tracing_intersection/README.md @@ -71,25 +71,27 @@ The following implementation will create 2.000.000 spheres at random positions a //-------------------------------------------------------------------------------------------------- // Creating all spheres // -void HelloVulkan::createSpheres() +void HelloVulkan::createSpheres(uint32_t nbSpheres) { std::random_device rd{}; std::mt19937 gen{rd()}; std::normal_distribution xzd{0.f, 5.f}; - std::normal_distribution yd{3.f, 1.f}; + std::normal_distribution yd{6.f, 3.f}; std::uniform_real_distribution radd{.05f, .2f}; // All spheres - Sphere s; - for(uint32_t i = 0; i < 2000000; i++) + m_spheres.resize(nbSpheres); + for(uint32_t i = 0; i < nbSpheres; i++) { - s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen)); - s.radius = radd(gen); - m_spheres.emplace_back(s); + Sphere s; + s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen)); + s.radius = radd(gen); + m_spheres[i] = std::move(s); } // Axis aligned bounding box of each sphere std::vector aabbs; + aabbs.reserve(nbSpheres); for(const auto& s : m_spheres) { Aabb aabb; @@ -99,28 +101,28 @@ void HelloVulkan::createSpheres() } // Creating two materials - MatrialObj mat; - mat.diffuse = vec3f(0, 1, 1); - std::vector materials; - std::vector matIdx; + MaterialObj mat; + mat.diffuse = nvmath::vec3f(0, 1, 1); + std::vector materials; + std::vector matIdx(nbSpheres); materials.emplace_back(mat); - mat.diffuse = vec3f(1, 1, 0); + mat.diffuse = nvmath::vec3f(1, 1, 0); materials.emplace_back(mat); // Assign a material to each sphere for(size_t i = 0; i < m_spheres.size(); i++) { - matIdx.push_back(i % 2); + matIdx[i] = i % 2; } // Creating all buffers - using vkBU = vk::BufferUsageFlagBits; + using vkBU = VkBufferUsageFlagBits; nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, vkBU::eStorageBuffer); - m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, vkBU::eShaderDeviceAddress); - m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, vkBU::eStorageBuffer); - m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, vkBU::eStorageBuffer); + m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); genCmdBuf.submitAndWait(cmdBuf); // Debug information @@ -148,39 +150,32 @@ What is changing compare to triangle primitive is the Aabb data (see Aabb struct //-------------------------------------------------------------------------------------------------- // Returning the ray tracing geometry used for the BLAS, containing all spheres // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::sphereToVkGeometryKHR() +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::sphereToVkGeometryKHR() { - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eAabbs); - asCreate.setMaxPrimitiveCount((uint32_t)m_spheres.size()); // Nb triangles - asCreate.setIndexType(vk::IndexType::eNoneKHR); - asCreate.setVertexFormat(vk::Format::eUndefined); - asCreate.setMaxVertexCount(0); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_spheresAabbBuffer.buffer; + VkDeviceAddress dataAddress = vkGetBufferDeviceAddress(m_device, &info); + VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR}; + aabbs.data.deviceAddress = dataAddress; + aabbs.stride = sizeof(Aabb); - vk::DeviceAddress dataAddress = m_device.getBufferAddress({m_spheresAabbBuffer.buffer}); - vk::AccelerationStructureGeometryAabbsDataKHR aabbs; - aabbs.setData(dataAddress); - aabbs.setStride(sizeof(Aabb)); + // Setting up the build info of the acceleration (C version, c++ gives wrong type) + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.aabbs = aabbs; - // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setAabbs(aabbs); + VkAccelerationStructureBuildRangeInfoKHR offset{}; + offset.firstVertex = 0; + offset.primitiveCount = (uint32_t)m_spheres.size(); // Nb aabb + offset.primitiveOffset = 0; + offset.transformOffset = 0; - vk::AccelerationStructureBuildOffsetInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); - - nvvk::RaytracingBuilderKHR::Blas blas; - blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); - blas.asBuildOffsetInfo.emplace_back(offset); - return blas; + nvvk::RaytracingBuilderKHR::BlasInput input; + input.asGeometry.emplace_back(asGeom); + input.asBuildOffsetInfo.emplace_back(offset); + return input; } ~~~~ @@ -212,7 +207,7 @@ The function `createBottomLevelAS()` is creating a BLAS per OBJ, the following m void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry - std::vector allBlas; + std::vector allBlas; allBlas.reserve(m_objModel.size()); for(const auto& obj : m_objModel) { @@ -228,7 +223,7 @@ void HelloVulkan::createBottomLevelAS() allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } ~~~~ @@ -261,19 +256,19 @@ In function `createDescriptorSetLayout()`, the addition of the material and mate ~~~~ C++ // Materials (binding = 1) - m_descSetLayoutBind.emplace_back(vkDS(1, vkDT::eStorageBuffer, nbObj + 1, - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj+1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials Index (binding = 4) - m_descSetLayoutBind.emplace_back( - vkDS(4, vkDT::eStorageBuffer, nbObj + 1, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj +1, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); ~~~~ And the new buffer holding the spheres ~~~~ C++ // Storing spheres (binding = 7) - m_descSetLayoutBind.emplace_back( // - vkDS(7, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR | vkSS::eIntersectionKHR)); + m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR); ~~~~ The function `updateDescriptorSet()` which is writing the values of the buffer need also to be modified. @@ -281,22 +276,22 @@ The function `updateDescriptorSet()` which is writing the values of the buffer n At the end of the loop on all models, lets add the new material and material index. ~~~~ C++ - for(auto& model : m_objModel) + for(auto& m : m_objModel) { - dbiMat.emplace_back(model.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(model.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(model.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(model.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } - dbiMat.emplace_back(m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); ~~~~ Then write the buffer for the spheres ~~~~ C++ - vk::DescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, dbiSpheres)); + VkDescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE}; + writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiSpheres)); ~~~~ ## Intersection Shader @@ -306,44 +301,33 @@ The intersection shader is added to the Hit Group `VK_RAY_TRACING_SHADER_GROUP_T Here is how the two hit group looks like: ~~~~ C++ - // Hit Group0 - Closest Hit - vk::ShaderModule chitSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); - + enum StageIndices { - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - } + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eClosestHit2, + eIntersection, + eShaderGroupCount + }; - // Hit Group1 - Closest Hit + Intersection (procedural) - vk::ShaderModule chit2SM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); - vk::ShaderModule rintSM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rint.spv", true, paths)); - { - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); - hg.setIntersectionShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); - m_rtShaderGroups.push_back(hg); - } + // Closest hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit2] = stage; + // Intersection + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; + stages[eIntersection] = stage; ~~~~ -And destroy the two shaders at the end - ~~~~ C++ - m_device.destroy(chit2SM); - m_device.destroy(rintSM); + // closest hit shader + Intersection (Hit group 2) + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + group.closestHitShader = eClosestHit2; + group.intersectionShader = eIntersection; + m_rtShaderGroups.push_back(group); ~~~~ ### raycommon.glsl diff --git a/ray_tracing_intersection/hello_vulkan.cpp b/ray_tracing_intersection/hello_vulkan.cpp index 23302b5..e7828e7 100644 --- a/ray_tracing_intersection/hello_vulkan.cpp +++ b/ray_tracing_intersection/hello_vulkan.cpp @@ -19,9 +19,7 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" @@ -37,9 +35,11 @@ extern std::vector defaultSearchPaths; #include "nvvk/pipeline_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" - #include +extern std::vector defaultSearchPaths; + + // Holding the camera matrices struct CameraMatrices { @@ -50,17 +50,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -68,46 +66,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -115,36 +113,30 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding(vkDS(1, vkDT::eStorageBuffer, nbObj + 1, - vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj + 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials Index (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj + 1, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj + 1, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing spheres (binding = 7) - m_descSetLayoutBind.addBinding( // - vkDS(7, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR | vkSS::eIntersectionKHR)); + m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -157,39 +149,39 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } - dbiMat.emplace_back(m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); - vk::DescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiSpheres)); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -197,40 +189,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -242,8 +232,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -267,18 +255,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -294,17 +278,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -316,11 +298,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -329,15 +310,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -345,18 +326,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -369,8 +349,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -383,16 +362,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -407,10 +385,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -428,21 +407,22 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.destroy(m_rtSBTBuffer); m_alloc.destroy(m_spheresBuffer); @@ -456,32 +436,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -496,10 +475,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -511,29 +492,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -542,11 +522,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -554,24 +532,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -580,26 +557,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -609,43 +583,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -660,45 +627,57 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } @@ -707,25 +686,25 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) // nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::sphereToVkGeometryKHR() { - vk::DeviceAddress dataAddress = m_device.getBufferAddress({m_spheresAabbBuffer.buffer}); + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_spheresAabbBuffer.buffer; + VkDeviceAddress dataAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryAabbsDataKHR aabbs; - aabbs.setData(dataAddress); - aabbs.setStride(sizeof(Aabb)); + VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR}; + aabbs.data.deviceAddress = dataAddress; + aabbs.stride = sizeof(Aabb); // Setting up the build info of the acceleration (C version, c++ gives wrong type) - vk::AccelerationStructureGeometryKHR asGeom(vk::GeometryTypeKHR::eAabbs, aabbs, - vk::GeometryFlagBitsKHR::eOpaque); - //asGeom.geometryType = vk::GeometryTypeKHR::eAabbs; - //asGeom.flags = vk::GeometryFlagBitsKHR::eOpaque; - //asGeom.geometry.aabbs = aabbs; + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.aabbs = aabbs; - - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount((uint32_t)m_spheres.size()); // Nb aabb - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset{}; + offset.firstVertex = 0; + offset.primitiveCount = (uint32_t)m_spheres.size(); // Nb aabb + offset.primitiveOffset = 0; + offset.transformOffset = 0; nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); @@ -781,13 +760,13 @@ void HelloVulkan::createSpheres(uint32_t nbSpheres) } // Creating all buffers - using vkBU = vk::BufferUsageFlagBits; + using vkBU = VkBufferUsageFlagBits; nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, vkBU::eStorageBuffer); - m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, vkBU::eShaderDeviceAddress); - m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, vkBU::eStorageBuffer); - m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, vkBU::eStorageBuffer); + m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); genCmdBuf.submitAndWait(cmdBuf); // Debug information @@ -816,7 +795,7 @@ void HelloVulkan::createBottomLevelAS() allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -845,7 +824,7 @@ void HelloVulkan::createTopLevelAS() tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -853,30 +832,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -886,13 +868,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -901,155 +880,168 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eClosestHit2, + eIntersection, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; + // Closest hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit2] = stage; + // Intersection + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; + stages[eIntersection] = stage; - - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group0 - Closest Hit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); - { - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - } + // closest hit shader + Intersection + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + group.closestHitShader = eClosestHit2; + group.intersectionShader = eIntersection; + m_rtShaderGroups.push_back(group); - // Hit Group1 - Closest Hit + Intersection (procedural) - vk::ShaderModule chit2SM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); - vk::ShaderModule rintSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); - { - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); - hg.setIntersectionShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); - m_rtShaderGroups.push_back(hg); - } - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); - m_device.destroy(chit2SM); - m_device.destroy(rintSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // The Shader Binding Table (SBT) -// - getting all shader handles and writing them in a SBT buffer +// - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this // See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = - static_cast(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, 2 chit, rint - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - uint32_t groupSizeAligned = - nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - - // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT + auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit + uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier + // Compute the actual size needed per SBT entry (round-up to alignment needed). + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; + // Fetch all the shader handles used in the pipeline. This is opaque data, + // so we store it in a vector of bytes. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); - // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer( - sbtSize, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR - | vk::BufferUsageFlagBits::eShaderBindingTableKHR, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + assert(result == VK_SUCCESS); + + // Allocate a buffer for storing the SBT. Give it a debug name for NSight. + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); - // Write the handles in the SBT + // Map the SBT buffer and write in the handles. void* mapped = m_alloc.map(m_rtSBTBuffer); auto* pData = reinterpret_cast(mapped); for(uint32_t g = 0; g < groupCount; g++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen + memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); - - m_alloc.finalizeAndReleaseStaging(); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -1058,31 +1050,34 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + // Size of a program identifier - uint32_t groupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); + uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; - using Stride = vk::StridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_rtSBTBuffer.buffer; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + + using Stride = VkStridedDeviceAddressRegionKHR; + std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen + Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss + Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 2}, // hit + Stride{0u, 0u, 0u}}; // callable + + + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - &strideAddresses[3], // - m_size.width, m_size.height, 1); // m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing_intersection/hello_vulkan.h b/ray_tracing_intersection/hello_vulkan.h index 7299a30..34a9160 100644 --- a/ray_tracing_intersection/hello_vulkan.h +++ b/ray_tracing_intersection/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -35,25 +35,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -90,39 +86,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -133,26 +131,26 @@ public: void updateRtDescriptorSet(); void createRtPipeline(); void createRtShaderBindingTable(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::Buffer m_rtSBTBuffer; struct RtPushConstant { nvmath::vec4f clearColor; nvmath::vec3f lightPosition; - float lightIntensity; - int lightType; + float lightIntensity{100.0f}; + int lightType{0}; } m_rtPushConstants; diff --git a/ray_tracing_intersection/main.cpp b/ray_tracing_intersection/main.cpp index 62b94b8..70b49b0 100644 --- a/ray_tracing_intersection/main.cpp +++ b/ray_tracing_intersection/main.cpp @@ -23,8 +23,6 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -74,6 +72,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -88,8 +87,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -116,9 +114,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -130,18 +128,16 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -156,11 +152,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -212,6 +207,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -220,8 +216,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -230,28 +225,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -260,40 +256,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_jitter_cam/CMakeLists.txt b/ray_tracing_jitter_cam/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_jitter_cam/CMakeLists.txt +++ b/ray_tracing_jitter_cam/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_jitter_cam/hello_vulkan.cpp b/ray_tracing_jitter_cam/hello_vulkan.cpp index bbd8562..e38addc 100644 --- a/ray_tracing_jitter_cam/hello_vulkan.cpp +++ b/ray_tracing_jitter_cam/hello_vulkan.cpp @@ -19,26 +19,25 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" +#include "nvh/alignment.hpp" #include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/alignment.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -50,17 +49,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -68,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -115,33 +112,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -154,25 +145,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -180,7 +171,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -188,40 +179,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -233,8 +222,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -258,18 +245,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -285,17 +268,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -307,11 +288,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -320,15 +300,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -336,18 +316,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -360,8 +339,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -374,16 +352,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -398,10 +375,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -419,21 +397,22 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.destroy(m_rtSBTBuffer); m_alloc.deinit(); @@ -442,32 +421,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -483,10 +461,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) resetFrame(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -498,29 +478,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -529,11 +508,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -541,24 +518,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -567,26 +543,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -596,43 +569,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -647,47 +613,63 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } +//-------------------------------------------------------------------------------------------------- +// +// void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry @@ -700,7 +682,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -717,7 +699,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -725,30 +707,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -758,13 +743,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -773,135 +755,158 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); + // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. + if(m_rtProperties.maxRayRecursionDepth <= 1) + { + throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); + } + + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // The Shader Binding Table (SBT) -// - getting all shader handles and writing them in a SBT buffer +// - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this // See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = - static_cast(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - uint32_t groupSizeAligned = - nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - - // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT + auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit + uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier + // Compute the actual size needed per SBT entry (round-up to alignment needed). + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; + // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. + // The order of handles follow the stage entry. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); - // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer( - sbtSize, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR - | vk::BufferUsageFlagBits::eShaderBindingTableKHR, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + assert(result == VK_SUCCESS); + + // Allocate a buffer for storing the SBT. Give it a debug name for NSight. + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); - // Write the handles in the SBT + // Map the SBT buffer and write in the handles. void* mapped = m_alloc.map(m_rtSBTBuffer); auto* pData = reinterpret_cast(mapped); for(uint32_t g = 0; g < groupCount; g++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen + memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); - - m_alloc.finalizeAndReleaseStaging(); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { updateFrame(); if(m_rtPushConstants.frame >= m_maxFrames) @@ -914,31 +919,34 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + // Size of a program identifier - uint32_t groupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); + uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; - using Stride = vk::StridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_rtSBTBuffer.buffer; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + + using Stride = VkStridedDeviceAddressRegionKHR; + std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen + Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss + Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit + Stride{0u, 0u, 0u}}; // callable + + + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - &strideAddresses[3], // - m_size.width, m_size.height, 1); // m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing_jitter_cam/hello_vulkan.h b/ray_tracing_jitter_cam/hello_vulkan.h index 598aab6..1696a6d 100644 --- a/ray_tracing_jitter_cam/hello_vulkan.h +++ b/ray_tracing_jitter_cam/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -35,25 +35,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -90,39 +86,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -133,28 +131,28 @@ public: void updateRtDescriptorSet(); void createRtPipeline(); void createRtShaderBindingTable(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void resetFrame(); void updateFrame(); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; - int m_maxFrames{10}; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::Buffer m_rtSBTBuffer; + int m_maxFrames{10}; struct RtPushConstant { nvmath::vec4f clearColor; nvmath::vec3f lightPosition; - float lightIntensity; - int lightType; + float lightIntensity{100.0f}; + int lightType{0}; int frame{0}; } m_rtPushConstants; }; diff --git a/ray_tracing_jitter_cam/main.cpp b/ray_tracing_jitter_cam/main.cpp index 3d287dc..24529fb 100644 --- a/ray_tracing_jitter_cam/main.cpp +++ b/ray_tracing_jitter_cam/main.cpp @@ -23,8 +23,6 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -55,9 +53,8 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - bool changed = false; - - changed |= ImGuiH::CameraWidget(); + bool changed{false}; + ImGuiH::CameraWidget(); if(ImGui::CollapsingHeader("Light")) { auto& pc = helloVk.m_pushConstant; @@ -81,6 +78,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -95,8 +93,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -123,9 +120,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -138,17 +135,15 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -163,11 +158,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -219,6 +213,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -232,8 +227,7 @@ int main(int argc, char** argv) helloVk.resetFrame(); renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -242,28 +236,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -272,40 +267,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_manyhits/CMakeLists.txt b/ray_tracing_manyhits/CMakeLists.txt index f79bd39..8587db8 100644 --- a/ray_tracing_manyhits/CMakeLists.txt +++ b/ray_tracing_manyhits/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") @@ -33,7 +33,7 @@ include_directories(${TUTO_KHR_DIR}/common) # GLSL to SPIR-V custom build compile_glsl_directory( SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" + DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" VULKAN_TARGET "vulkan1.2" ) diff --git a/ray_tracing_manyhits/README.md b/ray_tracing_manyhits/README.md index b7cc206..f0d90d5 100644 --- a/ray_tracing_manyhits/README.md +++ b/ray_tracing_manyhits/README.md @@ -59,18 +59,31 @@ void main() This new shader needs to be added to the raytracing pipeline. So, in `createRtPipeline` in `hello_vulkan.cpp`, load the new closest hit shader immediately after loading the first one. ~~~~ C++ - vk::ShaderModule chit2SM = - nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eClosestHit2, + eShaderGroupCount + }; + + // ... + + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit2] = stage; ~~~~ Then add a new hit group group immediately after adding the first hit group: ~~~~ C++ - // Second group - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); - m_rtShaderGroups.push_back(hg); + // Hit 2 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit2; + m_rtShaderGroups.push_back(group); ~~~~ ### `raytrace.rgen` @@ -200,6 +213,36 @@ In `main`, after we set which hit group an instance will use, we can add the dat ### `HelloVulkan::createRtShaderBindingTable` +**NEW** + +The creation of the shading binding table as it was done, was using hardcoded offsets and potentially could lead to errors. +Instead, the new code uses the `nvvk::SBTWraper` that uses the ray tracing pipeline and the `VkRayTracingPipelineCreateInfoKHR` to +create the SBT information. + +The wrapper will find the handles for each group and will add the +data `m_hitShaderRecord` to the Hit group. + +```` C + // Find handle indices and add data + m_sbtWrapper.addIndices(rayPipelineInfo); + m_sbtWrapper.addData(SBTWrapper::eHit, 1, m_hitShaderRecord[0]); + m_sbtWrapper.addData(SBTWrapper::eHit, 2, m_hitShaderRecord[1]); + m_sbtWrapper.create(m_rtPipeline); +```` + +The buffer for Hit will have the following layout + +``` +| handle | handle,data | handle,data | +``` + +The wrapper will make sure the stride covers the largest data and is aligned +based on the GPU properties. + + + +**OLD - for reference** + Since we are no longer compacting all handles in a continuous buffer, we need to fill the SBT as described above. After retrieving the handles of all 5 groups (raygen, miss, miss shadow, hit0, and hit1) @@ -255,16 +298,27 @@ Then write the new SBT like this, where only Hit 1 has extra data. Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sbtBuffer`: ~~~~ C++ - m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR); + m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR); ~~~~ ### `raytrace` +**NEW** + +The mvvk::SBTWrapper gives use the information without having to compute the `VkStridedDeviceAddressRegionKHR` + +``` C + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); +``` + +**OLD** + Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`. ~~~~ C++ - vk::DeviceSize hitGroupSize = + VkDeviceSize hitGroupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), m_rtProperties.shaderGroupBaseAlignment); ~~~~ @@ -272,7 +326,7 @@ Finally, since the size of the hit group is now larger than just the handle, we The stride device address will be modified like this: ~~~~ C++ - using Stride = vk::StridedDeviceAddressRegionKHR; + using Stride = VkStridedDeviceAddressRegionKHR; std::array strideAddresses{ Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss @@ -280,7 +334,7 @@ The stride device address will be modified like this: Stride{0u, 0u, 0u}}; // callable ~~~~ -!!! Note: +**Note:** The result should now show both `wuson` models with a yellow color. ![](images/manyhits4.png) diff --git a/ray_tracing_manyhits/hello_vulkan.cpp b/ray_tracing_manyhits/hello_vulkan.cpp index 0cc107a..f29b3ec 100644 --- a/ray_tracing_manyhits/hello_vulkan.cpp +++ b/ray_tracing_manyhits/hello_vulkan.cpp @@ -19,26 +19,26 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" -#include "nvh//cameramanipulator.hpp" +#include "nvh/alignment.hpp" +#include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/alignment.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + + // Holding the camera matrices struct CameraMatrices { @@ -49,17 +49,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -67,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -114,33 +112,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -153,25 +145,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; for(auto& m : m_objModel) { - dbiMat.emplace_back(m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(m.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -179,48 +171,46 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; - for(auto& t : m_textures) + std::vector diit; + for(auto& texture : m_textures) { - diit.emplace_back(t.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -232,8 +222,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -257,18 +245,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -284,17 +268,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -306,11 +288,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -319,15 +300,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -335,18 +316,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -359,8 +339,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -373,16 +352,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -397,10 +375,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -418,22 +397,23 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_sbtWrapper.destroy(); m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.destroy(m_rtSBTBuffer); m_alloc.deinit(); @@ -442,32 +422,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -482,10 +461,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -497,29 +478,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -528,11 +508,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -540,24 +518,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -566,26 +543,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -595,43 +569,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -646,49 +613,65 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } +//-------------------------------------------------------------------------------------------------- +// +// void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry @@ -701,7 +684,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -714,11 +697,11 @@ void HelloVulkan::createTopLevelAS() rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT rayInst.blasId = m_objInstance[i].objIndex; - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.hitGroupId = m_objInstance[i].hitgroup; // Using the hit group set in main + rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -726,30 +709,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -759,13 +745,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -774,121 +757,151 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eClosestHit2, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; + // + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit2] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - vk::ShaderModule chit2SM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); + // closest hit shader + // Hit 0 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); + // Hit 1 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit2; + m_rtShaderGroups.push_back(group); + // Hit 2 + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit2; + m_rtShaderGroups.push_back(group); - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - // Second group - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); - m_rtShaderGroups.push_back(hg); - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - // Manually defining group indices + // Find handle indices and add data m_sbtWrapper.addIndices(rayPipelineInfo); - m_sbtWrapper.addIndex(SBTWrapper::eHit, 4); // hit = 2 m_sbtWrapper.addData(SBTWrapper::eHit, 1, m_hitShaderRecord[0]); m_sbtWrapper.addData(SBTWrapper::eHit, 2, m_hitShaderRecord[1]); m_sbtWrapper.create(m_rtPipeline); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); - m_device.destroy(chit2SM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // The Shader Binding Table (SBT) -// - getting all shader handles and writing them in a SBT buffer +// - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this // See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = - static_cast(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, 2 chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - uint32_t groupSizeAligned = m_rtProperties.shaderGroupBaseAlignment; - - // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT + auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit + uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier + // Compute the actual size needed per SBT entry (round-up to alignment needed). + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; + // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. + // The order of handles follow the stage entry. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + + assert(result == VK_SUCCESS); // Retrieve the handle pointers std::vector handles(groupCount); @@ -900,8 +913,7 @@ void HelloVulkan::createRtShaderBindingTable() // Sizes uint32_t rayGenSize = groupSizeAligned; uint32_t missSize = groupSizeAligned; - uint32_t hitSize = - nvh::align_up(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), groupSizeAligned); + uint32_t hitSize = nvh::align_up(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), groupSizeAligned); uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize; std::vector sbtBuffer(newSbtSize); @@ -935,11 +947,10 @@ void HelloVulkan::createRtShaderBindingTable() // Write the handles in the SBT nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); + VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, - vk::BufferUsageFlagBits::eShaderDeviceAddressKHR - | vk::BufferUsageFlagBits::eShaderBindingTableKHR); + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR); m_debug.setObjectName(m_rtSBTBuffer.buffer, "SBT"); @@ -952,7 +963,7 @@ void HelloVulkan::createRtShaderBindingTable() //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -961,14 +972,14 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); //// Size of a program identifier @@ -984,7 +995,7 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& //std::array strideAddresses{ // Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen // Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - // Stride{sbtAddress + 3u * groupSize, hitGroupSize, hitGroupSize * 3}, // hit + // Stride{sbtAddress + 3u * groupSize, hitGroupSize, hitGroupSize * 2}, // hit // Stride{0u, 0u, 0u}}; // callable //strideAddresses[0] = m_sbtWrapper.getRaygenRegion(); @@ -1001,9 +1012,9 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& //regions[2] = m_sbtWrapper.getRegion(SBTWrapper::eHit); //regions[3] = m_sbtWrapper.getRegion(SBTWrapper::eCallable); - auto regions = m_sbtWrapper.getRegions(); - cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], // - m_size.width, m_size.height, 1); // + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); + m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing_manyhits/hello_vulkan.h b/ray_tracing_manyhits/hello_vulkan.h index f25e3fa..ec222a4 100644 --- a/ray_tracing_manyhits/hello_vulkan.h +++ b/ray_tracing_manyhits/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -37,25 +37,21 @@ using nvvk::SBTWrapper; // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -93,39 +89,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -136,20 +134,19 @@ public: void updateRtDescriptorSet(); void createRtPipeline(); void createRtShaderBindingTable(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; - + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::Buffer m_rtSBTBuffer; struct RtPushConstant { nvmath::vec4f clearColor; diff --git a/ray_tracing_manyhits/main.cpp b/ray_tracing_manyhits/main.cpp index 852d880..75aeace 100644 --- a/ray_tracing_manyhits/main.cpp +++ b/ray_tracing_manyhits/main.cpp @@ -23,19 +23,19 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" +#include "imgui.h" + #include "hello_vulkan.h" #include "imgui/imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" + ////////////////////////////////////////////////////////////////////////// #define UNUSED(x) (void)(x) ////////////////////////////////////////////////////////////////////////// @@ -43,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -70,6 +71,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -84,8 +86,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -112,9 +113,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -126,18 +127,16 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -152,11 +151,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -169,10 +167,10 @@ int main(int argc, char** argv) helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0))); - HelloVulkan::ObjInstance inst = helloVk.m_objInstance[0]; // Instance the wuson object + HelloVulkan::ObjInstance inst = helloVk.m_objInstance[0]; // Instance the Wuson object inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0)); inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform)); - helloVk.m_objInstance.push_back(inst); // Adding an instance of the wuson + helloVk.m_objInstance.push_back(inst); // Adding an instance of the Wuson helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); @@ -180,8 +178,8 @@ int main(int argc, char** argv) helloVk.m_hitShaderRecord.resize(2); helloVk.m_hitShaderRecord[0].color = nvmath::vec4f(0, 1, 0, 0); // Green helloVk.m_hitShaderRecord[1].color = nvmath::vec4f(0, 1, 1, 0); // Cyan - helloVk.m_objInstance[0].hitgroup = 1; // wuson 0 - helloVk.m_objInstance[1].hitgroup = 2; // wuson 1 + helloVk.m_objInstance[0].hitgroup = 1; // Wuson 0 + helloVk.m_objInstance[1].hitgroup = 2; // Wuson 1 helloVk.createOffscreenRender(); @@ -197,7 +195,7 @@ int main(int argc, char** argv) helloVk.createTopLevelAS(); helloVk.createRtDescriptorSet(); helloVk.createRtPipeline(); - helloVk.createRtShaderBindingTable(); + //helloVk.createRtShaderBindingTable(); helloVk.createPostDescriptor(); helloVk.createPostPipeline(); @@ -222,6 +220,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -230,8 +229,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -240,28 +238,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -270,40 +269,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_rayquery/CMakeLists.txt b/ray_tracing_rayquery/CMakeLists.txt index 7b31b78..8587db8 100644 --- a/ray_tracing_rayquery/CMakeLists.txt +++ b/ray_tracing_rayquery/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") diff --git a/ray_tracing_rayquery/README.md b/ray_tracing_rayquery/README.md index 494b11d..d727b1e 100644 --- a/ray_tracing_rayquery/README.md +++ b/ray_tracing_rayquery/README.md @@ -26,14 +26,14 @@ First, let's remove all extra code Remove most functions and members to keep only what is need to create the acceleration structure: ~~~~ C++ -// #VKRay -void initRayTracing(); -nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); -void createBottomLevelAS(); -void createTopLevelAS(); + // #VKRay + void initRayTracing(); + auto objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); -vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; -nvvk::RaytracingBuilderKHR m_rtBuilder; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; ~~~~ ### hello_vulkan (source) @@ -58,11 +58,11 @@ m_descSetLayoutBind.emplace_back( // In `HelloVulkan::updateDescriptorSet`, write the value to the descriptor set. ~~~~ C++ - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, descASInfo)); + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo)); ~~~~ diff --git a/ray_tracing_rayquery/hello_vulkan.cpp b/ray_tracing_rayquery/hello_vulkan.cpp index b3dc8af..a86d748 100644 --- a/ray_tracing_rayquery/hello_vulkan.cpp +++ b/ray_tracing_rayquery/hello_vulkan.cpp @@ -19,23 +19,24 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" #include "stb_image.h" #include "hello_vulkan.h" +#include "nvh/alignment.hpp" #include "nvh/cameramanipulator.hpp" +#include "nvh/fileoperations.hpp" +#include "nvvk/commands_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/images_vk.hpp" #include "nvvk/pipeline_vk.hpp" - -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" +#include "nvvk/shaders_vk.hpp" + +extern std::vector defaultSearchPaths; // Holding the camera matrices @@ -48,17 +49,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -66,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -113,36 +112,25 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT); // The top level acceleration structure - m_descSetLayoutBind.addBinding( // - vkDS(7, vkDT::eAccelerationStructureKHR, 1, vkSS::eFragment)); + m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descPool = m_descSetLayoutBind.createPool(m_device, 1); @@ -154,25 +142,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -180,55 +168,53 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo)); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -240,8 +226,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -265,18 +249,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -292,17 +272,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -314,11 +292,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -327,15 +304,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -343,18 +320,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the VKImage - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + // Creating the dummy texture + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -367,8 +343,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -381,16 +356,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -405,10 +379,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -426,14 +401,15 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); @@ -443,32 +419,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -482,10 +457,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updatePostDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -497,29 +474,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -528,11 +504,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -540,24 +514,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -566,26 +539,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -595,43 +565,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -646,45 +609,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - // Building part - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - // The primitive itself - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; - // Our blas is only one geometry, but could be made of many geometries + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); @@ -707,7 +678,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -724,5 +695,5 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } diff --git a/ray_tracing_rayquery/hello_vulkan.h b/ray_tracing_rayquery/hello_vulkan.h index 9367576..3642e7d 100644 --- a/ray_tracing_rayquery/hello_vulkan.h +++ b/ray_tracing_rayquery/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -35,25 +35,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -90,39 +86,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -130,6 +128,6 @@ public: void createBottomLevelAS(); void createTopLevelAS(); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; }; diff --git a/ray_tracing_rayquery/main.cpp b/ray_tracing_rayquery/main.cpp index c8e8ae6..ee561f8 100644 --- a/ray_tracing_rayquery/main.cpp +++ b/ray_tracing_rayquery/main.cpp @@ -23,10 +23,6 @@ // at the top of imgui.cpp. #include -#include - -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -36,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -48,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -75,6 +71,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -89,8 +86,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -117,9 +113,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -129,18 +125,19 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR}; + ; + contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeatures); - vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures; - contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures); - // Creating Vulkan base application nvvk::Context vkctx{}; @@ -151,16 +148,14 @@ int main(int argc, char** argv) // Use a compatible device vkctx.initDevice(compatibleDevices[0], contextInfo); - // Create example HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -173,6 +168,7 @@ int main(int argc, char** argv) helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); + helloVk.createOffscreenRender(); helloVk.createDescriptorSetLayout(); helloVk.createGraphicsPipeline(); @@ -193,110 +189,98 @@ int main(int argc, char** argv) nvmath::vec4f clearColor = nvmath::vec4f(1, 1, 1, 1.00f); + helloVk.setupGlfwCallbacks(window); ImGui_ImplGlfw_InitForVulkan(window, true); // Main loop while(!glfwWindowShouldClose(window)) { - try + glfwPollEvents(); + if(helloVk.isMinimized()) + continue; + + // Start the Dear ImGui frame + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + + // Show UI window. + if(helloVk.showGui()) { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; + ImGuiH::Panel::Begin(); + ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); - - // Offscreen render pass - { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); - - // Rendering Scene - { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); - helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); - } - } - - // 2nd rendering pass: tone mapper, UI - { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); - - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); - // Rendering tonemapper - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); - } - - // Submit for display - cmdBuf.end(); - helloVk.submitFrame(); + renderUI(helloVk); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } - catch(const std::system_error& e) + + // Start rendering the scene + helloVk.prepareFrame(); + + // Start command buffer of this frame + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); + + // Updating camera buffer + helloVk.updateUniformBuffer(cmdBuf); + + // Clearing screen + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; + + // Offscreen render pass { - if(e.code() == vk::Result::eErrorDeviceLost) + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; + + // Rendering Scene { -#if _WIN32 - MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1); -#endif + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + helloVk.rasterize(cmdBuf); + vkCmdEndRenderPass(cmdBuf); } - std::cout << e.what() << std::endl; - return e.code().value(); } + + // 2nd rendering pass: tone mapper, UI + { + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; + + // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + helloVk.drawPost(cmdBuf); + // Rendering UI + ImGui::Render(); + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); + vkCmdEndRenderPass(cmdBuf); + } + + // Submit for display + vkEndCommandBuffer(cmdBuf); + helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_reflections/CMakeLists.txt b/ray_tracing_reflections/CMakeLists.txt index eefca7c..8587db8 100644 --- a/ray_tracing_reflections/CMakeLists.txt +++ b/ray_tracing_reflections/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") @@ -29,7 +29,6 @@ list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) include_directories(${TUTO_KHR_DIR}/common) - #-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build compile_glsl_directory( @@ -39,7 +38,6 @@ compile_glsl_directory( ) - #-------------------------------------------------------------------------------------------------- # Sources target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) diff --git a/ray_tracing_reflections/README.md b/ray_tracing_reflections/README.md index 8c10c80..7b27bba 100644 --- a/ray_tracing_reflections/README.md +++ b/ray_tracing_reflections/README.md @@ -44,8 +44,7 @@ Vulkan ray tracing allows recursive calls to traceRayEXT, up to a limit defined In `createRtPipeline()` in `hello_vulkan.cpp`, bring the maximum recursion depth up to 10, making sure not to exceed the physical device's maximum recursion limit: ~~~~ C++ - rayPipelineInfo.setMaxPipelineRayRecursionDepth( - std::max(10u, m_rtProperties.maxRecursionDepth)); // Ray depth + rayPipelineInfo.maxPipelineRayRecursionDepth = std::max(10u, m_rtProperties.maxRecursionDepth); // Ray depth ~~~~ ### `raycommon.glsl` @@ -203,7 +202,7 @@ Since the ray generation shader now handles attenuation, we no longer need to at Finally, we no longer need to have a deep recursion setting in `createRtPipeline` -- just a depth of 2, one for the initial ray generation segment and another for shadow rays. ~~~~ C++ - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth ~~~~ In `raytrace.rgen`, we can now make the maximum ray depth significantly larger -- such as 100, for instance -- without causing a device lost error. diff --git a/ray_tracing_reflections/hello_vulkan.cpp b/ray_tracing_reflections/hello_vulkan.cpp index 7eb2dd1..6511c67 100644 --- a/ray_tracing_reflections/hello_vulkan.cpp +++ b/ray_tracing_reflections/hello_vulkan.cpp @@ -19,9 +19,7 @@ #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" @@ -38,6 +36,8 @@ extern std::vector defaultSearchPaths; #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -49,17 +49,15 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -67,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -114,33 +112,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -153,25 +145,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto &m : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(m.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -179,48 +171,46 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; - for(auto & t: m_textures) + std::vector diit; + for(auto& texture : m_textures) { - diit.emplace_back(t.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -232,8 +222,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -257,18 +245,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -284,17 +268,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -306,11 +288,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -319,15 +300,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -335,18 +316,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -359,8 +339,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -373,16 +352,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -397,10 +375,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -418,21 +397,22 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.destroy(m_rtSBTBuffer); m_alloc.deinit(); @@ -441,32 +421,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -481,10 +460,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -496,29 +477,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -527,11 +507,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -539,24 +517,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -565,26 +542,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -594,43 +568,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -645,47 +612,63 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS +// Convert an OBJ model into the ray tracing geometry used to build the BLAS // auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + // BLAS builder requires raw device addresses. + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + uint32_t maxPrimitiveCount = model.nbIndices / 3; - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + // Describe buffer as array of VertexObj. + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); + // Describe index data (32-bit unsigned int) + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; + // Indicate identity transform by setting transformData to null device pointer. + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + // Identify the above data as containing opaque triangles. + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; + // The entire array will be used to build the BLAS. + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; + + // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; input.asGeometry.emplace_back(asGeom); input.asBuildOffsetInfo.emplace_back(offset); + return input; } +//-------------------------------------------------------------------------------------------------- +// +// void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry @@ -698,7 +681,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -715,7 +698,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -723,30 +706,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -756,13 +742,10 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } @@ -771,134 +754,152 @@ void HelloVulkan::updateRtDescriptorSet() // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, + eShaderGroupCount + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point + // Raygen + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; + // Miss + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; + // Hit Group - Closest Hit + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stages[eClosestHit] = stage; - std::vector stages; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); - // Hit Group - Closest Hit + AnyHit - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); - m_rtShaderGroups.push_back(hg); - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + // closest hit shader + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit; + m_rtShaderGroups.push_back(group); // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); - rayPipelineInfo.setGroupCount(static_cast( - m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, + // two miss shader groups, and one hit group. + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // The Shader Binding Table (SBT) -// - getting all shader handles and writing them in a SBT buffer +// - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this // See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = - static_cast(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - uint32_t groupSizeAligned = - nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - - // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT + auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit + uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier + // Compute the actual size needed per SBT entry (round-up to alignment needed). + uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + // Bytes needed for the SBT. uint32_t sbtSize = groupCount * groupSizeAligned; + // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. + // The order of handles follow the stage entry. std::vector shaderHandleStorage(sbtSize); - auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); - assert(result == vk::Result::eSuccess); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); - // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer( - sbtSize, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR - | vk::BufferUsageFlagBits::eShaderBindingTableKHR, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + assert(result == VK_SUCCESS); + + // Allocate a buffer for storing the SBT. Give it a debug name for NSight. + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); - // Write the handles in the SBT + // Map the SBT buffer and write in the handles. void* mapped = m_alloc.map(m_rtSBTBuffer); auto* pData = reinterpret_cast(mapped); for(uint32_t g = 0; g < groupCount; g++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen + memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); - - m_alloc.finalizeAndReleaseStaging(); } + //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -907,31 +908,34 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity; m_rtPushConstants.lightType = m_pushConstant.lightType; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); + + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + // Size of a program identifier - uint32_t groupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); + uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; - using Stride = vk::StridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = m_rtSBTBuffer.buffer; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + + using Stride = VkStridedDeviceAddressRegionKHR; + std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen + Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss + Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit + Stride{0u, 0u, 0u}}; // callable + + + vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], + m_size.width, m_size.height, 1); - cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - &strideAddresses[3], // - m_size.width, m_size.height, 1); // m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing_reflections/hello_vulkan.h b/ray_tracing_reflections/hello_vulkan.h index 6e3e13c..c43554e 100644 --- a/ray_tracing_reflections/hello_vulkan.h +++ b/ray_tracing_reflections/hello_vulkan.h @@ -19,11 +19,11 @@ #pragma once - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -35,25 +35,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -90,39 +86,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -133,19 +131,19 @@ public: void updateRtDescriptorSet(); void createRtPipeline(); void createRtShaderBindingTable(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::Buffer m_rtSBTBuffer; struct RtPushConstant { diff --git a/ray_tracing_reflections/main.cpp b/ray_tracing_reflections/main.cpp index d90dece..486839b 100644 --- a/ray_tracing_reflections/main.cpp +++ b/ray_tracing_reflections/main.cpp @@ -23,16 +23,15 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" +#include "imgui.h" + #include "hello_vulkan.h" #include "imgui/imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -44,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -71,6 +71,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -85,8 +86,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -113,9 +113,9 @@ int main(int argc, char** argv) nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); - contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); -#ifdef WIN32 + contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -127,18 +127,16 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -153,11 +151,10 @@ int main(int argc, char** argv) HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -168,11 +165,9 @@ int main(int argc, char** argv) // Creation of the example helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), - nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0)) - * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); + nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0)) * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), - nvmath::translation_mat4(nvmath::vec3f(2, 0, 0)) - * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); + nvmath::translation_mat4(nvmath::vec3f(2, 0, 0)) * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f))); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), nvmath::translation_mat4(nvmath::vec3f(0, -1, 0))); @@ -216,6 +211,7 @@ int main(int argc, char** argv) ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + // Show UI window. if(helloVk.showGui()) { @@ -225,8 +221,7 @@ int main(int argc, char** argv) renderUI(helloVk); ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -235,28 +230,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -265,40 +261,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window); diff --git a/ray_tracing_specialization/CMakeLists.txt b/ray_tracing_specialization/CMakeLists.txt index 24e1da2..8587db8 100644 --- a/ray_tracing_specialization/CMakeLists.txt +++ b/ray_tracing_specialization/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) #-------------------------------------------------------------------------------------------------- # Project setting get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -SET(PROJNAME vk_${PROJNAME}_KHR) +set(PROJNAME vk_${PROJNAME}_KHR) project(${PROJNAME} LANGUAGES C CXX) message(STATUS "-------------------------------") message(STATUS "Processing Project ${PROJNAME}:") @@ -76,4 +76,3 @@ _finalize_target( ${PROJNAME} ) install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") - diff --git a/ray_tracing_specialization/README.md b/ray_tracing_specialization/README.md index 5e0e5e8..f7046b1 100644 --- a/ray_tracing_specialization/README.md +++ b/ray_tracing_specialization/README.md @@ -95,14 +95,15 @@ In our example, we will have only integers for constant data. There are various ~~~~ C ////////////////////////////////////////////////////////////////////////// -/// Helper to generate specialization info +// Helper to generate specialization info +// class Specialization { public: void add(uint32_t constantID, int32_t value) { spec_values.push_back(value); - vk::SpecializationMapEntry entry; + VkSpecializationMapEntry entry; entry.constantID = constantID; entry.size = sizeof(int32_t); entry.offset = static_cast(spec_entries.size() * sizeof(int32_t)); @@ -115,40 +116,37 @@ public: add(v.first, v.second); } - vk::SpecializationInfo* getSpecialization() + VkSpecializationInfo* getSpecialization() { - spec_info.setData(spec_values); - spec_info.setMapEntries(spec_entries); + spec_info.dataSize = static_cast(spec_values.size() * sizeof(int32_t)); + spec_info.pData = spec_values.data(); + spec_info.mapEntryCount = static_cast(spec_entries.size()); + spec_info.pMapEntries = spec_entries.data(); return &spec_info; } private: - std::vector spec_values; - std::vector spec_entries; - vk::SpecializationInfo spec_info; + std::vector spec_values; + std::vector spec_entries; + VkSpecializationInfo spec_info; }; ~~~~ -In `HelloVulkan::createRtPipeline()`, -first move the Closest Hit shader module creation up in the function next to the other one, as follow ... +In `HelloVulkan::createRtPipeline()`, we will create 8 specialization of the closest hit shader. +So the number of stages, will be 11 instead of 4. -~~~~ C -vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); -~~~~ - -Thenjust after creating the shader modules, create a `Specialization` for each of the 8 on/off permutations of the 3 constants. +~~~~ C + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, // <---- 8 specialization of this one + eShaderGroupCount = 11 + }; +~~~~ +Then create a `Specialization` for each of the 8 on/off permutations of the 3 constants. ~~~~ C // Specialization @@ -162,23 +160,35 @@ Thenjust after creating the shader modules, create a `Specialization` for each o } ~~~~ -Then we will create as many HIT shader groups as we have specializations. This will give us the ability later to choose which 'specialization' we want to use. +Now the shader group will be created 8 times, each with a different specialization. + +~~~~ C + // Hit Group - Closest Hit + // Create many variation of the closest hit + for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) + { + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stage.pSpecializationInfo = specializations[s].getSpecialization(); + stages[eClosestHit + s] = stage; + } +~~~~ + +**Tip** : We can avoid to create 8 shader modules, but we would have to properly deal with the + deletion of them at the end of the function. + + +We will also modify the creation of the hit group to create as many HIT shader groups as we have specializations. This will give us the ability later to choose which 'specialization' we want to use. ~~~~ C // Hit Group - Closest Hit + AnyHit - for(size_t i = 0; i < specializations.size(); i++) + // Creating many Hit groups, one for each specialization + for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) { - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - vk::PipelineShaderStageCreateInfo stage; - stage.stage = vk::ShaderStageFlagBits::eClosestHitKHR; - stage.module = chitSM; - stage.pName = "main"; - stage.pSpecializationInfo = specializations[i].getSpecialization(); - stages.push_back(stage); - m_rtShaderGroups.push_back(hg); + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit + s; // Using variation of the closest hit + m_rtShaderGroups.push_back(group); } ~~~~ diff --git a/ray_tracing_specialization/hello_vulkan.cpp b/ray_tracing_specialization/hello_vulkan.cpp index f1b7307..7e14367 100644 --- a/ray_tracing_specialization/hello_vulkan.cpp +++ b/ray_tracing_specialization/hello_vulkan.cpp @@ -20,9 +20,7 @@ #include #include -#include -extern std::vector defaultSearchPaths; #define STB_IMAGE_IMPLEMENTATION #include "obj_loader.h" @@ -39,6 +37,8 @@ extern std::vector defaultSearchPaths; #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +extern std::vector defaultSearchPaths; + // Holding the camera matrices struct CameraMatrices @@ -55,13 +55,10 @@ struct CameraMatrices // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images // -void HelloVulkan::setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) +void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) { - AppBase::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(device, physicalDevice); + AppBaseVk::setup(instance, device, physicalDevice, queueFamily); + m_alloc.init(instance, device, physicalDevice); m_debug.setup(m_device); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); } @@ -69,46 +66,46 @@ void HelloVulkan::setup(const vk::Instance& instance, //-------------------------------------------------------------------------------------------------- // Called at each frame to update the camera matrix // -void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) { // Prepare new UBO contents on host. const float aspectRatio = m_size.width / static_cast(m_size.height); CameraMatrices hostUBO = {}; hostUBO.view = CameraManip.getMatrix(); - hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); + hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). hostUBO.viewInverse = nvmath::invert(hostUBO.view); // #VKRay hostUBO.projInverse = nvmath::invert(hostUBO.proj); // UBO on the device, and what stages access it. - vk::Buffer deviceUBO = m_cameraMat.buffer; - auto uboUsageStages = - vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR; + VkBuffer deviceUBO = m_cameraMat.buffer; + auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; // Ensure that the modified UBO is not visible to previous frames. - vk::BufferMemoryBarrier beforeBarrier; - beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); - beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - beforeBarrier.setBuffer(deviceUBO); - beforeBarrier.setOffset(0); - beforeBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); + VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + beforeBarrier.buffer = deviceUBO; + beforeBarrier.offset = 0; + beforeBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &beforeBarrier, 0, nullptr); + // Schedule the host-to-device upload. (hostUBO is copied into the cmd // buffer so it is okay to deallocate when the function returns). - cmdBuf.updateBuffer(m_cameraMat.buffer, 0, hostUBO); + vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO); // Making sure the updated UBO will be visible. - vk::BufferMemoryBarrier afterBarrier; - afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); - afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); - afterBarrier.setBuffer(deviceUBO); - afterBarrier.setOffset(0); - afterBarrier.setSize(sizeof hostUBO); - cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, - vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); + VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; + afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + afterBarrier.buffer = deviceUBO; + afterBarrier.offset = 0; + afterBarrier.size = sizeof(hostUBO); + vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, + nullptr, 1, &afterBarrier, 0, nullptr); } //-------------------------------------------------------------------------------------------------- @@ -116,33 +113,27 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) // void HelloVulkan::createDescriptorSetLayout() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; auto nbTxt = static_cast(m_textures.size()); auto nbObj = static_cast(m_objModel.size()); // Camera matrices (binding = 0) - m_descSetLayoutBind.addBinding( - vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR)); + m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Materials (binding = 1) - m_descSetLayoutBind.addBinding( - vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Scene description (binding = 2) - m_descSetLayoutBind.addBinding( // - vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Textures (binding = 3) - m_descSetLayoutBind.addBinding( - vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Materials (binding = 4) - m_descSetLayoutBind.addBinding( - vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, + VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing vertices (binding = 5) - m_descSetLayoutBind.addBinding( // - vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // Storing indices (binding = 6) - m_descSetLayoutBind.addBinding( // - vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR)); + m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); @@ -155,25 +146,25 @@ void HelloVulkan::createDescriptorSetLayout() // void HelloVulkan::updateDescriptorSet() { - std::vector writes; + std::vector writes; // Camera matrices and scene description - vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); - vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; + VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); // All material buffers, 1 buffer per OBJ - std::vector dbiMat; - std::vector dbiMatIdx; - std::vector dbiVert; - std::vector dbiIdx; - for(auto& obj : m_objModel) + std::vector dbiMat; + std::vector dbiMatIdx; + std::vector dbiVert; + std::vector dbiIdx; + for(auto& m : m_objModel) { - dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); - dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); + dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE}); + dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE}); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); @@ -181,7 +172,7 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); // All texture samplers - std::vector diit; + std::vector diit; for(auto& texture : m_textures) { diit.emplace_back(texture.descriptor); @@ -189,40 +180,38 @@ void HelloVulkan::updateDescriptorSet() writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); // Writing the information - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } + //-------------------------------------------------------------------------------------------------- // Creating the pipeline layout // void HelloVulkan::createGraphicsPipeline() { - using vkSS = vk::ShaderStageFlagBits; - - vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0, - sizeof(ObjPushConstant)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)}; // Creating the Pipeline Layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - vk::DescriptorSetLayout descSetLayout(m_descSetLayout); - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_descSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); + // Creating the Pipeline std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); + gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); + gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({ - {0, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, pos))}, - {1, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, vk::Format::eR32G32B32Sfloat, static_cast(offsetof(VertexObj, color))}, - {3, 0, vk::Format::eR32G32Sfloat, static_cast(offsetof(VertexObj, texCoord))}, + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, + {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, }); m_graphicsPipeline = gpb.createPipeline(); @@ -234,8 +223,6 @@ void HelloVulkan::createGraphicsPipeline() // void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) { - using vkBU = vk::BufferUsageFlagBits; - LOGI("Loading File: %s \n", filename.c_str()); ObjLoader loader; loader.loadModel(filename); @@ -259,18 +246,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform model.nbVertices = static_cast(loader.m_vertices.size()); // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress - | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); + nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); + VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); + VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage); + model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage); + model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); // Creates all textures found createTextureImages(cmdBuf, loader.m_textures); cmdBufGet.submitAndWait(cmdBuf); @@ -286,17 +269,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform m_objInstance.emplace_back(instance); } + //-------------------------------------------------------------------------------------------------- // Creating the uniform buffer holding the camera matrices // - Buffer is host visible // void HelloVulkan::createUniformBuffer() { - using vkBU = vk::BufferUsageFlagBits; - using vkMP = vk::MemoryPropertyFlagBits; - - m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), - vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal); + m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); } @@ -308,11 +289,10 @@ void HelloVulkan::createUniformBuffer() // void HelloVulkan::createSceneDescriptionBuffer() { - using vkBU = vk::BufferUsageFlagBits; nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); auto cmdBuf = cmdGen.createCommandBuffer(); - m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); + m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); cmdGen.submitAndWait(cmdBuf); m_alloc.finalizeAndReleaseStaging(); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); @@ -321,15 +301,15 @@ void HelloVulkan::createSceneDescriptionBuffer() //-------------------------------------------------------------------------------------------------- // Creating all textures and samplers // -void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures) +void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) { - using vkIU = vk::ImageUsageFlagBits; + VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.maxLod = FLT_MAX; - vk::SamplerCreateInfo samplerCreateInfo{ - {}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear}; - samplerCreateInfo.setMaxLod(FLT_MAX); - vk::Format format = vk::Format::eR8G8B8A8Srgb; + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; // If no textures are present, create a dummy one to accommodate the pipeline layout if(textures.empty() && m_textures.empty()) @@ -337,18 +317,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, nvvk::Texture texture; std::array color{255u, 255u, 255u, 255u}; - vk::DeviceSize bufferSize = sizeof(color); - auto imgSize = vk::Extent2D(1, 1); + VkDeviceSize bufferSize = sizeof(color); + auto imgSize = VkExtent2D{1, 1}; auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal); + nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_textures.push_back(texture); } else @@ -361,8 +340,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, o << "media/textures/" << texture; std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - stbi_uc* stbi_pixels = - stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); std::array color{255u, 0u, 255u, 255u}; @@ -375,16 +353,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, pixels = reinterpret_cast(color.data()); } - vk::DeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = vk::Extent2D(texWidth, texHeight); - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); + VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; + auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; + auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); { nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - vk::ImageViewCreateInfo ivInfo = - nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); + nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); m_textures.push_back(texture); } @@ -399,10 +376,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, // void HelloVulkan::destroyResources() { - m_device.destroy(m_graphicsPipeline); - m_device.destroy(m_pipelineLayout); - m_device.destroy(m_descPool); - m_device.destroy(m_descSetLayout); + vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_descPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); + m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_sceneDesc); @@ -420,22 +398,23 @@ void HelloVulkan::destroyResources() } //#Post - m_device.destroy(m_postPipeline); - m_device.destroy(m_postPipelineLayout); - m_device.destroy(m_postDescPool); - m_device.destroy(m_postDescSetLayout); m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenDepth); - m_device.destroy(m_offscreenRenderPass); - m_device.destroy(m_offscreenFramebuffer); + vkDestroyPipeline(m_device, m_postPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); + vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + // #VKRay m_sbtWrapper.destroy(); m_rtBuilder.destroy(); - m_device.destroy(m_rtDescPool); - m_device.destroy(m_rtDescSetLayout); - m_device.destroy(m_rtPipeline); - m_device.destroy(m_rtPipelineLayout); + vkDestroyPipeline(m_device, m_rtPipeline, nullptr); + vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); + vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); m_alloc.deinit(); } @@ -443,32 +422,31 @@ void HelloVulkan::destroyResources() //-------------------------------------------------------------------------------------------------- // Drawing the scene in raster mode // -void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) +void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) { - using vkPBP = vk::PipelineBindPoint; - using vkSS = vk::ShaderStageFlagBits; - vk::DeviceSize offset{0}; + VkDeviceSize offset{0}; m_debug.beginLabel(cmdBuf, "Rasterize"); // Dynamic Viewport - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); // Drawing all triangles - cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); - cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); + + for(int i = 0; i < m_objInstance.size(); ++i) { auto& inst = m_objInstance[i]; auto& model = m_objModel[inst.objIndex]; m_pushConstant.instanceId = i; // Telling which instance is drawn - cmdBuf.pushConstants(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0, - m_pushConstant); - cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); - cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); - cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); + vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(ObjPushConstant), &m_pushConstant); + vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); + vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); } m_debug.endLabel(cmdBuf); } @@ -483,10 +461,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/) updateRtDescriptorSet(); } + ////////////////////////////////////////////////////////////////////////// // Post-processing ////////////////////////////////////////////////////////////////////////// + //-------------------------------------------------------------------------------------------------- // Creating an offscreen frame buffer and the associated render pass // @@ -498,29 +478,28 @@ void HelloVulkan::createOffscreenRender() // Creating the color image { auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - vk::ImageUsageFlagBits::eColorAttachment - | vk::ImageUsageFlagBits::eSampled - | vk::ImageUsageFlagBits::eStorage); + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); + VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; } // Creating the depth buffer - auto depthCreateInfo = - nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, - vk::ImageUsageFlagBits::eDepthStencilAttachment); + auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); { nvvk::Image image = m_alloc.createImage(depthCreateInfo); - vk::ImageViewCreateInfo depthStencilView; - depthStencilView.setViewType(vk::ImageViewType::e2D); - depthStencilView.setFormat(m_offscreenDepthFormat); - depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); - depthStencilView.setImage(image.image); + + VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = m_offscreenDepthFormat; + depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; + depthStencilView.image = image.image; m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); } @@ -529,11 +508,9 @@ void HelloVulkan::createOffscreenRender() { nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eGeneral); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, - vk::ImageLayout::eDepthStencilAttachmentOptimal, - vk::ImageAspectFlagBits::eDepth); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); genCmdBuf.submitAndWait(cmdBuf); } @@ -541,24 +518,23 @@ void HelloVulkan::createOffscreenRender() // Creating a renderpass for the offscreen if(!m_offscreenRenderPass) { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); + m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, + true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); } - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - m_device.destroy(m_offscreenFramebuffer); - vk::FramebufferCreateInfo info; - info.setRenderPass(m_offscreenRenderPass); - info.setAttachmentCount(2); - info.setPAttachments(attachments.data()); - info.setWidth(m_size.width); - info.setHeight(m_size.height); - info.setLayers(1); - m_offscreenFramebuffer = m_device.createFramebuffer(info); + // Creating the frame buffer for offscreen + std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; + + vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); + VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + info.renderPass = m_offscreenRenderPass; + info.attachmentCount = 2; + info.pAttachments = attachments.data(); + info.width = m_size.width; + info.height = m_size.height; + info.layers = 1; + vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); } //-------------------------------------------------------------------------------------------------- @@ -567,26 +543,23 @@ void HelloVulkan::createOffscreenRender() void HelloVulkan::createPostPipeline() { // Push constants in the fragment shader - vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; + VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; // Creating the pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; - pipelineLayoutCreateInfo.setSetLayoutCount(1); - pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); - m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); + VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + createInfo.setLayoutCount = 1; + createInfo.pSetLayouts = &m_postDescSetLayout; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRanges; + vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); + // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, - m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, - true), - vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), - vk::ShaderStageFlagBits::eFragment); - pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); - m_postPipeline = pipelineGenerator.createPipeline(); + nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); + pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); + pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); + pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; + m_postPipeline = pipelineGenerator.createPipeline(); m_debug.setObjectName(m_postPipeline, "post"); } @@ -596,43 +569,36 @@ void HelloVulkan::createPostPipeline() // void HelloVulkan::createPostDescriptor() { - using vkDS = vk::DescriptorSetLayoutBinding; - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - - m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); + m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); } + //-------------------------------------------------------------------------------------------------- // Update the output // void HelloVulkan::updatePostDescriptorSet() { - vk::WriteDescriptorSet writeDescriptorSets = - m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - m_device.updateDescriptorSets(writeDescriptorSets, nullptr); + VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); + vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); } //-------------------------------------------------------------------------------------------------- // Draw a full screen quad with the attached image // -void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) +void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) { m_debug.beginLabel(cmdBuf, "Post"); - cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); - cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}}); + setViewport(cmdBuf); auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - cmdBuf.pushConstants(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, - aspectRatio); - cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, - m_postDescSet, {}); - cmdBuf.draw(3, 1, 0, 0); + vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); + vkCmdDraw(cmdBuf, 3, 1, 0, 0); m_debug.endLabel(cmdBuf); } @@ -647,10 +613,10 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = - m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + prop2.pNext = &m_rtProperties; + vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); + m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); } @@ -661,35 +627,38 @@ void HelloVulkan::initRayTracing() auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { // BLAS builder requires raw device addresses. - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); - vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; + info.buffer = model.vertexBuffer.buffer; + VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info); + info.buffer = model.indexBuffer.buffer; + VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info); uint32_t maxPrimitiveCount = model.nbIndices / 3; // Describe buffer as array of VertexObj. - vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data. - triangles.setVertexData(vertexAddress); - triangles.setVertexStride(sizeof(VertexObj)); + VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; + triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data. + triangles.vertexData.deviceAddress = vertexAddress; + triangles.vertexStride = sizeof(VertexObj); // Describe index data (32-bit unsigned int) - triangles.setIndexType(vk::IndexType::eUint32); - triangles.setIndexData(indexAddress); + triangles.indexType = VK_INDEX_TYPE_UINT32; + triangles.indexData.deviceAddress = indexAddress; // Indicate identity transform by setting transformData to null device pointer. - triangles.setTransformData({}); - triangles.setMaxVertex(model.nbVertices); + //triangles.transformData = {}; + triangles.maxVertex = model.nbVertices; // Identify the above data as containing opaque triangles. - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setTriangles(triangles); + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + asGeom.geometry.triangles = triangles; // The entire array will be used to build the BLAS. - vk::AccelerationStructureBuildRangeInfoKHR offset; - offset.setFirstVertex(0); - offset.setPrimitiveCount(maxPrimitiveCount); - offset.setPrimitiveOffset(0); - offset.setTransformOffset(0); + VkAccelerationStructureBuildRangeInfoKHR offset; + offset.firstVertex = 0; + offset.primitiveCount = maxPrimitiveCount; + offset.primitiveOffset = 0; + offset.transformOffset = 0; // Our blas is made from only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::BlasInput input; @@ -714,7 +683,7 @@ void HelloVulkan::createBottomLevelAS() // We could add more geometry in each BLAS, but we add only one for now allBlas.emplace_back(blas); } - m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } void HelloVulkan::createTopLevelAS() @@ -731,7 +700,7 @@ void HelloVulkan::createTopLevelAS() rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } - m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); + m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); } //-------------------------------------------------------------------------------------------------- @@ -739,30 +708,33 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - using vkDT = vk::DescriptorType; - using vkSS = vk::ShaderStageFlagBits; - using vkDSLB = vk::DescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, - vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS - m_rtDescSetLayoutBind.addBinding( - vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to + // shoot shadow rays) + m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS + m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, + VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0]; - vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; - descASInfo.setAccelerationStructureCount(1); - descASInfo.setPAccelerationStructures(&tlas); - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; + VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocateInfo.descriptorPool = m_rtDescPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_rtDescSetLayout; + vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - std::vector writes; + + VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); + VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; + descASInfo.accelerationStructureCount = 1; + descASInfo.pAccelerationStructures = &tlas; + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + + std::vector writes; writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); - m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); } @@ -772,25 +744,23 @@ void HelloVulkan::createRtDescriptorSet() // void HelloVulkan::updateRtDescriptorSet() { - using vkDT = vk::DescriptorType; - // (1) Output buffer - vk::DescriptorImageInfo imageInfo{ - {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; - vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo}; - m_device.updateDescriptorSets(wds, nullptr); + VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo); + vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); } ////////////////////////////////////////////////////////////////////////// -/// Helper to generate specialization info +// Helper to generate specialization info +// class Specialization { public: void add(uint32_t constantID, int32_t value) { spec_values.push_back(value); - vk::SpecializationMapEntry entry; + VkSpecializationMapEntry entry; entry.constantID = constantID; entry.size = sizeof(int32_t); entry.offset = static_cast(spec_entries.size() * sizeof(int32_t)); @@ -803,17 +773,19 @@ public: add(v.first, v.second); } - vk::SpecializationInfo* getSpecialization() + VkSpecializationInfo* getSpecialization() { - spec_info.setData(spec_values); - spec_info.setMapEntries(spec_entries); + spec_info.dataSize = static_cast(spec_values.size() * sizeof(int32_t)); + spec_info.pData = spec_values.data(); + spec_info.mapEntryCount = static_cast(spec_entries.size()); + spec_info.pMapEntries = spec_entries.data(); return &spec_info; } private: - std::vector spec_values; - std::vector spec_entries; - vk::SpecializationInfo spec_info; + std::vector spec_values; + std::vector spec_entries; + VkSpecializationInfo spec_info; }; @@ -822,21 +794,16 @@ private: // void HelloVulkan::createRtPipeline() { - vk::ShaderModule raygenSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - vk::ShaderModule missSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + enum StageIndices + { + eRaygen, + eMiss, + eMiss2, + eClosestHit, // <---- 8 specialization of this one + eShaderGroupCount = 11 + }; - // The second miss shader is invoked when a shadow ray misses the geometry. It - // simply indicates that no occlusion has been found - vk::ShaderModule shadowmissSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - - vk::ShaderModule chitSM = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - - // Specialization + // Specialization - set 8 permutations of the 3 constant std::vector specializations(8); for(int i = 0; i < 8; i++) { @@ -846,95 +813,119 @@ void HelloVulkan::createRtPipeline() specializations[i].add({{0, a}, {1, b}, {2, c}}); } - std::vector stages; + // All stages + std::array stages{}; + VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.pName = "main"; // All the same entry point // Raygen - vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - rg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); - m_rtShaderGroups.push_back(rg); + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + stages[eRaygen] = stage; // Miss - vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); - m_rtShaderGroups.push_back(mg); - // Shadow Miss - mg.setGeneralShader(static_cast(stages.size())); - stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); - m_rtShaderGroups.push_back(mg); + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss] = stage; + // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found + stage.module = + nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; + stages[eMiss2] = stage; - // Hit Group - Closest Hit + AnyHit - for(auto& specialization : specializations) + // Hit Group - Closest Hit + // Create many variation of the closest hit + for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) { - vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, - VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; - hg.setClosestHitShader(static_cast(stages.size())); - vk::PipelineShaderStageCreateInfo stage; - stage.stage = vk::ShaderStageFlagBits::eClosestHitKHR; - stage.module = chitSM; - stage.pName = "main"; - stage.pSpecializationInfo = specialization.getSpecialization(); - stages.push_back(stage); - m_rtShaderGroups.push_back(hg); + stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); + stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + stage.pSpecializationInfo = specializations[s].getSpecialization(); + stages[eClosestHit + s] = stage; } - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + // Shader groups + VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; + group.anyHitShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = VK_SHADER_UNUSED_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.intersectionShader = VK_SHADER_UNUSED_KHR; + + // Raygen + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eRaygen; + m_rtShaderGroups.push_back(group); + + // Miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss; + m_rtShaderGroups.push_back(group); + + // Shadow Miss + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group.generalShader = eMiss2; + m_rtShaderGroups.push_back(group); + + // Hit Group - Closest Hit + AnyHit + // Creating many Hit groups, one for each specialization + for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) + { + group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group.generalShader = VK_SHADER_UNUSED_KHR; + group.closestHitShader = eClosestHit + s; // Using variation of the closest hit + m_rtShaderGroups.push_back(group); + } // Push constant: we want to be able to update constants used by the shaders - vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, sizeof(RtPushConstant)}; - pipelineLayoutCreateInfo.setPushConstantRangeCount(1); - pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); + VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant)}; + + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setSetLayoutCount(static_cast(rtDescSetLayouts.size())); - pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); + std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); + + vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); // Assemble the shader stages and recursion depth info into the ray tracing pipeline - - vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; - rayPipelineInfo.setStageCount(static_cast(stages.size())); // Stages are shaders - rayPipelineInfo.setPStages(stages.data()); + VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; + rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders + rayPipelineInfo.pStages = stages.data(); // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, // two miss shader groups, and one hit group. - rayPipelineInfo.setGroupCount(static_cast(m_rtShaderGroups.size())); - rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); + rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); + rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth - rayPipelineInfo.setLayout(m_rtPipelineLayout); + // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the + // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low + // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop + // in the ray generation to avoid deep recursion. + rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth + rayPipelineInfo.layout = m_rtPipelineLayout; - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; + vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. if(m_rtProperties.maxRayRecursionDepth <= 1) { - throw std::runtime_error( - "Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); + throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); } - m_device.destroy(raygenSM); - m_device.destroy(missSM); - m_device.destroy(shadowmissSM); - m_device.destroy(chitSM); + for(auto& s : stages) + vkDestroyShaderModule(m_device, s.module, nullptr); } //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene // -void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) +void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) { m_debug.beginLabel(cmdBuf, "Ray trace"); // Initializing push constant values @@ -944,19 +935,16 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& m_rtPushConstants.lightType = m_pushConstant.lightType; m_rtPushConstants.specialization = m_pushConstant.specialization; - cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline); - cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, - {m_rtDescSet, m_descSet}, {}); - cmdBuf.pushConstants(m_rtPipelineLayout, - vk::ShaderStageFlagBits::eRaygenKHR - | vk::ShaderStageFlagBits::eClosestHitKHR - | vk::ShaderStageFlagBits::eMissKHR, - 0, m_rtPushConstants); - - auto regions = m_sbtWrapper.getRegions(); - cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], // - m_size.width, m_size.height, 1); + std::vector descSets{m_rtDescSet, m_descSet}; + vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); + vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, + (uint32_t)descSets.size(), descSets.data(), 0, nullptr); + vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, + VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + 0, sizeof(RtPushConstant), &m_rtPushConstants); + auto& regions = m_sbtWrapper.getRegions(); + vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing_specialization/hello_vulkan.h b/ray_tracing_specialization/hello_vulkan.h index f20cb9a..d2a1ad1 100644 --- a/ray_tracing_specialization/hello_vulkan.h +++ b/ray_tracing_specialization/hello_vulkan.h @@ -18,13 +18,12 @@ */ #pragma once -#include - -#include "nvvk/appbase_vkpp.hpp" +#include "nvvk/appbase_vk.hpp" #include "nvvk/debug_util_vk.hpp" #include "nvvk/descriptorsets_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp" +#include "nvvk/resourceallocator_vk.hpp" // #VKRay #include "nvvk/raytraceKHR_vk.hpp" @@ -37,25 +36,21 @@ // - Rendering is done in an offscreen framebuffer // - The image of the framebuffer is displayed in post-process in a full-screen quad // -class HelloVulkan : public nvvk::AppBase +class HelloVulkan : public nvvk::AppBaseVk { public: - void setup(const vk::Instance& instance, - const vk::Device& device, - const vk::PhysicalDevice& physicalDevice, - uint32_t queueFamily) override; + void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; void createDescriptorSetLayout(); void createGraphicsPipeline(); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void updateDescriptorSet(); void createUniformBuffer(); void createSceneDescriptionBuffer(); - void createTextureImages(const vk::CommandBuffer& cmdBuf, - const std::vector& textures); - void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); + void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); + void updateUniformBuffer(const VkCommandBuffer& cmdBuf); void onResize(int /*w*/, int /*h*/) override; void destroyResources(); - void rasterize(const vk::CommandBuffer& cmdBuff); + void rasterize(const VkCommandBuffer& cmdBuff); // The OBJ model struct ObjModel @@ -93,39 +88,41 @@ public: std::vector m_objInstance; // Graphic pipeline - vk::PipelineLayout m_pipelineLayout; - vk::Pipeline m_graphicsPipeline; + VkPipelineLayout m_pipelineLayout; + VkPipeline m_graphicsPipeline; nvvk::DescriptorSetBindings m_descSetLayoutBind; - vk::DescriptorPool m_descPool; - vk::DescriptorSetLayout m_descSetLayout; - vk::DescriptorSet m_descSet; + VkDescriptorPool m_descPool; + VkDescriptorSetLayout m_descSetLayout; + VkDescriptorSet m_descSet; nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances std::vector m_textures; // vector of all textures of the scene + nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::DebugUtil m_debug; // Utility to name objects + // #Post void createOffscreenRender(); void createPostPipeline(); void createPostDescriptor(); void updatePostDescriptorSet(); - void drawPost(vk::CommandBuffer cmdBuf); + void drawPost(VkCommandBuffer cmdBuf); nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - vk::DescriptorPool m_postDescPool; - vk::DescriptorSetLayout m_postDescSetLayout; - vk::DescriptorSet m_postDescSet; - vk::Pipeline m_postPipeline; - vk::PipelineLayout m_postPipelineLayout; - vk::RenderPass m_offscreenRenderPass; - vk::Framebuffer m_offscreenFramebuffer; + VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; + VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; + VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; + VkPipeline m_postPipeline{VK_NULL_HANDLE}; + VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; + VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; + VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; nvvk::Texture m_offscreenColor; - vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; nvvk::Texture m_offscreenDepth; - vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; + VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; + VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; // #VKRay void initRayTracing(); @@ -135,19 +132,19 @@ public: void createRtDescriptorSet(); void updateRtDescriptorSet(); void createRtPipeline(); - void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); + void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - vk::DescriptorPool m_rtDescPool; - vk::DescriptorSetLayout m_rtDescSetLayout; - vk::DescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - vk::PipelineLayout m_rtPipelineLayout; - vk::Pipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; + nvvk::RaytracingBuilderKHR m_rtBuilder; + nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; + VkDescriptorPool m_rtDescPool; + VkDescriptorSetLayout m_rtDescSetLayout; + VkDescriptorSet m_rtDescSet; + std::vector m_rtShaderGroups; + VkPipelineLayout m_rtPipelineLayout; + VkPipeline m_rtPipeline; + nvvk::SBTWrapper m_sbtWrapper; struct RtPushConstant { diff --git a/ray_tracing_specialization/main.cpp b/ray_tracing_specialization/main.cpp index 7c6aeee..d0e1e8a 100644 --- a/ray_tracing_specialization/main.cpp +++ b/ray_tracing_specialization/main.cpp @@ -23,8 +23,6 @@ // at the top of imgui.cpp. #include -#include -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" @@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" -#include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" @@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // Default search path for shaders std::vector defaultSearchPaths; + // GLFW Callback functions static void onErrorCallback(int error, const char* description) { @@ -84,6 +82,7 @@ void renderUI(HelloVulkan& helloVk) static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; + //-------------------------------------------------------------------------------------------------- // Application Entry // @@ -98,8 +97,7 @@ int main(int argc, char** argv) return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = - glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); @@ -123,12 +121,12 @@ int main(int argc, char** argv) }; // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo(true); + nvvk::ContextCreateInfo contextInfo; contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); -#ifdef WIN32 +#ifdef _WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); @@ -138,19 +136,19 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); + // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, - &accelFeature); - vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, - &rtPipelineFeature); + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; + contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - // Creating Vulkan base application nvvk::Context vkctx{}; vkctx.initInstance(contextInfo); @@ -160,16 +158,14 @@ int main(int argc, char** argv) // Use a compatible device vkctx.initDevice(compatibleDevices[0], contextInfo); - // Create example HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw - const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); + const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, - vkctx.m_queueGCT.familyIndex); + helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); @@ -229,9 +225,7 @@ int main(int argc, char** argv) ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", - 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } @@ -240,28 +234,29 @@ int main(int argc, char** argv) helloVk.prepareFrame(); // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; + auto curFrame = helloVk.getCurFrame(); + const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmdBuf, &beginInfo); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen - std::array clearValues; - clearValues[0].setColor( - std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); - clearValues[1].setDepthStencil({1.0f, 0}); + std::array clearValues{}; + clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; + clearValues[1].depthStencil = {1.0f, 0}; // Offscreen render pass { - vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; - offscreenRenderPassBeginInfo.setClearValueCount(2); - offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); - offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); - offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); - offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + offscreenRenderPassBeginInfo.clearValueCount = 2; + offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); + offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; + offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; + offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; // Rendering Scene if(useRaytracer) @@ -270,40 +265,40 @@ int main(int argc, char** argv) } else { - cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); + vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.rasterize(cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } } // 2nd rendering pass: tone mapper, UI { - vk::RenderPassBeginInfo postRenderPassBeginInfo; - postRenderPassBeginInfo.setClearValueCount(2); - postRenderPassBeginInfo.setPClearValues(clearValues.data()); - postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); - postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); - postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); + VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + postRenderPassBeginInfo.clearValueCount = 2; + postRenderPassBeginInfo.pClearValues = clearValues.data(); + postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); + postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; + postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper + vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); helloVk.drawPost(cmdBuf); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - cmdBuf.endRenderPass(); + vkCmdEndRenderPass(cmdBuf); } // Submit for display - cmdBuf.end(); + vkEndCommandBuffer(cmdBuf); helloVk.submitFrame(); } // Cleanup - helloVk.getDevice().waitIdle(); + vkDeviceWaitIdle(helloVk.getDevice()); + helloVk.destroyResources(); helloVk.destroy(); - vkctx.deinit(); glfwDestroyWindow(window);