diff --git a/CMakeLists.txt b/CMakeLists.txt index ee6f590..9484aee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,37 +1,42 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) project(vk_raytracing_tutorial) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # look for shared_sources 1) as a sub-folder 2) at some other locations # this cannot be put anywhere else since we still didn't find CMakeLists_include.txt yet -# -if(NOT BASE_DIRECTORY) # if not defined, it means this cmake file was called as the first entry point and not included - # check if the external repository is outside or inside the project (as a sub-module) - # testing the file CMakeLists_include.txt because when sub-modules are not cloned, the folders are still there... - # we also assume here that if shared_sources is there, shared_external is, too... - SET(BASE_DIRECTORY "" CACHE FILEPATH "folder containing shared_sources") +if(NOT BASE_DIRECTORY) + SET(BASE_DIRECTORY "" CACHE FILEPATH "folder containing shared_sources") SET(ADD_SUBDIR_BELOW 1) - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/shared_sources/CMakeLists_include.txt) - SET(BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../shared_sources/CMakeLists_include.txt) - SET(BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..) - elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../../shared_sources/CMakeLists_include.txt) - SET(BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../..) - else() - endif() -endif(NOT BASE_DIRECTORY) - -if(EXISTS ${BASE_DIRECTORY}/shared_sources/CMakeLists_include.txt) - INCLUDE(${BASE_DIRECTORY}/shared_sources/CMakeLists_include.txt) -else() - Message(FATAL_ERROR "could not find base directory, please set BASE_DIRECTORY to folder containing shared_sources") + find_path(BASE_DIRECTORY2 + NAMES shared_sources + PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR} + REQUIRED + DOC "Couldn't find shared_source directory'" + ) + SET(BASE_DIRECTORY ${BASE_DIRECTORY2} ) endif() + +## Various functions and macros REQUIRED +include(${BASE_DIRECTORY}/shared_sources/CMakeLists_include.txt) +set(TUTO_KHR_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +# presets and utility functions used in all CMakeLists +include(utilities.cmake) + +#-------------------------------------------------------------------------------------------------- +# Package shared by all projects _add_package_VulkanSDK() _add_package_OpenGL() _add_package_ImGUI() _add_package_ZLIB() _add_shared_sources_lib() +message(STATUS "COPY ${CMAKE_CURRENT_SOURCE_DIR}/media to ${EXECUTABLE_OUTPUT_PATH}") +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/media DESTINATION ${EXECUTABLE_OUTPUT_PATH}) + + +#-------------------------------------------------------------------------------------------------- +# Sub examples add_subdirectory(ray_tracing__advance) add_subdirectory(ray_tracing__before) add_subdirectory(ray_tracing__simple) diff --git a/docs/Images/resultRasterCube.png b/docs/Images/resultRasterCube.png index 69a3f4f..7298d3a 100644 Binary files a/docs/Images/resultRasterCube.png and b/docs/Images/resultRasterCube.png differ diff --git a/docs/Images/resultRaytraceShadowMedieval.png b/docs/Images/resultRaytraceShadowMedieval.png index 2e9024d..d58a1f7 100644 Binary files a/docs/Images/resultRaytraceShadowMedieval.png and b/docs/Images/resultRaytraceShadowMedieval.png differ diff --git a/docs/setup.md b/docs/setup.md index 55d1f15..a954bae 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -9,6 +9,14 @@ Besides the current repository, you will also need to clone or download the foll * [shared_sources](https://github.com/nvpro-samples/shared_sources): The primary framework that all samples depend on. * [shared_external](https://github.com/nvpro-samples/shared_external): Third party libraries that are provided pre-compiled, mostly for Windows x64 / MSVC. +Cloning all repositories + +~~~~~ +git clone https://github.com/nvpro-samples/shared_sources.git +git clone https://github.com/nvpro-samples/shared_external.git +git clone https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR.git +~~~~~ + The directory structure should be looking like this: ~~~~ @@ -44,7 +52,7 @@ Vulkan driver. The CMakefile will use other makefiles from `shared_sources` and look for Vulkan environment variables for the installation of the SDK. Therefore, it is important to have all the above installed before running Cmake in the `vk_raytracing_tutorial_KHR` directory. -:warning: **Note:** If you are using your own Vulkan header files, it is possible to overide the default search path. +**Note:** If you are using your own Vulkan header files, it is possible to overide the default search path. Modify `VULKAN > VULKAN_HEADERS_OVERRIDE_INCLUDE_DIR` to the path to beta vulkan headers. ## Starting From Extra Tutorial diff --git a/docs/vkrt_tuto_manyhits.md.htm b/docs/vkrt_tuto_manyhits.md.htm index 966e1d9..fc6a638 100644 --- a/docs/vkrt_tuto_manyhits.md.htm +++ b/docs/vkrt_tuto_manyhits.md.htm @@ -218,11 +218,11 @@ The size of each group can be described as follows: ~~~~ C++ // Sizes - uint32_t rayGenSize = baseAlignment; - uint32_t missSize = baseAlignment; + uint32_t rayGenSize = groupSizeAligned; + uint32_t missSize = groupSizeAligned; uint32_t hitSize = - ROUND_UP(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), baseAlignment); - uint32_t newSbtSize = rayGenSize + 2 * missSize + 2 * hitSize; + nvh::align_up(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), groupSizeAligned); + uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize; ~~~~ Then write the new SBT like this, where only Hit 1 has extra data. @@ -258,21 +258,23 @@ Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sb m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR); ~~~~ -Note: we are using this `define` for rounding up to the correct alignment -~~~~ C++ -#ifndef ROUND_UP -#define ROUND_UP(v, powerOf2Alignment) (((v) + (powerOf2Alignment)-1) & ~((powerOf2Alignment)-1)) -#endif -~~~~ - ## `raytrace` -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`. +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 hitGroupStride = -ROUND_UP(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), progOffset); +vk::DeviceSize hitGroupSize = + nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), + m_rtProperties.shaderGroupBaseAlignment); + + +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{0u, 0u, 0u}}; // callable ~~~~ !!! Note: diff --git a/docs/vkrt_tutorial.md.htm b/docs/vkrt_tutorial.md.htm index 5bfdfce..a99a8e2 100644 --- a/docs/vkrt_tutorial.md.htm +++ b/docs/vkrt_tutorial.md.htm @@ -36,78 +36,90 @@ verbosity and its potential for errors. # Environment Setup +**The preferred way** to download the project (including NVVK) is to use the +nvpro-samples `build_all` script. + +In a command line, clone the `nvpro-samples/build_all` repository from +https://github.com/nvpro-samples/build_all: + +~~~~~ +git clone https://github.com/nvpro-samples/build_all.git +~~~~~ + +Then open the `build_all` folder and run either `clone_all.bat` (Windows) or +`clone_all.sh` (Linux). + +**If you want to clone as few repositories as possible**, open a command line, +and run the following commands to clone the repositories you need: +~~~~~ +git clone https://github.com/nvpro-samples/shared_sources.git +git clone https://github.com/nvpro-samples/shared_external.git +git clone https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR.git +~~~~~ + +## Generating the Solution + +One typical way to store the build system is to create a `build` directory below the +main project. You can use CMake-GUI or do the following steps. + +~~~~~ +cd vk_raytracing_tutorial_KHR +mkdir build +cd build +cmake .. +~~~~~ ## Beta Installation -The SDK 1.2.135 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project. +The SDK 1.2.161 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project. Nevertheless, if you are in the Beta period, it is suggested to install and compile all of the following and replace with the current environment. * Latest driver: https://developer.nvidia.com/vulkan-driver -* Latest Vulkan headers: https://github.com/KhronosGroup/Vulkan-Headers -* Latest glslangValidator: https://github.com/KhronosGroup/glslang - -## Structure - -This tutorial is a modification of [`ray_tracing__before`](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/tree/master/ray_tracing__before), which loads are render OBJ scenes with Vulkan rasterizer. -All following instructions are based on the modification of this project. -The directory `ray_tracing__simple` is the end result of this tutorial. - -Besides the current repository, you will also need to clone or download the following repositories: - -* [shared_sources](https://github.com/nvpro-samples/shared_sources): The primary framework that all samples depend on. -* [shared_external](https://github.com/nvpro-samples/shared_external): Third party libraries that are provided pre-compiled, mostly for Windows x64 / MSVC. - -The directory structure should be looking like: - -********************************************************** -* \ -* | -* +-- 📂 shared_external -* | -* +-- 📂 shared_sources -* | -* +-- 📂 vk_raytracing_tutorial_KHR -* | | -* | +-- 📂 ray_tracing__before -* | | -* | ⋮ -* | -* ⋮ -********************************************************** - - -!!! Warning - **Run CMake** in vk_raytracing_tutorial_KHR. - -!!! Warning Beta - Modify `VULKAN > VULKAN_HEADERS_OVERRIDE_INCLUDE_DIR` to the path to beta vulkan headers. +* Vulkan headers: https://github.com/KhronosGroup/Vulkan-Headers +* Validator: https://github.com/KhronosGroup/Vulkan-ValidationLayers +* Vulkan-Hpp: https://github.com/KhronosGroup/Vulkan-Hpp !!! Tip Visual Assist To get auto-completion, edit vulkan.hpp and change two places from:
`namespace VULKAN_HPP_NAMESPACE` to `namespace vk` -The starting project is a simple framework allowing us to load OBJ files and rasterize them +# Compiling & Running + +Open the solution located in the build directory, then compile and run `vk_ray_tracing__before_KHR`. + +This will be the starting point of the tutorial. This project is a simple framework allowing us to load OBJ files and rasterize them using Vulkan. ![First Run](Images/resultRasterCube.png width="350px") +The following steps in the tutorial will be modifying this project +`vk_ray_tracing__before_KHR` and will add support for ray tracing. The +end result of the tutorial is the project `vk_ray_tracing__simple_KHR`. +It is possible to look in that project if something went wrong. + +The project `vk_ray_tracing__simple_KHR` will be the starting point for the +extra tutorials. + # Ray Tracing Setup Go to the `main` function of the `main.cpp` file, and find where we request Vulkan extensions with `nvvk::ContextCreateInfo`. -To request ray tracing capabilities, we need to explicitly -add the -[VK_KHR_ray_tracing](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_ray_tracing.html) -extension as well as its various dependencies. +To be able to use ray tracing, we will need VK_KHR_ACCELERATION_STRUCTURE and VK_KHR_RAY_TRACING_PIPELINE. +Those extensions have also dependencies on other extension, therefore all the following +extensions will need to be added. ```` C // #VKRay: Activate the ray tracing extension -vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; -contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); +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); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); @@ -115,20 +127,20 @@ contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); ```` -Before creating the device, a linked structure of features must past. Not all extensions requires a set of features, but -ray tracing features must be enabled before the creation of the device. By providing -`raytracingFeature`, the context creation will query the capable features for ray tracing and will use the -filled structure to create the device. - +Before creating the device, a linked structure of features must past. Not all extensions +requires a set of features, but ray tracing features must be enabled before the creation of the device. +By providing `accelFeature`, and `rtPipelineFeature`, the context creation will query the capable features + for ray tracing and will use the filled structure to create the device. 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::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; +void initRayTracing(); +vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; ```` + At the end of `hello_vulkan.cpp`, add the body of `initRayTracing()`, which will query the ray tracing capabilities of the GPU using this extension. In particular, it will obtain the maximum recursion depth, ie. the number of nested ray tracing calls that can be performed from a single ray. This can be seen as the number @@ -144,15 +156,17 @@ creating the shader binding table in a later section. void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); } ```` ## main -In `main.cpp`, in the `main()` function, we call the initialization method right after `helloVk.updateDescriptorSet();` +In `main.cpp`, in the `main()` function, we call the initialization method right after +`helloVk.updateDescriptorSet();` ```` C // #VKRay @@ -188,12 +202,11 @@ This sample loads an OBJ file and stores its indices, vertices and material data model is referenced by an `ObjInstance` structure which also contains the transformation matrix of that particular instance. For ray tracing the `ObjModel` and `ObjInstance` will then naturally fit the BLAS and TLAS, respectively. -To simplify the ray tracing setup we use a helper class containing utility functions for acceleration structure builds. -In the header file, include the`raytrace_vkpp` helper +To simplify the ray tracing setup we use a helper class containing utility functions for +acceleration structure builds. In the header file, include the`raytrace_vkpp` helper ```` C // #VKRay -#define ALLOC_DEDICATED #include "nvvk/raytrace_vk.hpp" ```` @@ -224,11 +237,12 @@ nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); Its implementation will fill three structures -* vk::AccelerationStructureCreateGeometryTypeInfoKHR: that defines how the AS will be constructed. -* vk::AccelerationStructureGeometryKHR: the geometry for build the AS, in this case, from triangles. -* vk::AccelerationStructureBuildOffsetInfoKHR: the offset, which correspond to the actual wanted geometry when building. +* vk::AccelerationStructureGeometryTrianglesDataKHR: defines the data from which the AS will be constructed. +* vk::AccelerationStructureGeometryKHR: the geometry type for building the AS, in this case, from triangles. +* vk::AccelerationStructureBuildRangeInfoKHR: the offset, which correspond to the actual wanted geometry when building. -Multiple of the above structure can be combined to create a single blas. In this example, the array will always be a length of one. +Multiple of the above structure can be combined to create a single blas. In this example, +the array will always be a length of one. Note that we consider all objects opaque for now, and indicate this to the builder for potential optimization. @@ -239,44 +253,37 @@ potential optimization. // nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - // Setting up the creation info of acceleration structure - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - // Building part vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + uint32_t maxPrimitiveCount = model.nbIndices / 3; + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); // Setting up the build info of the acceleration vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); // The primitive itself - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(maxPrimitiveCount); offset.setPrimitiveOffset(0); offset.setTransformOffset(0); // Our blas is only one geometry, but could be made of many geometries nvvk::RaytracingBuilderKHR::Blas blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; @@ -817,7 +824,7 @@ void HelloVulkan::createRtDescriptorSet() 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::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; descASInfo.setAccelerationStructureCount(1); descASInfo.setPAccelerationStructures(&tlas); @@ -825,8 +832,8 @@ void HelloVulkan::createRtDescriptorSet() {}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral}; 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, 0, &descASInfo)); + writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); m_device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, nullptr); } ```` @@ -840,27 +847,27 @@ index buffers. Even though the vertex and index buffers will only be used by the 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)); +// 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)); ```` We set the actual contents of the descriptor set by adding those buffers in `updateDescriptorSet()`: @@ -884,14 +891,23 @@ We set the actual contents of the descriptor set by adding those buffers in `upd 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. The ray tracing -will need to use those buffers as storage buffers. We update the usage of the buffers in `loadModel`: +Originally the buffers containing the vertices and indices were only used by the rasterization pipeline. +The ray tracing will need to use those buffers as storage buffers (`VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT`), +the address to those buffers are needed to fill the `VkAccelerationStructureGeometryTrianglesDataKHR` structure, +and because they are use for constructing the acceleration structure, they also need +the `VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR` flag. + +We update the usage of the buffers in `loadModel`: ```` C - model.vertexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_vertices, vkBU::eVertexBuffer | vkBU::eStorageBuffer); - model.indexBuffer = - m_alloc.createBuffer(cmdBuf, loader.m_indices, vkBU::eIndexBuffer | vkBU::eStorageBuffer); +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); ```` !!! Note: Array of Buffers @@ -1076,10 +1092,10 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true)); std::vector stages; @@ -1114,7 +1130,7 @@ shaders. // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -1192,9 +1208,10 @@ call as a miss. Note that it is preferable to keep the recursion level as low as formulation instead. ```` C - rayPipelineInfo.setMaxRecursionDepth(1); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(1); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, rayPipelineInfo); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); ```` Once the pipeline has been created we discard the shader modules: @@ -1279,23 +1296,29 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; ```` -We then fetch the handles to the shader groups of the pipeline, and let the allocator allocate the device memory and -copy the handles into the SBT: +We then fetch the handles to the shader groups of the pipeline, and let the allocator +allocate the device memory and copy the handles into the SBT. Note that SBT buffer need the +`VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR` flag and since we will need the address +of SBT buffer, therefore the buffer need also the `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` flag. ```` C std::vector shaderHandleStorage(sbtSize); m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); - // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + + // Write the handles in the SBT + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -1304,7 +1327,7 @@ copy the handles into the SBT: for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -1366,12 +1389,21 @@ each shader. In our case the stride is simply the size of a shader group handle, shader-group-specific data within the SBT, resulting in a larger stride. ```` C - vk::DeviceSize progSize = m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize missStride = progSize; - vk::DeviceSize hitGroupOffset = 2u * progSize; // Jump over the previous shaders - vk::DeviceSize hitGroupStride = progSize; +// Size of a program identifier + uint32_t groupSize = + nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; + vk::DeviceSize hitGroupSize = + nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), + m_rtProperties.shaderGroupBaseAlignment); + vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); + + 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, hitGroupSize, hitGroupSize * 3}, // hit + Stride{0u, 0u, 0u}}; // callable ```` @@ -1382,19 +1414,9 @@ 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 -vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); - -const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; -const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; -const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; -const vk::StridedBufferRegionKHR callableShaderBindingTable; - -cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // - 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); } @@ -1823,8 +1845,8 @@ The OBJ model is loaded in `main.cpp` by calling `helloVk.loadModel`. Let's load ```` C // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); ```` Since that model is larger, we can change the `CameraManip.setLookat` call to @@ -1860,7 +1882,7 @@ In the body of `createRtPipeline`, we need to define the new miss shader right a // simply indicates that no occlusion has been found vk::ShaderModule shadowmissSM = nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); ```` @@ -1880,7 +1902,7 @@ 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.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth ```` At the end of the method, we destroy the shader module for the shadow miss shader: diff --git a/ray_tracing__advance/CMakeLists.txt b/ray_tracing__advance/CMakeLists.txt index 4a1c58b..3d537a1 100644 --- a/ray_tracing__advance/CMakeLists.txt +++ b/ray_tracing__advance/CMakeLists.txt @@ -1,31 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) -##################################################################################### +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") + + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -44,41 +51,27 @@ foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -91,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing__advance/hello_vulkan.cpp b/ray_tracing__advance/hello_vulkan.cpp index 6e086fd..3a25711 100644 --- a/ray_tracing__advance/hello_vulkan.cpp +++ b/ray_tracing__advance/hello_vulkan.cpp @@ -32,7 +32,6 @@ extern std::vector defaultSearchPaths; #define VMA_IMPLEMENTATION - #define STB_IMAGE_IMPLEMENTATION #include "fileformats/stb_image.h" #include "obj_loader.h" @@ -200,7 +199,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -234,8 +233,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass()); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions(std::vector{ {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, @@ -254,6 +253,7 @@ 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); @@ -280,10 +280,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -378,9 +380,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -538,12 +541,16 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& void HelloVulkan::updateFrame() { static nvmath::mat4f refCamMatrix; + static float refFov{CameraManip.getFov()}; - auto& m = CameraManip.getMatrix(); - if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) + const auto& m = CameraManip.getMatrix(); + const auto fov = CameraManip.getFov(); + + if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov) { resetFrame(); refCamMatrix = m; + refFov = fov; } m_pushConstants.frame++; } diff --git a/ray_tracing__advance/main.cpp b/ray_tracing__advance/main.cpp index 28ce493..a87c55a 100644 --- a/ray_tracing__advance/main.cpp +++ b/ray_tracing__advance/main.cpp @@ -44,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" +#include "imgui_camera_widget.h" #include ////////////////////////////////////////////////////////////////////////// @@ -64,47 +65,46 @@ void renderUI(HelloVulkan& helloVk) { static int item = 1; bool changed = false; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) - { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); - changed = true; - } - changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstants.lightType, 0); - ImGui::SameLine(); - changed |= ImGui::RadioButton("Spot", &helloVk.m_pushConstants.lightType, 1); - ImGui::SameLine(); - changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstants.lightType, 2); - if(helloVk.m_pushConstants.lightType < 2) - { - 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); - } - if(helloVk.m_pushConstants.lightType < 2) - { - changed |= - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f); - } - if(helloVk.m_pushConstants.lightType == 1) - { - float dCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotCutoff)); - float dOutCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotOuterCutoff)); - changed |= ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); - changed |= ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); - dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; - helloVk.m_pushConstants.lightSpotCutoff = cos(deg2rad(dCutoff)); - helloVk.m_pushConstants.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); + changed |= ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) + { + changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstants.lightType, 0); + ImGui::SameLine(); + changed |= ImGui::RadioButton("Spot", &helloVk.m_pushConstants.lightType, 1); + ImGui::SameLine(); + changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstants.lightType, 2); + + + if(helloVk.m_pushConstants.lightType < 2) + { + 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); + } + if(helloVk.m_pushConstants.lightType < 2) + { + changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, + 500.f); + } + if(helloVk.m_pushConstants.lightType == 1) + { + float dCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotCutoff)); + float dOutCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotOuterCutoff)); + changed |= ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); + changed |= ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); + dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; + + helloVk.m_pushConstants.lightSpotCutoff = cos(deg2rad(dCutoff)); + helloVk.m_pushConstants.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); + } } - changed |= ImGui::InputInt("Max Frames", &helloVk.m_maxFrames); - helloVk.m_maxFrames = std::max(helloVk.m_maxFrames, 1); + + changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 1000); if(changed) helloVk.resetFrame(); } @@ -134,7 +134,7 @@ int main(int argc, char** argv) // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0)); + CameraManip.setLookat({8.440, 9.041, -8.973}, {-2.462, 3.661, -0.286}, {0.000, 1.000, 0.000}); // Setup Vulkan if(!glfwVulkanSupported()) @@ -148,19 +148,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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); @@ -175,11 +172,17 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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{}; @@ -199,7 +202,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -208,9 +211,9 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creating scene - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths), + 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))); @@ -222,7 +225,6 @@ int main(int argc, char** argv) for(int n = 0; n < 50; ++n) { - ObjInstance inst; inst.objIndex = wusonIndex; inst.txtOffset = 0; @@ -284,14 +286,15 @@ int main(int argc, char** argv) // Start the Dear ImGui frame ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); // Updating camera buffer helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGui::NewFrame(); + ImGuiH::Panel::Begin(); bool changed = false; // Edit 3 floats representing a color changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); @@ -304,7 +307,9 @@ int main(int argc, char** argv) renderUI(helloVk); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::Render(); + + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -357,6 +362,7 @@ int main(int argc, char** argv) // Rendering tonemapper offscreen.draw(cmdBuff, helloVk.getSize()); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing__advance/offscreen.cpp b/ray_tracing__advance/offscreen.cpp index 21445e8..98b7b71 100644 --- a/ray_tracing__advance/offscreen.cpp +++ b/ray_tracing__advance/offscreen.cpp @@ -74,7 +74,7 @@ void Offscreen::createFramebuffer(VkExtent2D& size) | vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eStorage); - nvvk::Image image = m_alloc->createImage(colorCreateInfo); + nvvk::Image image = m_alloc->createImage(colorCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); m_colorTexture = m_alloc->createTexture(image, ivInfo, vk::SamplerCreateInfo()); m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -153,9 +153,9 @@ void Offscreen::createPipeline(vk::RenderPass& renderPass) std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_pipeline = pipelineGenerator.createPipeline(); diff --git a/ray_tracing__advance/raytrace.cpp b/ray_tracing__advance/raytrace.cpp index 6d6e07a..4bd6492 100644 --- a/ray_tracing__advance/raytrace.cpp +++ b/ray_tracing__advance/raytrace.cpp @@ -30,6 +30,7 @@ #include "nvh/fileoperations.hpp" #include "nvvk/descriptorsets_vk.hpp" +#include "nvh/alignment.hpp" #include "nvvk/shaders_vk.hpp" #include "obj_loader.h" @@ -47,9 +48,10 @@ void Raytracer::setup(const vk::Device& device, m_graphicsQueueIndex = queueFamily; // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex); m_debug.setup(device); @@ -69,45 +71,36 @@ void Raytracer::destroy() //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas Raytracer::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput Raytracer::objectToVkGeometryKHR(const ObjModel& model) { - // Setting up the creation info of acceleration structure - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - // Building part vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); // Setting up the build info of the acceleration vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -116,18 +109,9 @@ nvvk::RaytracingBuilderKHR::Blas Raytracer::objectToVkGeometryKHR(const ObjModel //-------------------------------------------------------------------------------------------------- // Returning the ray tracing geometry used for the BLAS, containing all spheres // -nvvk::RaytracingBuilderKHR::Blas Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj) +nvvk::RaytracingBuilderKHR::BlasInput Raytracer::implicitToVkGeometryKHR( + const ImplInst& implicitObj) { - - // Setting up the creation info of acceleration structure - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eAabbs); - asCreate.setIndexType(vk::IndexType::eNoneKHR); - asCreate.setVertexFormat(vk::Format::eUndefined); - asCreate.setMaxPrimitiveCount(static_cast(implicitObj.objImpl.size())); // Nb triangles - asCreate.setMaxVertexCount(0); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer}); vk::AccelerationStructureGeometryAabbsDataKHR aabbs; @@ -135,21 +119,20 @@ nvvk::RaytracingBuilderKHR::Blas Raytracer::implicitToVkGeometryKHR(const ImplIn aabbs.setStride(sizeof(ObjImplicit)); // Setting up the build info of the acceleration - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit - asGeom.geometry.setAabbs(aabbs); + VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; + asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit + asGeom.geometry.aabbs = aabbs; - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(static_cast(implicitObj.objImpl.size())); // Nb aabb offset.setPrimitiveOffset(0); offset.setTransformOffset(0); - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -158,7 +141,7 @@ nvvk::RaytracingBuilderKHR::Blas Raytracer::implicitToVkGeometryKHR(const ImplIn void Raytracer::createBottomLevelAS(std::vector& models, ImplInst& implicitObj) { // BLAS - Storing each primitive in a geometry - std::vector allBlas; + std::vector allBlas; allBlas.reserve(models.size()); for(const auto& obj : models) { @@ -266,16 +249,15 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -286,7 +268,7 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"}); rg.setGeneralShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(rg); + m_rtShaderGroups.push_back(rg); // 0 // Miss vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, @@ -294,19 +276,19 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"}); mg.setGeneralShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(mg); + m_rtShaderGroups.push_back(mg); // 1 // Shadow Miss stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); mg.setGeneralShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(mg); + m_rtShaderGroups.push_back(mg); // 2 // Hit Group0 - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::ShaderModule ahitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rahit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rahit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -315,19 +297,19 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) hg.setClosestHitShader(static_cast(stages.size() - 1)); stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); hg.setAnyHitShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(hg); + m_rtShaderGroups.push_back(hg); // 3 // Hit Group1 - Closest Hit + Intersection (procedural) vk::ShaderModule chit2SM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); vk::ShaderModule ahit2SM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace2.rahit.spv", true, paths)); + nvh::loadFile("shaders/raytrace2.rahit.spv", true, paths, true)); vk::ShaderModule rintSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rint.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rint.spv", true, paths, true)); { vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -338,7 +320,7 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) hg.setAnyHitShader(static_cast(stages.size() - 1)); stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"}); hg.setIntersectionShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(hg); + m_rtShaderGroups.push_back(hg); // 4 } // Callable shaders @@ -348,22 +330,23 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) vk::ShaderModule call0 = nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/light_point.rcall.spv", true, paths)); + nvh::loadFile("shaders/light_point.rcall.spv", true, paths, true)); vk::ShaderModule call1 = nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/light_spot.rcall.spv", true, paths)); + nvh::loadFile("shaders/light_spot.rcall.spv", true, paths, true)); vk::ShaderModule call2 = - nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths)); + nvvk::createShaderModule(m_device, + nvh::loadFile("shaders/light_inf.rcall.spv", true, paths, true)); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); callGroup.setGeneralShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(callGroup); + m_rtShaderGroups.push_back(callGroup); // 5 stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"}); callGroup.setGeneralShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(callGroup); + m_rtShaderGroups.push_back(callGroup); // 6 stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"}); callGroup.setGeneralShader(static_cast(stages.size() - 1)); - m_rtShaderGroups.push_back(callGroup); + m_rtShaderGroups.push_back(callGroup); //7 vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; @@ -393,10 +376,10 @@ void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -422,18 +405,24 @@ void Raytracer::createRtShaderBindingTable() auto groupCount = static_cast(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc->createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc->createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -442,7 +431,7 @@ void Raytracer::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc->unmap(m_rtSBTBuffer); @@ -479,27 +468,22 @@ void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf, | vk::ShaderStageFlagBits::eCallableKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize callableGroupOffset = 5u * progSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = (vk::DeviceSize)m_rtShaderGroups.size() * progSize; + // 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}); - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable = { - m_rtSBTBuffer.buffer, callableGroupOffset, progSize, sbtSize}; + 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 * 2}, // hit + Stride{sbtAddress + 5u * groupSize, groupStride, groupSize * 3}}; // callable - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], + &strideAddresses[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 43b4247..9084c18 100644 --- a/ray_tracing__advance/raytrace.hpp +++ b/ray_tracing__advance/raytrace.hpp @@ -43,8 +43,8 @@ public: uint32_t queueFamily); void destroy(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - nvvk::RaytracingBuilderKHR::Blas implicitToVkGeometryKHR(const ImplInst& implicitObj); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + nvvk::RaytracingBuilderKHR::BlasInput implicitToVkGeometryKHR(const ImplInst& implicitObj); void createBottomLevelAS(std::vector& models, ImplInst& implicitObj); void createTopLevelAS(std::vector& instances, ImplInst& implicitObj); void createRtDescriptorSet(const vk::ImageView& outputImage); @@ -65,7 +65,7 @@ private: nvvk::DebugUtil m_debug; // Utility to name objects - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing__advance/shaders/light_inf.rcall b/ray_tracing__advance/shaders/light_inf.rcall index bc70cf3..a89034e 100644 --- a/ray_tracing__advance/shaders/light_inf.rcall +++ b/ray_tracing__advance/shaders/light_inf.rcall @@ -3,7 +3,7 @@ #extension GL_GOOGLE_include_directive : enable #include "raycommon.glsl" -layout(location = 0) callableDataInEXT rayLight cLight; +layout(location = 3) callableDataInEXT rayLight cLight; layout(push_constant) uniform Constants { diff --git a/ray_tracing__advance/shaders/light_point.rcall b/ray_tracing__advance/shaders/light_point.rcall index 389273c..bdca9fa 100644 --- a/ray_tracing__advance/shaders/light_point.rcall +++ b/ray_tracing__advance/shaders/light_point.rcall @@ -3,7 +3,7 @@ #extension GL_GOOGLE_include_directive : enable #include "raycommon.glsl" -layout(location = 0) callableDataInEXT rayLight cLight; +layout(location = 3) callableDataInEXT rayLight cLight; layout(push_constant) uniform Constants { diff --git a/ray_tracing__advance/shaders/light_spot.rcall b/ray_tracing__advance/shaders/light_spot.rcall index b845f0a..1214d29 100644 --- a/ray_tracing__advance/shaders/light_spot.rcall +++ b/ray_tracing__advance/shaders/light_spot.rcall @@ -3,7 +3,7 @@ #extension GL_GOOGLE_include_directive : enable #include "raycommon.glsl" -layout(location = 0) callableDataInEXT rayLight cLight; +layout(location = 3) callableDataInEXT rayLight cLight; layout(push_constant) uniform Constants { diff --git a/ray_tracing__advance/shaders/raytrace.rahit b/ray_tracing__advance/shaders/raytrace.rahit index 8ef6d33..cf611a5 100644 --- a/ray_tracing__advance/shaders/raytrace.rahit +++ b/ray_tracing__advance/shaders/raytrace.rahit @@ -30,7 +30,7 @@ void main() uint seed = prd.seed; // We don't want to modify the PRD if(mat.dissolve == 0.0) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; else if(rnd(seed) > mat.dissolve) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; } diff --git a/ray_tracing__advance/shaders/raytrace.rchit b/ray_tracing__advance/shaders/raytrace.rchit index 503032b..5e350fd 100644 --- a/ray_tracing__advance/shaders/raytrace.rchit +++ b/ray_tracing__advance/shaders/raytrace.rchit @@ -36,7 +36,7 @@ layout(push_constant) uniform Constants } pushC; -layout(location = 0) callableDataEXT rayLight cLight; +layout(location = 3) callableDataEXT rayLight cLight; void main() @@ -97,7 +97,7 @@ void main() cLight.outLightDistance = 10000000; } #else - executeCallableEXT(pushC.lightType, 0); + executeCallableEXT(pushC.lightType, 3); #endif // Material of the object diff --git a/ray_tracing__advance/shaders/raytrace2.rahit b/ray_tracing__advance/shaders/raytrace2.rahit index a71a877..624891c 100644 --- a/ray_tracing__advance/shaders/raytrace2.rahit +++ b/ray_tracing__advance/shaders/raytrace2.rahit @@ -26,7 +26,7 @@ void main() uint seed = prd.seed; // We don't want to modify the PRD if(mat.dissolve == 0.0) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; else if(rnd(seed) > mat.dissolve) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; } diff --git a/ray_tracing__advance/shaders/raytrace2.rchit b/ray_tracing__advance/shaders/raytrace2.rchit index e267a5d..dc88972 100644 --- a/ray_tracing__advance/shaders/raytrace2.rchit +++ b/ray_tracing__advance/shaders/raytrace2.rchit @@ -37,7 +37,7 @@ layout(push_constant) uniform Constants } pushC; -layout(location = 0) callableDataEXT rayLight cLight; +layout(location = 3) callableDataEXT rayLight cLight; void main() @@ -71,7 +71,7 @@ void main() } cLight.inHitPosition = worldPos; - executeCallableEXT(pushC.lightType, 0); + executeCallableEXT(pushC.lightType, 3); // Material of the object WaveFrontMaterial mat = materials[nonuniformEXT(gl_InstanceCustomIndexEXT)].m[impl.matId]; diff --git a/ray_tracing__before/CMakeLists.txt b/ray_tracing__before/CMakeLists.txt index 1ca7679..316f8df 100644 --- a/ray_tracing__before/CMakeLists.txt +++ b/ray_tracing__before/CMakeLists.txt @@ -1,30 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) +SET(VULKAN_TARGET_ENV vulkan1.2) UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -34,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -88,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing__before/hello_vulkan.cpp b/ray_tracing__before/hello_vulkan.cpp index 27bc7f5..00bf5e8 100644 --- a/ray_tracing__before/hello_vulkan.cpp +++ b/ray_tracing__before/hello_vulkan.cpp @@ -174,8 +174,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions(std::vector{ {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, @@ -194,6 +194,7 @@ 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); @@ -293,7 +294,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -311,9 +312,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -527,9 +529,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); diff --git a/ray_tracing__before/hello_vulkan.h b/ray_tracing__before/hello_vulkan.h index 4d1f1ec..3b36931 100644 --- a/ray_tracing__before/hello_vulkan.h +++ b/ray_tracing__before/hello_vulkan.h @@ -62,8 +62,8 @@ public: // The OBJ model struct ObjModel { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; + uint32_t nbIndices{0}; + uint32_t nbVertices{0}; nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' @@ -125,8 +125,8 @@ public: vk::PipelineLayout m_postPipelineLayout; vk::RenderPass m_offscreenRenderPass; vk::Framebuffer m_offscreenFramebuffer; - nvvk::Texture m_offscreenColor; + nvvk::Texture m_offscreenColor; vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat}; - nvvk::Texture m_offscreenDepth; + nvvk::Texture m_offscreenDepth; vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; }; diff --git a/ray_tracing__before/main.cpp b/ray_tracing__before/main.cpp index 480c56f..d8ed7be 100644 --- a/ray_tracing__before/main.cpp +++ b/ray_tracing__before/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -62,19 +63,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -119,19 +117,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceDescriptorIndexingFeaturesEXT indexFeature; - vk::PhysicalDeviceScalarBlockLayoutFeaturesEXT scalarFeature; - // Requesting Vulkan extensions and layers 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 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); @@ -143,8 +138,8 @@ 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, false, &indexFeature); - contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, false, &scalarFeature); + contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); + contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); // Creating Vulkan base application nvvk::Context vkctx{}; @@ -164,7 +159,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -173,7 +168,7 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); helloVk.createOffscreenRender(); helloVk.createDescriptorSetLayout(); @@ -206,13 +201,15 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + 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); - ImGui::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -259,6 +256,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing__simple/CMakeLists.txt b/ray_tracing__simple/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing__simple/CMakeLists.txt +++ b/ray_tracing__simple/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing__simple/hello_vulkan.cpp b/ray_tracing__simple/hello_vulkan.cpp index 4a870f2..6efb4aa 100644 --- a/ray_tracing__simple/hello_vulkan.cpp +++ b/ray_tracing__simple/hello_vulkan.cpp @@ -35,6 +35,7 @@ extern std::vector defaultSearchPaths; #include "obj_loader.h" #include "hello_vulkan.h" +#include "nvh/alignment.hpp" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvvk/commands_vk.hpp" @@ -54,6 +55,7 @@ struct CameraMatrices nvmath::mat4f projInverse; }; + //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images @@ -161,7 +163,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -192,8 +194,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions(std::vector{ {0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, @@ -212,6 +214,7 @@ 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); @@ -238,10 +241,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -314,7 +319,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -332,7 +337,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); @@ -554,9 +559,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -620,55 +625,49 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - // Setting up the creation info of acceleration structure - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - // Building part vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + uint32_t maxPrimitiveCount = model.nbIndices / 3; + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); // Setting up the build info of the acceleration vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); // The primitive itself - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(maxPrimitiveCount); offset.setPrimitiveOffset(0); offset.setTransformOffset(0); // Our blas is only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; @@ -680,7 +679,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { @@ -766,16 +765,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -802,7 +800,7 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -838,10 +836,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -860,18 +858,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -880,7 +883,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -909,24 +912,21 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders + // 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}); - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + 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 - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], + &strideAddresses[3], // m_size.width, m_size.height, 1); // diff --git a/ray_tracing__simple/hello_vulkan.h b/ray_tracing__simple/hello_vulkan.h index f7fb46a..33dd335 100644 --- a/ray_tracing__simple/hello_vulkan.h +++ b/ray_tracing__simple/hello_vulkan.h @@ -133,18 +133,18 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing__simple/main.cpp b/ray_tracing__simple/main.cpp index e448f03..bdc39c0 100644 --- a/ray_tracing__simple/main.cpp +++ b/ray_tracing__simple/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -115,17 +113,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Requesting Vulkan extensions and layers 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); @@ -138,8 +135,12 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); + 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); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); @@ -165,7 +166,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -174,8 +175,8 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.createOffscreenRender(); @@ -220,15 +221,18 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -281,6 +285,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_animation/CMakeLists.txt b/ray_tracing_animation/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_animation/CMakeLists.txt +++ b/ray_tracing_animation/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_animation/README.md b/ray_tracing_animation/README.md index e8c89c2..783bdbe 100644 --- a/ray_tracing_animation/README.md +++ b/ray_tracing_animation/README.md @@ -6,7 +6,7 @@ This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR). -We will implement two animation methods: animating only the transformation matrices, and animating the geometry itself. +We will implement two animation methods: only the transformation matrices, and animating the geometry itself. ## Animating the Matrices @@ -76,13 +76,10 @@ Next, we update the buffer that describes the scene, which is used by the raster m_debug.endLabel(cmdBuf); genCmdBuf.submitAndWait(cmdBuf); m_alloc.destroy(stagingBuffer); - - m_rtBuilder.updateTlasMatrices(m_tlas); - m_rtBuilder.updateBlas(2); } ~~~~ -:warning: **Note:** + **Note:** We could have used `cmdBuf.updateBuffer(m_sceneDesc.buffer, 0, m_objInstance)` to update the buffer, but this function only works for buffers with less than 65,536 bytes. If we had 2000 Wuson models, this call wouldn't work. @@ -153,144 +150,22 @@ In the `for` loop, add at the end The last point is to call the update at the end of the function. ~~~~ C++ -m_rtBuilder.updateTlasMatrices(m_tlas); + m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true); ~~~~ ![](images/animation1.gif) -### nvvk::RaytracingBuilder::updateTlasMatrices (Implementation) +### nvvk::RaytracingBuilder::buildTlas (Implementation) -We currently use `nvvk::RaytracingBuilder` to update the matrices for convenience, but -this could be done more efficiently if one kept some of the buffer and memory references. Using a -memory allocator, such as the one described in the [Many Objects Tutorial](vkrt_tuto_instances.md.htm), -could also be an alternative for avoiding multiple reallocations. Here's the implementation of `nvvk::RaytracingBuilder::updateTlasMatrices`. +We are using `nvvk::RaytracingBuilder` to update the matrices for convenience. There +is only a small variation with constructing the matrices and updating them. The main +differences are: -#### Staging Buffer +* The `VkAccelerationStructureBuildGeometryInfoKHR` mode will be set to `VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR` +* We will **not** create the acceleration structure, but reuse it. +* The source and destination of `VkAccelerationStructureCreateInfoKHR` will both use the previously created acceleration structure. -As in the rasterizer, the data needs to be staged before it can be copied to the buffer used for -building the TLAS. - -~~~~ C++ - void updateTlasMatrices(const std::vector& instances) - { - VkDeviceSize bufferSize = instances.size() * sizeof(VkAccelerationStructureInstanceKHR); - // Create a staging buffer on the host to upload the new instance data - nvvkBuffer stagingBuffer = m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, -#if defined(ALLOC_VMA) - VmaMemoryUsage::VMA_MEMORY_USAGE_CPU_TO_GPU -#else - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT -#endif - ); - - // Copy the instance data into the staging buffer - auto* gInst = reinterpret_cast(m_alloc.map(stagingBuffer)); - for(int i = 0; i < instances.size(); i++) - { - gInst[i] = instanceToVkGeometryInstanceKHR(instances[i]); - } - m_alloc.unmap(stagingBuffer); -~~~~ - -#### Scratch Memory - -Building the TLAS always needs scratch memory, and so we need to request it. If -we hadn't set the `eAllowUpdate` flag, the returned size would be zero and the rest of the code -would fail. - -~~~~ C++ - // Compute the amount of scratch memory required by the AS builder to update - VkAccelerationStructureMemoryRequirementsInfoKHR memoryRequirementsInfo{ - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR}; - memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR; - memoryRequirementsInfo.accelerationStructure = m_tlas.as.accel; - memoryRequirementsInfo.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - - VkMemoryRequirements2 reqMem{VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; - vkGetAccelerationStructureMemoryRequirementsKHR(m_device, &memoryRequirementsInfo, &reqMem); - VkDeviceSize scratchSize = reqMem.memoryRequirements.size; - - // Allocate the scratch buffer - nvvkBuffer scratchBuffer = - m_alloc.createBuffer(scratchSize, VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; - bufferInfo.buffer = scratchBuffer.buffer; - VkDeviceAddress scratchAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo); -~~~~ - -#### Update the Buffer -In a new command buffer, we copy the staging buffer to the device buffer and -add a barrier to make sure the memory finishes copying before updating the TLAS. - -~~~~ C++ - // Update the instance buffer on the device side and build the TLAS - nvvk::CommandPool genCmdBuf(m_device, m_queueIndex); - VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - - VkBufferCopy region{0, 0, bufferSize}; - vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_instBuffer.buffer, 1, ®ion); - - //VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; - bufferInfo.buffer = m_instBuffer.buffer; - VkDeviceAddress instanceAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo); - - - // Make sure the copy of the instance buffer are copied before triggering the - // acceleration structure build - VkMemoryBarrier barrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER}; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, - 0, 1, &barrier, 0, nullptr, 0, nullptr); -~~~~ - -#### Update Acceleration Structure - -We update the TLAS using the same acceleration structure for source and -destination to update it in place, and using the VK_TRUE parameter to trigger the update. - -~~~~ C++ - VkAccelerationStructureGeometryDataKHR geometry{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR}; - geometry.instances.arrayOfPointers = VK_FALSE; - geometry.instances.data.deviceAddress = instanceAddress; - VkAccelerationStructureGeometryKHR topASGeometry{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - topASGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - topASGeometry.geometry = geometry; - - const VkAccelerationStructureGeometryKHR* pGeometry = &topASGeometry; - - VkAccelerationStructureBuildGeometryInfoKHR topASInfo{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR}; - topASInfo.flags = m_tlas.flags; - topASInfo.update = VK_TRUE; - topASInfo.srcAccelerationStructure = m_tlas.as.accel; - topASInfo.dstAccelerationStructure = m_tlas.as.accel; - topASInfo.geometryArrayOfPointers = VK_FALSE; - topASInfo.geometryCount = 1; - topASInfo.ppGeometries = &pGeometry; - topASInfo.scratchData.deviceAddress = scratchAddress; - - uint32_t nbInstances = (uint32_t)instances.size(); - VkAccelerationStructureBuildOffsetInfoKHR buildOffsetInfo = {nbInstances, 0, 0, 0}; - const VkAccelerationStructureBuildOffsetInfoKHR* pBuildOffsetInfo = &buildOffsetInfo; - - // Build the TLAS - - // Update the acceleration structure. Note the VK_TRUE parameter to trigger the update, - // and the existing TLAS being passed and updated in place - vkCmdBuildAccelerationStructureKHR(cmdBuf, 1, &topASInfo, &pBuildOffsetInfo); - - genCmdBuf.submitAndWait(cmdBuf); -~~~~ - -#### Cleanup - -Finally, we release all temporary buffers. - -~~~~ C++ - m_alloc.destroy(scratchBuffer); - m_alloc.destroy(stagingBuffer); - } -~~~~ +What is happening is the buffer containing all matrices will be updated and the `vkCmdBuildAccelerationStructuresKHR` will update the acceleration in place. ## BLAS Animation @@ -484,14 +359,15 @@ In `main.cpp`, after the other resource creation functions, add the creation fun helloVk.createCompPipelines(); ~~~~ -In the rendering loop, after the call to `animationInstances`, call the object animation function. +In the rendering loop, **before** the call to `animationInstances`, call the object animation function. ~~~~ C++ helloVk.animationObject(diff.count()); ~~~~ -:warning: **Note:** At this point, the object should be animated when using the rasterizer, but should still be immobile when using the ray tracer. +**Note:** Always update the TLAS when BLAS are modified. This will make sure that the TLAS knows about the new bounding box sizes. +**Note:** At this point, the object should be animated when using the rasterizer, but should still be immobile when using the ray tracer. ## Update BLAS diff --git a/ray_tracing_animation/hello_vulkan.cpp b/ray_tracing_animation/hello_vulkan.cpp index dcaf651..0924906 100644 --- a/ray_tracing_animation/hello_vulkan.cpp +++ b/ray_tracing_animation/hello_vulkan.cpp @@ -39,6 +39,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/descriptorsets_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" @@ -162,7 +163,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -193,8 +194,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -212,6 +213,7 @@ 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); @@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -560,9 +565,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -626,49 +631,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - // Consider the geometry opaque for optimization + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -701,8 +700,10 @@ void HelloVulkan::createTopLevelAS() 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::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace + | vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate; + m_rtBuilder.buildTlas(m_tlas, m_rtFlags); } //-------------------------------------------------------------------------------------------------- @@ -762,16 +763,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -798,7 +798,7 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -833,10 +833,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -855,18 +855,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -875,7 +880,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -904,23 +909,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); - // m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + // 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}); + + 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 + + cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], + &strideAddresses[3], // m_size.width, m_size.height, 1); // m_debug.endLabel(cmdBuf); @@ -966,7 +970,7 @@ void HelloVulkan::animationInstances(float time) genCmdBuf.submitAndWait(cmdBuf); m_alloc.destroy(stagingBuffer); - m_rtBuilder.updateTlasMatrices(m_tlas); + m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true); } void HelloVulkan::animationObject(float time) @@ -1016,10 +1020,9 @@ void HelloVulkan::createCompPipelines() m_compPipelineLayout = m_device.createPipelineLayout(layout_info); vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; - computePipelineCreateInfo.stage = - nvvk::createShaderStageInfo(m_device, - nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths), - VK_SHADER_STAGE_COMPUTE_BIT); + computePipelineCreateInfo.stage = nvvk::createShaderStageInfo( + m_device, nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths, true), + VK_SHADER_STAGE_COMPUTE_BIT); m_compPipeline = static_cast( m_device.createComputePipeline({}, computePipelineCreateInfo)); m_device.destroy(computePipelineCreateInfo.stage.module); diff --git a/ray_tracing_animation/hello_vulkan.h b/ray_tracing_animation/hello_vulkan.h index 7a904c5..d384493 100644 --- a/ray_tracing_animation/hello_vulkan.h +++ b/ray_tracing_animation/hello_vulkan.h @@ -132,18 +132,18 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; @@ -154,8 +154,8 @@ public: vk::Pipeline m_rtPipeline; nvvk::Buffer m_rtSBTBuffer; - std::vector m_tlas; - std::vector m_blas; + std::vector m_tlas; + std::vector m_blas; struct RtPushConstant { @@ -180,4 +180,6 @@ public: vk::DescriptorSet m_compDescSet; vk::Pipeline m_compPipeline; vk::PipelineLayout m_compPipelineLayout; + + vk::BuildAccelerationStructureFlagsKHR m_rtFlags; }; diff --git a/ray_tracing_animation/main.cpp b/ray_tracing_animation/main.cpp index 7e8e548..4e353a6 100644 --- a/ray_tracing_animation/main.cpp +++ b/ray_tracing_animation/main.cpp @@ -36,6 +36,7 @@ #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -62,19 +63,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -116,19 +114,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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); @@ -143,11 +138,16 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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{}; @@ -167,7 +167,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -176,13 +176,13 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), nvmath::scale_mat4(nvmath::vec3f(2.f, 1.f, 2.f))); - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); HelloVulkan::ObjInstance inst = helloVk.m_objInstance.back(); for(int i = 0; i < 5; i++) helloVk.m_objInstance.push_back(inst); - helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true)); helloVk.createOffscreenRender(); @@ -232,21 +232,23 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // #VK_animation std::chrono::duration diff = std::chrono::system_clock::now() - start; - helloVk.animationInstances(diff.count()); helloVk.animationObject(diff.count()); + helloVk.animationInstances(diff.count()); // Start rendering the scene helloVk.prepareFrame(); @@ -298,6 +300,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_anyhit/CMakeLists.txt b/ray_tracing_anyhit/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_anyhit/CMakeLists.txt +++ b/ray_tracing_anyhit/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_anyhit/README.md b/ray_tracing_anyhit/README.md index 1365641..4c7a465 100644 --- a/ray_tracing_anyhit/README.md +++ b/ray_tracing_anyhit/README.md @@ -17,7 +17,7 @@ The any hit shader can be useful for discarding intersections, such as for alpha used for simple transparency. In this example we will show what is needed to do to add this shader type and to create a transparency effect. -:warning: **Note:** + **Note:** This example is based on many elements from the [Antialiasing Tutorial](vkrt_tuto_jitter_cam.md.htm). @@ -49,7 +49,7 @@ layout(binding = 1, set = 1, scalar) buffer MatColorBufferObject { WaveFrontMate // clang-format on ~~~~ -:warning: **Note:** + **Note:** You can find the source of `random.glsl` in the Antialiasing Tutorial [here](../ray_tracing_jitter_cam/README.md#toc1.1). @@ -205,11 +205,11 @@ uint flags = gl_RayFlagsSkipClosestHitShaderEXT; For a more interesting scene, you can replace the `helloVk.loadModel` calls in `main()` with the following scene: ~~~~ C++ - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths), + 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))); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); ~~~~ ## OBJ Materials @@ -259,7 +259,7 @@ And we need to add the following to the ray tracing pipeline, a copy of the prev Create two new files `raytrace_0.ahit` and `raytrace_1.ahit`, and rename `raytrace.ahit` to `raytrace_ahit.glsl` -:warning: **Note:** + **Note:** Cmake need to be re-run to add the new files to the project. In `raytrace_0.ahit` add the following code @@ -390,7 +390,7 @@ m_rtShaderGroups.push_back(hg); At the end of the function, delete the shader module `ahit1SM`. -:warning: **Note:** Re-Run + **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 1460d7a..300e755 100644 --- a/ray_tracing_anyhit/hello_vulkan.cpp +++ b/ray_tracing_anyhit/hello_vulkan.cpp @@ -39,6 +39,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/descriptorsets_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" @@ -165,7 +166,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -196,8 +197,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -215,6 +216,7 @@ 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); @@ -241,10 +243,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -317,7 +321,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -335,9 +339,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -556,9 +561,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -622,50 +627,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // Avoid double hits asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); offset.setPrimitiveOffset(0); offset.setTransformOffset(0); - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -673,7 +671,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { @@ -759,16 +757,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -796,10 +793,10 @@ void HelloVulkan::createRtPipeline() // Payload 0 vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::ShaderModule ahitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rahit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rahit.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}; @@ -812,7 +809,7 @@ void HelloVulkan::createRtPipeline() // Payload 1 vk::ShaderModule ahit1SM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths)); + nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths, true)); hg.setClosestHitShader(VK_SHADER_UNUSED_KHR); // Not used by shadow (skipped) stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit1SM, "main"}); hg.setAnyHitShader(static_cast(stages.size() - 1)); @@ -843,9 +840,9 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = m_device.createRayTracingPipelineKHR({}, rayPipelineInfo).value; + m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -866,18 +863,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -886,7 +888,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -919,24 +921,23 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + // 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}); - // m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // - m_size.width, m_size.height, 1); // + 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 + + cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], + &strideAddresses[3], // + m_size.width, m_size.height, + 1); // m_debug.endLabel(cmdBuf); @@ -949,12 +950,16 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& void HelloVulkan::updateFrame() { static nvmath::mat4f refCamMatrix; + static float refFov{CameraManip.getFov()}; - auto& m = CameraManip.getMatrix(); - if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) + const auto& m = CameraManip.getMatrix(); + const auto fov = CameraManip.getFov(); + + if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov) { resetFrame(); refCamMatrix = m; + refFov = fov; } m_rtPushConstants.frame++; } diff --git a/ray_tracing_anyhit/hello_vulkan.h b/ray_tracing_anyhit/hello_vulkan.h index 10ce562..9d6279f 100644 --- a/ray_tracing_anyhit/hello_vulkan.h +++ b/ray_tracing_anyhit/hello_vulkan.h @@ -132,19 +132,19 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void resetFrame(); void updateFrame(); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing_anyhit/main.cpp b/ray_tracing_anyhit/main.cpp index 3d38da3..55a6fa7 100644 --- a/ray_tracing_anyhit/main.cpp +++ b/ray_tracing_anyhit/main.cpp @@ -36,6 +36,7 @@ #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -115,19 +113,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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); @@ -141,8 +136,15 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); + 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); + contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); @@ -166,7 +168,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -175,11 +177,11 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths), + 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))); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.createOffscreenRender(); @@ -224,15 +226,17 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -285,6 +289,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_anyhit/shaders/raytrace.rahit b/ray_tracing_anyhit/shaders/raytrace.rahit index 6af0802..def0fe8 100644 --- a/ray_tracing_anyhit/shaders/raytrace.rahit +++ b/ray_tracing_anyhit/shaders/raytrace.rahit @@ -35,7 +35,7 @@ void main() return; if(mat.dissolve == 0.0) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; else if(rnd(prd.seed) > mat.dissolve) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; } diff --git a/ray_tracing_anyhit/shaders/raytrace_rahit.glsl b/ray_tracing_anyhit/shaders/raytrace_rahit.glsl index a1fb942..12918cd 100644 --- a/ray_tracing_anyhit/shaders/raytrace_rahit.glsl +++ b/ray_tracing_anyhit/shaders/raytrace_rahit.glsl @@ -39,7 +39,7 @@ void main() return; if(mat.dissolve == 0.0) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; else if(rnd(prd.seed) > mat.dissolve) - ignoreIntersectionEXT(); + ignoreIntersectionEXT; } diff --git a/ray_tracing_callable/CMakeLists.txt b/ray_tracing_callable/CMakeLists.txt index 590ec4f..c374896 100644 --- a/ray_tracing_callable/CMakeLists.txt +++ b/ray_tracing_callable/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,6 +42,7 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" "shaders/*.rcall" @@ -44,41 +51,27 @@ foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -91,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_callable/README.md b/ray_tracing_callable/README.md index b190cc8..c536bc9 100644 --- a/ray_tracing_callable/README.md +++ b/ray_tracing_callable/README.md @@ -101,9 +101,9 @@ m_device.destroy(call2); Here are the source of all shaders -* [light_point.rcall](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/master/ray_tracing_callable/shaders/light_point.rcall) -* [light_spot.rcall](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/master/ray_tracing_callable/shaders/light_spot.rcall) -* [light_inf.rcall](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/master/ray_tracing_callable/shaders/light_inf.rcall) +* [light_point.rcall](shaders/light_point.rcall) +* [light_spot.rcall](shaders/light_spot.rcall) +* [light_inf.rcall](shaders/light_inf.rcall) ### Passing Callable to traceRaysKHR @@ -116,19 +116,19 @@ In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Therefore, the callable starts at `4 * progSize` ~~~~ C++ -vk::DeviceSize callableGroupOffset = 4u * progSize; // Jump over the previous shaders -vk::DeviceSize callableGroupStride = progSize; + 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++ -const vk::StridedBufferRegionKHR callableShaderBindingTable = { - m_rtSBTBuffer.buffer, callableGroupOffset, progSize, sbtSize}; - -cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // - m_size.width, m_size.height, 1); // + cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], + &strideAddresses[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 8df376c..aa65458 100644 --- a/ray_tracing_callable/hello_vulkan.cpp +++ b/ray_tracing_callable/hello_vulkan.cpp @@ -39,6 +39,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/descriptorsets_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" @@ -162,7 +163,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -193,8 +194,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -212,6 +213,7 @@ 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); @@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -553,9 +558,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -619,47 +624,46 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - nvvk::RaytracingBuilderKHR::Blas blas; - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices + nvvk::RaytracingBuilderKHR::BlasInput blas; + vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); + // Consider the geometry opaque for optimization asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); offset.setPrimitiveOffset(0); offset.setTransformOffset(0); + blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -667,7 +671,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { @@ -753,16 +757,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -789,7 +792,7 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -805,12 +808,13 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule call0 = nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/light_point.rcall.spv", true, paths)); + nvh::loadFile("shaders/light_point.rcall.spv", true, paths, true)); vk::ShaderModule call1 = nvvk::createShaderModule(m_device, - nvh::loadFile("shaders/light_spot.rcall.spv", true, paths)); + nvh::loadFile("shaders/light_spot.rcall.spv", true, paths, true)); vk::ShaderModule call2 = - nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths)); + nvvk::createShaderModule(m_device, + nvh::loadFile("shaders/light_inf.rcall.spv", true, paths, true)); stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"}); callGroup.setGeneralShader(static_cast(stages.size() - 1)); @@ -850,10 +854,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -875,18 +879,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -895,7 +904,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -928,28 +937,23 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eCallableKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize hitGroupStride = progSize; - vk::DeviceSize callableGroupOffset = 4u * progSize; // Jump over the previous shaders - vk::DeviceSize callableGroupStride = progSize; - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + // 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}); - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable = { - m_rtSBTBuffer.buffer, callableGroupOffset, progSize, sbtSize}; + 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{sbtAddress + 4u * groupSize, groupStride, groupSize * 1}}; // callable - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + 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_callable/hello_vulkan.h b/ray_tracing_callable/hello_vulkan.h index 662dcea..85f25ed 100644 --- a/ray_tracing_callable/hello_vulkan.h +++ b/ray_tracing_callable/hello_vulkan.h @@ -136,18 +136,18 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing_callable/main.cpp b/ray_tracing_callable/main.cpp index f3604bf..58a332f 100644 --- a/ray_tracing_callable/main.cpp +++ b/ray_tracing_callable/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -61,35 +62,32 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen)) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); - } - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Spot", &helloVk.m_pushConstant.lightType, 1); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 2); - if(helloVk.m_pushConstant.lightType < 2) - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - if(helloVk.m_pushConstant.lightType > 0) - ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstant.lightDirection.x, -1.f, 1.f); - if(helloVk.m_pushConstant.lightType < 2) - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 500.f); - if(helloVk.m_pushConstant.lightType == 1) - { - float dCutoff = rad2deg(acos(helloVk.m_pushConstant.lightSpotCutoff)); - float dOutCutoff = rad2deg(acos(helloVk.m_pushConstant.lightSpotOuterCutoff)); - ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); - ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); - dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Spot", &helloVk.m_pushConstant.lightType, 1); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 2); - helloVk.m_pushConstant.lightSpotCutoff = cos(deg2rad(dCutoff)); - helloVk.m_pushConstant.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); + if(helloVk.m_pushConstant.lightType < 2) + ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + if(helloVk.m_pushConstant.lightType > 0) + ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstant.lightDirection.x, -1.f, 1.f); + if(helloVk.m_pushConstant.lightType < 2) + ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 500.f); + if(helloVk.m_pushConstant.lightType == 1) + { + float dCutoff = rad2deg(acos(helloVk.m_pushConstant.lightSpotCutoff)); + float dOutCutoff = rad2deg(acos(helloVk.m_pushConstant.lightSpotOuterCutoff)); + ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); + ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); + dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; + + helloVk.m_pushConstant.lightSpotCutoff = cos(deg2rad(dCutoff)); + helloVk.m_pushConstant.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); + } } } @@ -132,19 +130,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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); @@ -159,11 +154,17 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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,7 +184,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -192,8 +193,8 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.createOffscreenRender(); @@ -238,15 +239,17 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -299,6 +302,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_gltf/CMakeLists.txt b/ray_tracing_gltf/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_gltf/CMakeLists.txt +++ b/ray_tracing_gltf/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_gltf/README.md b/ray_tracing_gltf/README.md index 75a03c9..de6c23f 100644 --- a/ray_tracing_gltf/README.md +++ b/ray_tracing_gltf/README.md @@ -95,7 +95,7 @@ Then we will flatten the scene graph and grab the information we will need using nvh::GltfAttributes::Normal | nvh::GltfAttributes::Texcoord_0); ~~~~ -The next par is to allocate the buffers to hold the information, such as the positions, normals, texture coordinates, etc. +The next part is to allocate the buffers to hold the information, such as the positions, normals, texture coordinates, etc. ~~~~C m_vertexBuffer = @@ -145,35 +145,26 @@ The function is similar, only the input is different. // nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim) { - // Setting up the creation info of acceleration structure - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(prim.indexCount / 3); // Nb triangles - asCreate.setMaxVertexCount(prim.vertexCount); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - - // Building part + // Building part vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer}); vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(nvmath::vec3f)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(prim.vertexCount); // Setting up the build info of the acceleration vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.geometry.setTriangles(triangles); - - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(prim.vertexOffset); offset.setPrimitiveCount(prim.indexCount / 3); offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t)); @@ -181,7 +172,6 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::Glt nvvk::RaytracingBuilderKHR::Blas blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -283,7 +273,7 @@ Camera position Scene ~~~~C - helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths)); + helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths, true)); ~~~~ Light Position @@ -310,12 +300,16 @@ Add the following two functions in `hello_vulkan.cpp`: void HelloVulkan::updateFrame() { static nvmath::mat4f refCamMatrix; + static float refFov{CameraManip.getFov()}; - auto& m = CameraManip.getMatrix(); - if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) + const auto& m = CameraManip.getMatrix(); + const auto fov = CameraManip.getFov(); + + if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov) { resetFrame(); refCamMatrix = m; + refFov = fov; } m_rtPushConstants.frame++; } @@ -505,7 +499,7 @@ First initialize the `payload` and variable to compute the accumulation. Now the loop over the trace function, will be like the following. -:warning: **Note:** the depth is hardcode, but could be a parameter to the `push constant`. + **Note:** the depth is hardcode, but could be a parameter to the `push constant`. ~~~~C for(; prd.depth < 10; prd.depth++) @@ -528,6 +522,6 @@ Now the loop over the trace function, will be like the following. } ~~~~ -:warning: **Note:** do not forget to use `hitValue` in the `imageStore`. +**Note:** do not forget to use `hitValue` in the `imageStore`. diff --git a/ray_tracing_gltf/hello_vulkan.cpp b/ray_tracing_gltf/hello_vulkan.cpp index 66fc308..d0a8dbd 100644 --- a/ray_tracing_gltf/hello_vulkan.cpp +++ b/ray_tracing_gltf/hello_vulkan.cpp @@ -46,6 +46,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/renderpasses_vk.hpp" #include "nvvk/shaders_vk.hpp" +#include "nvh/alignment.hpp" #include "shaders/binding.glsl" // Holding the camera matrices @@ -182,8 +183,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescriptions( {{0, sizeof(nvmath::vec3)}, {1, sizeof(nvmath::vec3)}, {2, sizeof(nvmath::vec2)}}); gpb.addAttributeDescriptions({ @@ -205,6 +206,7 @@ void HelloVulkan::loadScene(const std::string& filename) tinygltf::TinyGLTF tcontext; std::string warn, error; + LOGI("Loading file: %s", filename.c_str()); if(!tcontext.LoadASCIIFromFile(&tmodel, &error, &warn, filename)) { assert(!"Error while loading scene"); @@ -223,10 +225,12 @@ void HelloVulkan::loadScene(const std::string& filename) m_vertexBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_positions, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); m_normalBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_normals, vkBU::eVertexBuffer | vkBU::eStorageBuffer); m_uvBuffer = m_alloc.createBuffer(cmdBuf, m_gltfScene.m_texcoords0, @@ -525,9 +529,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -591,54 +595,46 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a GLTF primitive in the Raytracing Geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::primitiveToGeometry( + const nvh::GltfPrimMesh& prim) { - // Setting up the creation info of acceleration structure - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(prim.indexCount / 3); // Nb triangles - asCreate.setMaxVertexCount(prim.vertexCount); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - // Building part vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer}); vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(nvmath::vec3f)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(prim.vertexCount); // Setting up the build info of the acceleration vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.geometry.setTriangles(triangles); - - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(prim.vertexOffset); offset.setPrimitiveCount(prim.indexCount / 3); offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t)); offset.setTransformOffset(0); - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -649,7 +645,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::primitiveToGeometry(const nvh::Glt void HelloVulkan::createBottomLevelAS() { // BLAS - Storing each primitive in a geometry - std::vector allBlas; + std::vector allBlas; allBlas.reserve(m_gltfScene.m_primMeshes.size()); for(auto& primMesh : m_gltfScene.m_primMeshes) { @@ -738,16 +734,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/pathtrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/pathtrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/pathtrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/pathtrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -774,7 +769,7 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/pathtrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/pathtrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -810,10 +805,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -832,18 +827,24 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + if(result != vk::Result::eSuccess) + LOGE("Fail getRayTracingShaderGroupHandlesKHR: %s", vk::to_string(result)); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -852,7 +853,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -883,25 +884,23 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders + // 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}); - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + 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 - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // - 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); @@ -914,12 +913,16 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& void HelloVulkan::updateFrame() { static nvmath::mat4f refCamMatrix; + static float refFov{CameraManip.getFov()}; - auto& m = CameraManip.getMatrix(); - if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) + const auto& m = CameraManip.getMatrix(); + const auto fov = CameraManip.getFov(); + + if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov) { resetFrame(); refCamMatrix = m; + refFov = fov; } m_rtPushConstants.frame++; } diff --git a/ray_tracing_gltf/hello_vulkan.h b/ray_tracing_gltf/hello_vulkan.h index 9d71ca9..190f107 100644 --- a/ray_tracing_gltf/hello_vulkan.h +++ b/ray_tracing_gltf/hello_vulkan.h @@ -127,7 +127,7 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - nvvk::RaytracingBuilderKHR::Blas primitiveToGeometry(const nvh::GltfPrimMesh& prim); + nvvk::RaytracingBuilderKHR::BlasInput primitiveToGeometry(const nvh::GltfPrimMesh& prim); void initRayTracing(); void createBottomLevelAS(); @@ -140,7 +140,7 @@ public: void updateFrame(); void resetFrame(); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing_gltf/main.cpp b/ray_tracing_gltf/main.cpp index c8469a4..bd6eb4f 100644 --- a/ray_tracing_gltf/main.cpp +++ b/ray_tracing_gltf/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -115,18 +113,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Requesting Vulkan extensions and layers 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_WIN32_SURFACE_EXTENSION_NAME); #else @@ -138,13 +134,17 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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); contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_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 @@ -166,7 +166,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -175,7 +175,7 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths)); + helloVk.loadScene(nvh::findFile("media/scenes/cornellBox.gltf", defaultSearchPaths, true)); helloVk.createOffscreenRender(); @@ -219,15 +219,17 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -280,6 +282,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_instances/CMakeLists.txt b/ray_tracing_instances/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_instances/CMakeLists.txt +++ b/ray_tracing_instances/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_instances/README.md b/ray_tracing_instances/README.md index 4b47ce6..95f586f 100644 --- a/ray_tracing_instances/README.md +++ b/ray_tracing_instances/README.md @@ -30,9 +30,9 @@ Then replace the calls to `helloVk.loadModel` in `main()` by ~~~~ C++ // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true)); + helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); 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() @@ -55,7 +55,7 @@ Then replace the calls to `helloVk.loadModel` in `main()` by } ~~~~ -:warning: **Note:** + **Note:** This will create 3 models (OBJ) and their instances, and then add 2000 instances distributed between green cubes and cubes with one color per face. @@ -73,7 +73,7 @@ Remove the previous code and replace it with the following std::normal_distribution disn(0.05f, 0.05f); for(int n = 0; n < 2000; ++n) { - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back(); float scale = fabsf(disn(gen)); @@ -85,7 +85,7 @@ Remove the previous code and replace it with the following inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform))); } - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); ~~~~ The example might still work, but the console will print the following error after loading 1363 objects. All other objects allocated after the 1363rd will fail to be displayed. diff --git a/ray_tracing_instances/hello_vulkan.cpp b/ray_tracing_instances/hello_vulkan.cpp index 0f74645..de3247f 100644 --- a/ray_tracing_instances/hello_vulkan.cpp +++ b/ray_tracing_instances/hello_vulkan.cpp @@ -41,6 +41,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/descriptorsets_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" @@ -178,7 +179,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -209,8 +210,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -228,6 +229,7 @@ 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); @@ -254,10 +256,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -330,7 +334,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -348,9 +352,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -575,9 +580,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -641,47 +646,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - nvvk::RaytracingBuilderKHR::Blas blas; - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - // Consider the geometry opaque for optimization + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); + + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -689,7 +690,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { @@ -775,16 +776,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -811,7 +811,7 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -846,10 +846,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -868,18 +868,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -888,7 +893,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -917,25 +922,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + // 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}); - // m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + 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 + + 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_instances/hello_vulkan.h b/ray_tracing_instances/hello_vulkan.h index 5134f27..0eac12e 100644 --- a/ray_tracing_instances/hello_vulkan.h +++ b/ray_tracing_instances/hello_vulkan.h @@ -145,18 +145,18 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing_instances/main.cpp b/ray_tracing_instances/main.cpp index 27a9f1c..baa43c3 100644 --- a/ray_tracing_instances/main.cpp +++ b/ray_tracing_instances/main.cpp @@ -38,6 +38,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -62,19 +63,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -116,20 +114,17 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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_WIN32_SURFACE_EXTENSION_NAME); #else @@ -143,11 +138,16 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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{}; @@ -167,7 +167,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -182,7 +182,7 @@ int main(int argc, char** argv) std::normal_distribution disn(0.05f, 0.05f); for(int n = 0; n < 2000; ++n) { - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back(); float scale = fabsf(disn(gen)); @@ -194,7 +194,7 @@ int main(int argc, char** argv) inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform))); } - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.createOffscreenRender(); helloVk.createDescriptorSetLayout(); @@ -238,15 +238,17 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -299,6 +301,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_intersection/CMakeLists.txt b/ray_tracing_intersection/CMakeLists.txt index 36119de..c374896 100644 --- a/ray_tracing_intersection/CMakeLists.txt +++ b/ray_tracing_intersection/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -39,46 +45,33 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -91,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_intersection/README.md b/ray_tracing_intersection/README.md index 8eb8428..8d2344a 100644 --- a/ray_tracing_intersection/README.md +++ b/ray_tracing_intersection/README.md @@ -190,11 +190,11 @@ In `main.cpp`, where we are loading the OBJ model, we can replace it with ~~~~ C++ // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.createSpheres(); ~~~~ -:warning: **Note:** it is possible to have more OBJ models, but the spheres will need to be added after all of them. + **Note:** it is possible to have more OBJ models, but the spheres will need to be added after all of them. The scene will be large, better to move the camera out @@ -248,7 +248,7 @@ Just before building the TLAS, we need to add the following rayInst.instanceId = static_cast(tlas.size()); // gl_InstanceID rayInst.blasId = static_cast(m_objModel.size()); rayInst.hitGroupId = 1; // We will use the same hit group for all objects - rayInst.flags = vk::GeometryInstanceFlagBitsKHR::eTriangleCullDisable; + rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; tlas.emplace_back(rayInst); } ~~~~ diff --git a/ray_tracing_intersection/hello_vulkan.cpp b/ray_tracing_intersection/hello_vulkan.cpp index 6ff3db6..998b71d 100644 --- a/ray_tracing_intersection/hello_vulkan.cpp +++ b/ray_tracing_intersection/hello_vulkan.cpp @@ -43,6 +43,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/commands_vk.hpp" #include "nvvk/renderpasses_vk.hpp" +#include "nvh/alignment.hpp" #include "nvvk/shaders_vk.hpp" #include @@ -172,7 +173,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -203,8 +204,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -222,6 +223,7 @@ 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); @@ -248,10 +250,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -324,7 +328,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -342,9 +346,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -568,9 +573,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -634,50 +639,44 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); // Setting up the build info of the acceleration vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -685,37 +684,30 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod //-------------------------------------------------------------------------------------------------- // 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 - - 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 - vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); - asGeom.geometry.setAabbs(aabbs); + // 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; - vk::AccelerationStructureBuildOffsetInfoKHR offset; + + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount((uint32_t)m_spheres.size()); // Nb aabb offset.setPrimitiveOffset(0); offset.setTransformOffset(0); - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -754,11 +746,11 @@ void HelloVulkan::createSpheres(uint32_t nbSpheres) // Creating two materials MaterialObj mat; - mat.diffuse = vec3f(0, 1, 1); + 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 @@ -787,7 +779,7 @@ void HelloVulkan::createSpheres(uint32_t nbSpheres) 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) { @@ -892,16 +884,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -928,7 +919,7 @@ void HelloVulkan::createRtPipeline() // Hit Group0 - Closest Hit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); { vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, @@ -942,10 +933,10 @@ void HelloVulkan::createRtPipeline() // Hit Group1 - Closest Hit + Intersection (procedural) vk::ShaderModule chit2SM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); vk::ShaderModule rintSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rint.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rint.spv", true, paths, true)); { vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -983,10 +974,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -1007,18 +998,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -1027,7 +1023,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -1056,25 +1052,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + // 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}); - // m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + 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 + + 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 0521ea6..7e0f7f5 100644 --- a/ray_tracing_intersection/hello_vulkan.h +++ b/ray_tracing_intersection/hello_vulkan.h @@ -132,18 +132,18 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; @@ -175,7 +175,7 @@ public: nvmath::vec3f maximum; }; - nvvk::RaytracingBuilderKHR::Blas sphereToVkGeometryKHR(); + nvvk::RaytracingBuilderKHR::BlasInput sphereToVkGeometryKHR(); std::vector m_spheres; // All spheres nvvk::Buffer m_spheresBuffer; // Buffer holding the spheres diff --git a/ray_tracing_intersection/main.cpp b/ray_tracing_intersection/main.cpp index 700edaa..1c63c05 100644 --- a/ray_tracing_intersection/main.cpp +++ b/ray_tracing_intersection/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -61,19 +62,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -200.f, 200.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 1000.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); ImGui::Text("Nb Spheres and Cubes: %d", helloVk.m_spheres.size()); } @@ -116,20 +114,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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_WIN32_SURFACE_EXTENSION_NAME); #else @@ -143,11 +137,17 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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{}; @@ -167,7 +167,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -176,8 +176,8 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - // helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + // helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.createSpheres(2000000); helloVk.createOffscreenRender(); @@ -222,15 +222,17 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -283,6 +285,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_jitter_cam/CMakeLists.txt b/ray_tracing_jitter_cam/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_jitter_cam/CMakeLists.txt +++ b/ray_tracing_jitter_cam/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_jitter_cam/README.md b/ray_tracing_jitter_cam/README.md index 6612e71..a7b7076 100644 --- a/ray_tracing_jitter_cam/README.md +++ b/ray_tracing_jitter_cam/README.md @@ -150,18 +150,22 @@ The implementation of `updateFrame` resets the frame counter if the camera has c ~~~~ C++ //-------------------------------------------------------------------------------------------------- -// If the camera matrix has changed, resets the frame. +// If the camera matrix or the the fov has changed, resets the frame. // otherwise, increments frame. // void HelloVulkan::updateFrame() { static nvmath::mat4f refCamMatrix; + static float refFov{CameraManip.getFov()}; - auto& m = CameraManip.getMatrix(); - if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) + const auto& m = CameraManip.getMatrix(); + const auto fov = CameraManip.getFov(); + + if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov) { resetFrame(); refCamMatrix = m; + refFov = fov; } m_rtPushConstants.frame++; } @@ -195,23 +199,20 @@ The frame number should also be reset when any parts of the scene change, such a ~~~~ C++ void renderUI(HelloVulkan& helloVk) { - static int item = 1; - bool changed = false; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + bool changed = false; + + changed |= ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); - changed = true; + auto& pc = helloVk.m_pushConstant; + changed |= ImGui::RadioButton("Point", &pc.lightType, 0); + ImGui::SameLine(); + changed |= ImGui::RadioButton("Infinite", &pc.lightType, 1); + + changed |= ImGui::SliderFloat3("Position", &pc.lightPosition.x, -20.f, 20.f); + changed |= ImGui::SliderFloat("Intensity", &pc.lightIntensity, 0.f, 150.f); } - changed |= - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - changed |= - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + if(changed) helloVk.resetFrame(); } @@ -242,8 +243,7 @@ int m_maxFrames{100}; and also add a way to control it in `renderUI()`, making sure that `m_maxFrames` cannot be set below 1: ~~~~ C++ -changed |= ImGui::InputInt("Max Frames", &helloVk.m_maxFrames); -helloVk.m_maxFrames = std::max(helloVk.m_maxFrames, 1); +changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 100); ~~~~ Then in `raytrace()`, immediately after the call to `updateFrame()`, return if the current frame has exceeded the max frame. diff --git a/ray_tracing_jitter_cam/hello_vulkan.cpp b/ray_tracing_jitter_cam/hello_vulkan.cpp index 5dfcb47..29fafd2 100644 --- a/ray_tracing_jitter_cam/hello_vulkan.cpp +++ b/ray_tracing_jitter_cam/hello_vulkan.cpp @@ -39,6 +39,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/descriptorsets_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" @@ -162,7 +163,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -193,8 +194,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -212,6 +213,7 @@ 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); @@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -553,9 +558,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -619,47 +624,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - nvvk::RaytracingBuilderKHR::Blas blas; - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - // Consider the geometry opaque for optimization + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); + + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -667,7 +668,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { @@ -753,16 +754,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -789,7 +789,7 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -824,10 +824,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -846,18 +846,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -866,7 +871,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -899,43 +904,44 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + // 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}); - // m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + 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 + + cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], + &strideAddresses[3], // m_size.width, m_size.height, 1); // - m_debug.endLabel(cmdBuf); } //-------------------------------------------------------------------------------------------------- -// If the camera matrix has changed, resets the frame. +// If the camera matrix or the the fov has changed, resets the frame. // otherwise, increments frame. // void HelloVulkan::updateFrame() { static nvmath::mat4f refCamMatrix; + static float refFov{CameraManip.getFov()}; - auto& m = CameraManip.getMatrix(); - if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0) + const auto& m = CameraManip.getMatrix(); + const auto fov = CameraManip.getFov(); + + if(memcmp(&refCamMatrix.a00, &m.a00, sizeof(nvmath::mat4f)) != 0 || refFov != fov) { resetFrame(); refCamMatrix = m; + refFov = fov; } m_rtPushConstants.frame++; } diff --git a/ray_tracing_jitter_cam/hello_vulkan.h b/ray_tracing_jitter_cam/hello_vulkan.h index cbcd794..4d3fb0c 100644 --- a/ray_tracing_jitter_cam/hello_vulkan.h +++ b/ray_tracing_jitter_cam/hello_vulkan.h @@ -132,19 +132,19 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void resetFrame(); void updateFrame(); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; @@ -154,7 +154,7 @@ public: vk::PipelineLayout m_rtPipelineLayout; vk::Pipeline m_rtPipeline; nvvk::Buffer m_rtSBTBuffer; - int m_maxFrames{100}; + int m_maxFrames{10}; struct RtPushConstant { diff --git a/ray_tracing_jitter_cam/main.cpp b/ray_tracing_jitter_cam/main.cpp index 9f75d76..257aa06 100644 --- a/ray_tracing_jitter_cam/main.cpp +++ b/ray_tracing_jitter_cam/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -61,25 +62,22 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - bool changed = false; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + bool changed = false; + + changed |= ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); - changed = true; + auto& pc = helloVk.m_pushConstant; + changed |= ImGui::RadioButton("Point", &pc.lightType, 0); + ImGui::SameLine(); + changed |= ImGui::RadioButton("Infinite", &pc.lightType, 1); + + changed |= ImGui::SliderFloat3("Position", &pc.lightPosition.x, -20.f, 20.f); + changed |= ImGui::SliderFloat("Intensity", &pc.lightIntensity, 0.f, 150.f); } - changed |= - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - changed |= - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); - changed |= ImGui::InputInt("Max Frames", &helloVk.m_maxFrames); - helloVk.m_maxFrames = std::max(helloVk.m_maxFrames, 1); + + + changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 100); if(changed) helloVk.resetFrame(); } @@ -123,20 +121,17 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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_WIN32_SURFACE_EXTENSION_NAME); #else @@ -149,12 +144,18 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); + 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{}; @@ -174,7 +175,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -183,8 +184,8 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.createOffscreenRender(); @@ -229,8 +230,9 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); bool changed = false; // Edit 3 floats representing a color changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); @@ -242,7 +244,8 @@ int main(int argc, char** argv) renderUI(helloVk); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -295,6 +298,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_manyhits/CMakeLists.txt b/ray_tracing_manyhits/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_manyhits/CMakeLists.txt +++ b/ray_tracing_manyhits/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_manyhits/README.md b/ray_tracing_manyhits/README.md index 89c2952..e677161 100644 --- a/ray_tracing_manyhits/README.md +++ b/ray_tracing_manyhits/README.md @@ -19,14 +19,14 @@ Then you can change the `helloVk.loadModel` calls to the following: ~~~~ C++ // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths), + helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0))); HelloVulkan::ObjInstance inst; inst.objIndex = 0; inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0)); inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform)); helloVk.m_objInstance.push_back(inst); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); ~~~~ ## Adding a new Closest Hit Shader @@ -60,7 +60,7 @@ This new shader needs to be added to the raytracing pipeline. So, in `createRtPi ~~~~ C++ vk::ShaderModule chit2SM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); ~~~~ Then add a new hit group group immediately after adding the first hit group: @@ -103,7 +103,7 @@ struct sceneDesc }; ~~~~ -:warning: **Note:** + **Note:** The solution will not automatically recompile the shaders after this change to `wavefront.glsl`; instead, you will need to recompile all of the SPIR-V shaders. ### `hello_vulkan.cpp` @@ -131,7 +131,7 @@ When creating the [Shader Binding Table](https://www.khronos.org/registry/vulkan This information can be used to pass extra information to a shader, for each entry in the SBT. -:warning: **Note:** + **Note:** Since each entry in an SBT group must have the same size, each entry of the group has to have enough space to accommodate the largest element in the entire group. The following diagram represents our current SBT, with the addition of some data to `HitGroup1`. As mentioned in the **note**, even if @@ -184,7 +184,7 @@ void main() } ~~~~ -:warning: **Note:** + **Note:** Adding a new shader requires to rerun CMake to added to the project compilation system. @@ -335,7 +335,7 @@ Finally, we need to add the new entry as well at the end of the buffer, reusing pBuffer += hitSize; ~~~~ -:warning: **Note:** +**Note:** Adding entries like this can be error-prone and inconvenient for decent scene sizes. Instead, it is recommended to wrap the storage of handles, data, and size per group in a SBT utility to handle this automatically. diff --git a/ray_tracing_manyhits/hello_vulkan.cpp b/ray_tracing_manyhits/hello_vulkan.cpp index 897d102..14af8e8 100644 --- a/ray_tracing_manyhits/hello_vulkan.cpp +++ b/ray_tracing_manyhits/hello_vulkan.cpp @@ -39,16 +39,12 @@ extern std::vector defaultSearchPaths; #include "nvvk/descriptorsets_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" -#ifndef ROUND_UP -#define ROUND_UP(v, powerOf2Alignment) (((v) + (powerOf2Alignment)-1) & ~((powerOf2Alignment)-1)) -#endif - - // Holding the camera matrices struct CameraMatrices { @@ -197,8 +193,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -216,6 +212,7 @@ 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); @@ -242,10 +239,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -318,7 +317,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -336,7 +335,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); @@ -558,9 +557,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -624,47 +623,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - nvvk::RaytracingBuilderKHR::Blas blas; - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - // Consider the geometry opaque for optimization + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); + + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -672,7 +667,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { @@ -758,16 +753,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -794,10 +788,10 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::ShaderModule chit2SM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -836,10 +830,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -857,16 +851,17 @@ void HelloVulkan::createRtPipeline() 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 - uint32_t groupAlignSize = m_rtProperties.shaderGroupBaseAlignment; + static_cast(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, 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 - uint32_t sbtSize = groupCount * groupAlignSize; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); // Retrieve the handle pointers std::vector handles(groupCount); @@ -876,10 +871,10 @@ void HelloVulkan::createRtShaderBindingTable() } // Sizes - uint32_t rayGenSize = groupAlignSize; - uint32_t missSize = groupAlignSize; + uint32_t rayGenSize = groupSizeAligned; + uint32_t missSize = groupSizeAligned; uint32_t hitSize = - ROUND_UP(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), groupAlignSize); + nvh::align_up(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), groupSizeAligned); uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize; std::vector sbtBuffer(newSbtSize); @@ -915,7 +910,9 @@ void HelloVulkan::createRtShaderBindingTable() nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR); + m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, + vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR); m_debug.setObjectName(m_rtSBTBuffer.buffer, "SBT"); @@ -946,26 +943,25 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize handleSize = m_rtProperties.shaderGroupHandleSize; - vk::DeviceSize alignSize = m_rtProperties.shaderGroupBaseAlignment; - vk::DeviceSize rayGenOffset = 0u * alignSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * alignSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * alignSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = alignSize * (vk::DeviceSize)m_rtShaderGroups.size(); + // Size of a program identifier + uint32_t groupSize = + nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); + uint32_t groupStride = groupSize; + vk::DeviceSize hitGroupSize = + nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), + m_rtProperties.shaderGroupBaseAlignment); + vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); - vk::DeviceSize hitGroupStride = ROUND_UP(handleSize + sizeof(HitRecordBuffer), alignSize); + 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, hitGroupSize, hitGroupSize * 3}, // hit + Stride{0u, 0u, 0u}}; // callable - // m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - handleSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - handleSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - hitGroupStride, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], + &strideAddresses[3], // m_size.width, m_size.height, 1); // diff --git a/ray_tracing_manyhits/hello_vulkan.h b/ray_tracing_manyhits/hello_vulkan.h index 973fac7..c8f8fb0 100644 --- a/ray_tracing_manyhits/hello_vulkan.h +++ b/ray_tracing_manyhits/hello_vulkan.h @@ -133,18 +133,18 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing_manyhits/main.cpp b/ray_tracing_manyhits/main.cpp index be00d6b..bb4c02b 100644 --- a/ray_tracing_manyhits/main.cpp +++ b/ray_tracing_manyhits/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -60,19 +61,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -114,20 +112,17 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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_WIN32_SURFACE_EXTENSION_NAME); #else @@ -141,11 +136,17 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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{}; @@ -165,7 +166,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -174,14 +175,14 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths), + helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0))); HelloVulkan::ObjInstance inst; inst.objIndex = 0; inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0)); inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform)); helloVk.m_objInstance.push_back(inst); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); + helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.m_objInstance[0].hitgroup = 1; helloVk.m_objInstance[1].hitgroup = 2; helloVk.m_hitShaderRecord.resize(2); @@ -230,15 +231,17 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -291,6 +294,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_rayquery/CMakeLists.txt b/ray_tracing_rayquery/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_rayquery/CMakeLists.txt +++ b/ray_tracing_rayquery/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_rayquery/README.md b/ray_tracing_rayquery/README.md index 952ba2f..c21e992 100644 --- a/ray_tracing_rayquery/README.md +++ b/ray_tracing_rayquery/README.md @@ -47,7 +47,7 @@ You can safely remove all raytrace.* shaders ## Support for Fragment shader -In `HelloVulkan::createDescriptorSetLayout`, add the acceleration structure to the description layout. +In `HelloVulkan::createDescriptorSetLayout`, add the acceleration structure to the description layout to have access to the acceleration structure directly in the fragment shader. ~~~~ C++ // The top level acceleration structure diff --git a/ray_tracing_rayquery/hello_vulkan.cpp b/ray_tracing_rayquery/hello_vulkan.cpp index d07f0e4..796df40 100644 --- a/ray_tracing_rayquery/hello_vulkan.cpp +++ b/ray_tracing_rayquery/hello_vulkan.cpp @@ -163,7 +163,7 @@ void HelloVulkan::updateDescriptorSet() std::vector diit; for(auto& texture : m_textures) { - diit.push_back(texture.descriptor); + diit.emplace_back(texture.descriptor); } writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); @@ -201,8 +201,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -220,6 +220,7 @@ 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); @@ -246,10 +247,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -340,9 +343,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -475,7 +479,7 @@ void HelloVulkan::createOffscreenRender() | vk::ImageUsageFlagBits::eStorage); - nvvk::Image image = m_alloc.createImage(colorCreateInfo); + nvvk::Image image = m_alloc.createImage(colorCreateInfo); vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -554,9 +558,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -620,55 +624,47 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - // Setting up the creation info of acceleration structure - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices - // Building part vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); // Setting up the build info of the acceleration vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); // The primitive itself - vk::AccelerationStructureBuildOffsetInfoKHR offset; + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); // Our blas is only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::Blas blas; + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; @@ -680,7 +676,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { diff --git a/ray_tracing_rayquery/hello_vulkan.h b/ray_tracing_rayquery/hello_vulkan.h index 6d1a8be..409e108 100644 --- a/ray_tracing_rayquery/hello_vulkan.h +++ b/ray_tracing_rayquery/hello_vulkan.h @@ -132,11 +132,11 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; - nvvk::RaytracingBuilderKHR m_rtBuilder; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; + nvvk::RaytracingBuilderKHR m_rtBuilder; }; diff --git a/ray_tracing_rayquery/main.cpp b/ray_tracing_rayquery/main.cpp index faeebad..65b7b75 100644 --- a/ray_tracing_rayquery/main.cpp +++ b/ray_tracing_rayquery/main.cpp @@ -39,6 +39,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -63,19 +64,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -117,20 +115,16 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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_WIN32_SURFACE_EXTENSION_NAME); #else @@ -142,11 +136,16 @@ int main(int argc, char** argv) contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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 @@ -168,7 +167,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -177,8 +176,8 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths)); + 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(); @@ -220,14 +219,16 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + 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); - ImGui::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -275,6 +276,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/ray_tracing_reflections/CMakeLists.txt b/ray_tracing_reflections/CMakeLists.txt index f2c44ad..c374896 100644 --- a/ray_tracing_reflections/CMakeLists.txt +++ b/ray_tracing_reflections/CMakeLists.txt @@ -1,32 +1,38 @@ -cmake_minimum_required(VERSION 2.8) +#***************************************************************************** +# Copyright 2020 NVIDIA Corporation. All rights reserved. +#***************************************************************************** +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} LANGUAGES C CXX) +message(STATUS "-------------------------------") +message(STATUS "Processing Project ${PROJNAME}:") -Project(${PROJNAME}) -Message(STATUS "-------------------------------") -Message(STATUS "Processing Project ${PROJNAME}:") -##################################################################################### -_add_project_definitions(${PROJNAME}) +#-------------------------------------------------------------------------------------------------- +# C++ target and defines +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJNAME}) +target_compile_definitions(${PROJNAME} PUBLIC PROJECT_NAME="${PROJNAME}") -##################################################################################### + +#-------------------------------------------------------------------------------------------------- # Source files for this project # file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON "../common/*.*") +file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories("../common") +include_directories(${TUTO_KHR_DIR}/common) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # GLSL to SPIR-V custom build # -# more than one file can be given: _compile_GLSL("GLSL_mesh.vert;GLSL_mesh.frag" "GLSL_mesh.spv" GLSL_SOURCES) -# the SpirV validator is fine as long as files are for different pipeline stages (entry points still need to be main()) -#_compile_GLSL( ) SET(VULKAN_TARGET_ENV vulkan1.2) - UNSET(GLSL_SOURCES) UNSET(SPV_OUTPUT) file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl") @@ -36,48 +42,36 @@ file(GLOB_RECURSE GLSL_SOURCE_FILES "shaders/*.vert" "shaders/*.rchit" "shaders/*.rahit" + "shaders/*.rint" "shaders/*.rmiss" "shaders/*.rgen" + "shaders/*.rcall" ) foreach(GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME) _compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT) endforeach(GLSL) - list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES}) -source_group(Shader_Files FILES ${GLSL_SOURCES}) -##################################################################################### -# Executable +#-------------------------------------------------------------------------------------------------- +# Sources +target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) +target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES}) + + +#-------------------------------------------------------------------------------------------------- +# Sub-folders in Visual Studio # -# if(WIN32 AND NOT GLUT_FOUND) -# add_definitions(/wd4996) #remove printf warning -# add_definitions(/wd4244) #remove double to float conversion warning -# add_definitions(/wd4305) #remove double to float truncation warning -# else() -# add_definitions(-fpermissive) -# endif() -add_executable(${PROJNAME} ${SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES} ${GLSL_SOURCES} ${CUDA_FILES} ${CUBIN_SOURCES}) +source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) +source_group("Sources" FILES ${SOURCE_FILES}) +source_group("Headers" FILES ${HEADER_FILES}) +source_group("Shader_Files" FILES ${GLSL_SOURCES}) -#_set_subsystem_console(${PROJNAME}) -##################################################################################### -# common source code needed for this sample -# -source_group(common FILES - ${COMMON_SOURCE_FILES} - ${PACKAGE_SOURCE_FILES} -) -source_group("Source Files" FILES ${SOURCE_FILES}) - -# if(UNIX) -# set(UNIXLINKLIBS dl pthread) -# else() -# set(UNIXLINKLIBS) -# endif() - -##################################################################################### +#-------------------------------------------------------------------------------------------------- # Linkage # target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources) @@ -90,15 +84,28 @@ foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) endforeach(RELEASELIB) -##################################################################################### +#-------------------------------------------------------------------------------------------------- # copies binaries that need to be put next to the exe files (ZLib, etc.) # _copy_binaries_to_target( ${PROJNAME} ) -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") -install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders") +#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}") +#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}") + +#---------------------------------------------------------------------------------------------------- +# Copying elements +# Media +# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media") +# Spir-V Shaders +target_copy_to_output_dir( + TARGET ${PROJECT_NAME} + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + DEST_SUBFOLDER "${PROJECT_NAME}/" + FILES ${SPV_OUTPUT} + ) + diff --git a/ray_tracing_reflections/README.md b/ray_tracing_reflections/README.md index 742be7c..02b19c0 100644 --- a/ray_tracing_reflections/README.md +++ b/ray_tracing_reflections/README.md @@ -12,14 +12,14 @@ First, we will create a scene with two reflective planes and a multicolored cube ~~~~ C++ // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths), + 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))); - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths), + 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))); - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), + 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))); ~~~~ @@ -44,7 +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.setMaxRecursionDepth( + rayPipelineInfo.setMaxPipelineRayRecursionDepth( std::max(10u, m_rtProperties.maxRecursionDepth)); // Ray depth ~~~~ @@ -203,7 +203,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.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(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. @@ -246,9 +246,9 @@ Then test for the value for when to stop break; ~~~~ -Finally, in `main.cpp` in the `renderUI` function, we will add a slider to control the value. +Finally, in `main.cpp` after the `renderUI()` function call, we will add a slider to control the depth value. ~~~~ C++ - ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 100); + ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50); ~~~~ diff --git a/ray_tracing_reflections/hello_vulkan.cpp b/ray_tracing_reflections/hello_vulkan.cpp index faf0b48..b661a21 100644 --- a/ray_tracing_reflections/hello_vulkan.cpp +++ b/ray_tracing_reflections/hello_vulkan.cpp @@ -39,6 +39,7 @@ extern std::vector defaultSearchPaths; #include "nvvk/descriptorsets_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" @@ -193,8 +194,8 @@ void HelloVulkan::createGraphicsPipeline() std::vector paths = defaultSearchPaths; nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths), vkSS::eVertex); - gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths), vkSS::eFragment); + gpb.addShader(nvh::loadFile("shaders/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); + gpb.addShader(nvh::loadFile("shaders/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addAttributeDescriptions({{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, pos)}, {1, 0, vk::Format::eR32G32B32Sfloat, offsetof(VertexObj, nrm)}, @@ -212,6 +213,7 @@ 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); @@ -238,10 +240,12 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, - vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress + | vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, - vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); + 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); // Creates all textures found @@ -314,7 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, auto imgSize = vk::Extent2D(1, 1); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - // Creating the dummy texure + // 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); @@ -332,9 +336,10 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, std::stringstream o; int texWidth, texHeight, texChannels; o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths); + 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}; @@ -553,9 +558,9 @@ void HelloVulkan::createPostPipeline() nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/passthrough.vert.spv", true, paths, true), vk::ShaderStageFlagBits::eVertex); - pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths), + pipelineGenerator.addShader(nvh::loadFile("shaders/post.frag.spv", true, paths, true), vk::ShaderStageFlagBits::eFragment); pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone); m_postPipeline = pipelineGenerator.createPipeline(); @@ -619,47 +624,43 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::initRayTracing() { // Requesting ray tracing properties - auto properties = m_physicalDevice.getProperties2(); - m_rtProperties = properties.get(); + auto properties = + m_physicalDevice.getProperties2(); + m_rtProperties = properties.get(); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); } //-------------------------------------------------------------------------------------------------- // Converting a OBJ primitive to the ray tracing geometry used for the BLAS // -nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) +nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) { - nvvk::RaytracingBuilderKHR::Blas blas; - vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; - asCreate.setGeometryType(vk::GeometryTypeKHR::eTriangles); - asCreate.setIndexType(vk::IndexType::eUint32); - asCreate.setVertexFormat(vk::Format::eR32G32B32Sfloat); - asCreate.setMaxPrimitiveCount(model.nbIndices / 3); // Nb triangles - asCreate.setMaxVertexCount(model.nbVertices); - asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); + vk::AccelerationStructureGeometryTrianglesDataKHR triangles; - triangles.setVertexFormat(asCreate.vertexFormat); + triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.setVertexData(vertexAddress); triangles.setVertexStride(sizeof(VertexObj)); - triangles.setIndexType(asCreate.indexType); + triangles.setIndexType(vk::IndexType::eUint32); triangles.setIndexData(indexAddress); triangles.setTransformData({}); + triangles.setMaxVertex(model.nbVertices); vk::AccelerationStructureGeometryKHR asGeom; - asGeom.setGeometryType(asCreate.geometryType); - // Consider the geometry opaque for optimization + asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.geometry.setTriangles(triangles); - vk::AccelerationStructureBuildOffsetInfoKHR offset; + + vk::AccelerationStructureBuildRangeInfoKHR offset; offset.setFirstVertex(0); - offset.setPrimitiveCount(asCreate.maxPrimitiveCount); + offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.setPrimitiveOffset(0); offset.setTransformOffset(0); + + nvvk::RaytracingBuilderKHR::BlasInput blas; blas.asGeometry.emplace_back(asGeom); - blas.asCreateGeometryInfo.emplace_back(asCreate); blas.asBuildOffsetInfo.emplace_back(offset); return blas; } @@ -667,7 +668,7 @@ nvvk::RaytracingBuilderKHR::Blas HelloVulkan::objectToVkGeometryKHR(const ObjMod 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) { @@ -753,16 +754,15 @@ void HelloVulkan::createRtPipeline() vk::ShaderModule raygenSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rgen.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true)); vk::ShaderModule missSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, 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("shaders/raytraceShadow.rmiss.spv", true, paths)); + vk::ShaderModule shadowmissSM = nvvk::createShaderModule( + m_device, nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true)); std::vector stages; @@ -789,7 +789,7 @@ void HelloVulkan::createRtPipeline() // Hit Group - Closest Hit + AnyHit vk::ShaderModule chitSM = nvvk::createShaderModule(m_device, // - nvh::loadFile("shaders/raytrace.rchit.spv", true, paths)); + nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true)); vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, @@ -824,10 +824,10 @@ void HelloVulkan::createRtPipeline() m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.setPGroups(m_rtShaderGroups.data()); - rayPipelineInfo.setMaxRecursionDepth(2); // Ray depth + rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.setLayout(m_rtPipelineLayout); - m_rtPipeline = - static_cast(m_device.createRayTracingPipelineKHR({}, rayPipelineInfo)); + m_rtPipeline = static_cast( + m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo)); m_device.destroy(raygenSM); m_device.destroy(missSM); @@ -846,18 +846,23 @@ 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 - uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment + 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 - uint32_t sbtSize = groupCount * baseAlignment; + uint32_t sbtSize = groupCount * groupSizeAligned; std::vector shaderHandleStorage(sbtSize); - m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, - shaderHandleStorage.data()); + auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, + shaderHandleStorage.data()); + assert(result == vk::Result::eSuccess); + // Write the handles in the SBT - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc, - vk::MemoryPropertyFlagBits::eHostVisible - | vk::MemoryPropertyFlagBits::eHostCoherent); + m_rtSBTBuffer = m_alloc.createBuffer( + sbtSize, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eShaderBindingTableKHR, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); // Write the handles in the SBT @@ -866,7 +871,7 @@ void HelloVulkan::createRtShaderBindingTable() for(uint32_t g = 0; g < groupCount; g++) { memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen - pData += baseAlignment; + pData += groupSizeAligned; } m_alloc.unmap(m_rtSBTBuffer); @@ -894,25 +899,22 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& | vk::ShaderStageFlagBits::eMissKHR, 0, m_rtPushConstants); - vk::DeviceSize progSize = - m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier - vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer - vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen - vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the previous shaders - vk::DeviceSize sbtSize = progSize * (vk::DeviceSize)m_rtShaderGroups.size(); + // 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}); - // m_sbtBuffer holds all the shader handles: raygen, n-miss, hit... - const vk::StridedBufferRegionKHR raygenShaderBindingTable = {m_rtSBTBuffer.buffer, rayGenOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR missShaderBindingTable = {m_rtSBTBuffer.buffer, missOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR hitShaderBindingTable = {m_rtSBTBuffer.buffer, hitGroupOffset, - progSize, sbtSize}; - const vk::StridedBufferRegionKHR callableShaderBindingTable; - cmdBuf.traceRaysKHR(&raygenShaderBindingTable, &missShaderBindingTable, &hitShaderBindingTable, - &callableShaderBindingTable, // + 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 + + 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 fdbdb6e..ab7ebb8 100644 --- a/ray_tracing_reflections/hello_vulkan.h +++ b/ray_tracing_reflections/hello_vulkan.h @@ -132,18 +132,18 @@ public: vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat}; // #VKRay - void initRayTracing(); - nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); + void initRayTracing(); + nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model); + void createBottomLevelAS(); + void createTopLevelAS(); + void createRtDescriptorSet(); + void updateRtDescriptorSet(); + void createRtPipeline(); + void createRtShaderBindingTable(); void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); - vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; vk::DescriptorPool m_rtDescPool; diff --git a/ray_tracing_reflections/main.cpp b/ray_tracing_reflections/main.cpp index f39bb95..fd66b87 100644 --- a/ray_tracing_reflections/main.cpp +++ b/ray_tracing_reflections/main.cpp @@ -37,6 +37,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "imgui_impl_glfw.h" #include "hello_vulkan.h" +#include "imgui_camera_widget.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" @@ -61,20 +62,16 @@ static void onErrorCallback(int error, const char* description) // Extra UI void renderUI(HelloVulkan& helloVk) { - static int item = 1; - if(ImGui::Combo("Up Vector", &item, "X\0Y\0Z\0\0")) + ImGuiH::CameraWidget(); + if(ImGui::CollapsingHeader("Light")) { - nvmath::vec3f pos, eye, up; - CameraManip.getLookat(pos, eye, up); - up = nvmath::vec3f(item == 0, item == 1, item == 2); - CameraManip.setLookat(pos, eye, up); + ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); + + ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); + ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f); } - ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 100.f); - ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 100); - ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1); } ////////////////////////////////////////////////////////////////////////// @@ -116,20 +113,17 @@ int main(int argc, char** argv) // Search path for shaders and other media defaultSearchPaths = { - PROJECT_ABSDIRECTORY, // shaders - PROJECT_ABSDIRECTORY "../", // media - PROJECT_NAME, // installed: shaders + media + NVPSystem::exePath(), + NVPSystem::exePath() + "..", NVPSystem::exePath() + std::string(PROJECT_NAME), }; - // Enabling the extension feature - vk::PhysicalDeviceRayTracingFeaturesKHR raytracingFeature; - // Requesting Vulkan extensions and layers 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_WIN32_SURFACE_EXTENSION_NAME); #else @@ -143,11 +137,17 @@ 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 - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_EXTENSION_NAME, false, &raytracingFeature); 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{}; @@ -167,7 +167,7 @@ int main(int argc, char** argv) helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSurface(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); + helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); @@ -176,15 +176,14 @@ int main(int argc, char** argv) helloVk.initGUI(0); // Using sub-pass 0 // Creation of the example - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths), + 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))); - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths), + 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))); - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), + 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))); @@ -230,15 +229,18 @@ int main(int argc, char** argv) helloVk.updateUniformBuffer(); // Show UI window. - if(1 == 1) + if(helloVk.showGui()) { + ImGuiH::Panel::Begin(); ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing 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::Render(); + ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); + ImGuiH::Panel::End(); } // Start rendering the scene @@ -291,6 +293,7 @@ int main(int argc, char** argv) // Rendering tonemapper helloVk.drawPost(cmdBuff); // Rendering UI + ImGui::Render(); ImGui::RenderDrawDataVK(cmdBuff, ImGui::GetDrawData()); cmdBuff.endRenderPass(); } diff --git a/utilities.cmake b/utilities.cmake new file mode 100644 index 0000000..8ca5a99 --- /dev/null +++ b/utilities.cmake @@ -0,0 +1,50 @@ + + + +# ------------------------------------------------------------------------------------------------- +# function that copies a list of files into the target directory +# +# target_copy_to_output_dir(TARGET foo +# [RELATIVE ] # allows to keep the folder structure starting from this level +# FILES [] +# ) +# +function(TARGET_COPY_TO_OUTPUT_DIR) + set(options) + set(oneValueArgs TARGET RELATIVE DEST_SUBFOLDER) + set(multiValueArgs FILES) + cmake_parse_arguments(TARGET_COPY_TO_OUTPUT_DIR "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + foreach(_ELEMENT ${TARGET_COPY_TO_OUTPUT_DIR_FILES} ) + + # handle absolute and relative paths + if(TARGET_COPY_TO_OUTPUT_DIR_RELATIVE) + set(_SOURCE_FILE ${TARGET_COPY_TO_OUTPUT_DIR_RELATIVE}/${_ELEMENT}) + set(_FOLDER_PATH ${_ELEMENT}) + else() + set(_SOURCE_FILE ${_ELEMENT}) + get_filename_component(_FOLDER_PATH ${_ELEMENT} NAME) + set (_ELEMENT "") + endif() + + # handle directories and files slightly different + if(IS_DIRECTORY ${_SOURCE_FILE}) + if(MDL_LOG_FILE_DEPENDENCIES) + MESSAGE(STATUS "- folder to copy: ${_SOURCE_FILE}") + endif() + add_custom_command( + TARGET ${TARGET_COPY_TO_OUTPUT_DIR_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${_SOURCE_FILE} $/${TARGET_COPY_TO_OUTPUT_DIR_DEST_SUBFOLDER}${_FOLDER_PATH} + ) + else() + if(MDL_LOG_FILE_DEPENDENCIES) + MESSAGE(STATUS "- file to copy: ${_SOURCE_FILE}") + endif() + add_custom_command( + TARGET ${TARGET_COPY_TO_OUTPUT_DIR_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_SOURCE_FILE} $/${TARGET_COPY_TO_OUTPUT_DIR_DEST_SUBFOLDER}${_ELEMENT} + ) + endif() + endforeach() +endfunction() +