Skip to content

Commit

Permalink
Port to the finalised Vulkan Khronos ray tracing extensions (#21)
Browse files Browse the repository at this point in the history
* Saving first WiP steps for when SDK is updated to final specs for ray tracing

* Upgraded to latest Vulkan SDK (1.2.162) with support for VK_KHR_acceleration_structure and VK_KHR_ray_tracing_pipeline.
Hopefully fixed all of the Vulkan calls and validation errors.
Fixed ImGui::SliderFloat logarithmic call (API break).

* Fix Windows CI.

* Fix Linux build (missing header include).
Fix Windows CI (update msbuild setup).

* Fix Linux build (missing header include).
Fix Windows CI (update msbuild setup).
  • Loading branch information
GPSnoopy authored Dec 15, 2020
1 parent 083bbd4 commit 8031f39
Show file tree
Hide file tree
Showing 30 changed files with 333 additions and 411 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:

runs-on: ubuntu-20.04
env:
SDK_VERSION: 1.2.154
SDK_VERSION: 1.2.162

steps:
- uses: actions/checkout@v2
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ jobs:

runs-on: windows-latest
env:
SDK_VERSION: 1.2.154.1
SDK_VERSION: 1.2.162.0

steps:
- uses: actions/checkout@v2
- name: Download Vulkan SDK
run: Invoke-WebRequest "https://sdk.lunarg.com/sdk/download/${env:SDK_VERSION}/windows/VulkanSDK-${env:SDK_VERSION}-Installer.exe?Human=true" -OutFile VulkanSDK.exe -v
run: Invoke-WebRequest "https://sdk.lunarg.com/sdk/download/${env:SDK_VERSION}/windows/vulkan_sdk.exe?Human=true" -OutFile vulkan_sdk.exe -v
- name: Install Vulkan SDK
run: .\VulkanSDK.exe /S
run: .\vulkan_sdk.exe /S
shell: cmd
- name: Compile vcpkg dependencies
run: vcpkg_windows.bat
Expand All @@ -25,7 +25,7 @@ jobs:
# (originally at https://github.com/warrenbuckley/Setup-MSBuild, later on adopted by Microsoft themselves).
# Comedy bonus: GitHub is now owned by Microsoft.
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1.0.0
uses: microsoft/setup-msbuild@v1
- name: Compile raytracer
run: |
set VULKAN_SDK=C:\VulkanSDK\%SDK_VERSION%
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ find_package(imgui CONFIG REQUIRED)
find_package(tinyobjloader CONFIG REQUIRED)
find_package(Vulkan REQUIRED)

add_definitions(-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS)

IF (NOT Vulkan_FOUND)
message(FATAL_ERROR "Could not find Vulkan library!")
ELSE()
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<img align="center" src="https://github.com/GPSnoopy/RayTracingInVulkan/blob/master/gallery/LucySettings.jpg">

My implementation of [Peter Shirley's Ray Tracing in One Weekend](https://github.com/RayTracing/raytracing.github.io) books using Vulkan and NVIDIA's RTX extension (VK_NV_ray_tracing, now ported to VK_KHR_ray_tracing). This allows most scenes to be rendered at interactive speed on appropriate hardware.
My implementation of [Peter Shirley's Ray Tracing in One Weekend](https://github.com/RayTracing/raytracing.github.io) books using Vulkan and NVIDIA's RTX extension (formerly VK_NV_ray_tracing, now ported to Khronos cross platform extensions). This allows most scenes to be rendered at interactive speed on appropriate hardware.

The real-time ray tracer can also load full geometry from OBJ files as well as render the procedural spheres from the book. An accumulation buffer is used to increase the sample count when the camera is not moving while keeping the frame rate interactive. I have added a UI built using [Dear ImGui](https://github.com/ocornut/imgui) to allow changing the renderer parameters on the fly. Unlike projects such as [Q2VKPT](http://brechpunkt.de/q2vkpt/), there is no denoising filter. So the image will get noisy when moving the camera.

Expand Down Expand Up @@ -64,7 +64,7 @@ If in doubt, please check the GitHub Actions [continuous integration configurati

## References

### Initial Implementation
### Initial Implementation (NVIDIA vendor specific extension)

* [Vulkan Tutorial](https://vulkan-tutorial.com/)
* [Introduction to Real-Time Ray Tracing with Vulkan](https://devblogs.nvidia.com/vulkan-raytracing)
Expand All @@ -77,8 +77,9 @@ If in doubt, please check the GitHub Actions [continuous integration configurati
* [NVIDIA Vulkan Forums](https://devtalk.nvidia.com/default/board/166/vulkan)
* [Profiling DXR shaders with Timer Instrumentation](https://www.reddit.com/r/vulkan/comments/hhyeyj/profiling_dxr_shaders_with_timer_instrumentation/)

### VK_KHR_ray_tracing Port
### Vulkan Khronos Ray Tracing (cross platform extension)

* [Khronos Vulkan Registry](https://www.khronos.org/registry/vulkan/)
* [NVIDIA Vulkan Ray Tracing Tutorial (VK_KHR_ray_tracing)](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR)
* [NVIDIA Vulkan Ray Tracing Tutorial (VK_KHR_ray_tracing)](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR)
* [NVIDIA Converting VK_NV_ray_tracing to VK_KHR_ray_tracing](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/NV_to_KHR.md.htm)
* [Vulkan Ray Tracing Final Specification Release](https://www.khronos.org/blog/vulkan-ray-tracing-final-specification-release)
80 changes: 15 additions & 65 deletions src/Assets/Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,14 @@
#include "Sphere.hpp"
#include "Texture.hpp"
#include "TextureImage.hpp"
#include "Vulkan/Buffer.hpp"
#include "Vulkan/Device.hpp"
#include "Vulkan/CommandPool.hpp"
#include "Vulkan/BufferUtil.hpp"
#include "Vulkan/ImageView.hpp"
#include "Vulkan/Sampler.hpp"
#include "Utilities/Exception.hpp"
#include <cstring>
#include "Vulkan/SingleTimeCommands.hpp"

namespace Assets {

namespace
{

template <class T>
void CopyFromStagingBuffer(Vulkan::CommandPool& commandPool, Vulkan::Buffer& dstBuffer, const std::vector<T>& content)
{
const auto& device = commandPool.Device();
const auto contentSize = sizeof(content[0]) * content.size();

// Create a temporary host-visible staging buffer.
auto stagingBuffer = std::make_unique<Vulkan::Buffer>(device, contentSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
auto stagingBufferMemory = stagingBuffer->AllocateMemory(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

// Copy the host data into the staging buffer.
const auto data = stagingBufferMemory.Map(0, contentSize);
std::memcpy(data, content.data(), contentSize);
stagingBufferMemory.Unmap();

// Copy the staging buffer to the device buffer.
dstBuffer.CopyFrom(commandPool, *stagingBuffer, contentSize);

// Delete the buffer before the memory
stagingBuffer.reset();
}

template <class T>
void CreateDeviceBuffer(
Vulkan::CommandPool& commandPool,
const char* const name,
const VkBufferUsageFlags usage,
const std::vector<T>& content,
std::unique_ptr<Vulkan::Buffer>& buffer,
std::unique_ptr<Vulkan::DeviceMemory>& memory)
{
const auto& device = commandPool.Device();
const auto& debugUtils = device.DebugUtils();
const auto contentSize = sizeof(content[0]) * content.size();
const VkMemoryAllocateFlags allocateFlags = usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ? VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT : 0;

buffer.reset(new Vulkan::Buffer(device, contentSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage));
memory.reset(new Vulkan::DeviceMemory(buffer->AllocateMemory(allocateFlags, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)));

debugUtils.SetObjectName(buffer->Handle(), (name + std::string(" Buffer")).c_str());
debugUtils.SetObjectName(memory->Handle(), (name + std::string(" Memory")).c_str());

CopyFromStagingBuffer(commandPool, *buffer, content);
}

}
namespace Assets {

Scene::Scene(Vulkan::CommandPool& commandPool, std::vector<Model>&& models, std::vector<Texture>&& textures, bool usedForRayTracing) :
models_(std::move(models)),
Expand Down Expand Up @@ -96,7 +45,7 @@ Scene::Scene(Vulkan::CommandPool& commandPool, std::vector<Model>&& models, std:
}

// Add optional procedurals.
const auto sphere = dynamic_cast<const Sphere*>(model.Procedural());
const auto* const sphere = dynamic_cast<const Sphere*>(model.Procedural());
if (sphere != nullptr)
{
const auto aabb = sphere->BoundingBox();
Expand All @@ -112,24 +61,25 @@ Scene::Scene(Vulkan::CommandPool& commandPool, std::vector<Model>&& models, std:

const auto flag = usedForRayTracing ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT : 0;

CreateDeviceBuffer(commandPool, "Vertices", VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | flag, vertices, vertexBuffer_, vertexBufferMemory_);
CreateDeviceBuffer(commandPool, "Indices", VK_BUFFER_USAGE_INDEX_BUFFER_BIT | flag, indices, indexBuffer_, indexBufferMemory_);
CreateDeviceBuffer(commandPool, "Materials", flag, materials, materialBuffer_, materialBufferMemory_);
CreateDeviceBuffer(commandPool, "Offsets", flag, offsets, offsetBuffer_, offsetBufferMemory_);
Vulkan::BufferUtil::CreateDeviceBuffer(commandPool, "Vertices", VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | flag, vertices, vertexBuffer_, vertexBufferMemory_);
Vulkan::BufferUtil::CreateDeviceBuffer(commandPool, "Indices", VK_BUFFER_USAGE_INDEX_BUFFER_BIT | flag, indices, indexBuffer_, indexBufferMemory_);
Vulkan::BufferUtil::CreateDeviceBuffer(commandPool, "Materials", flag, materials, materialBuffer_, materialBufferMemory_);
Vulkan::BufferUtil::CreateDeviceBuffer(commandPool, "Offsets", flag, offsets, offsetBuffer_, offsetBufferMemory_);

CreateDeviceBuffer(commandPool, "AABBs", flag, aabbs, aabbBuffer_, aabbBufferMemory_);
CreateDeviceBuffer(commandPool, "Procedurals", flag, procedurals, proceduralBuffer_, proceduralBufferMemory_);
Vulkan::BufferUtil::CreateDeviceBuffer(commandPool, "AABBs", flag, aabbs, aabbBuffer_, aabbBufferMemory_);
Vulkan::BufferUtil::CreateDeviceBuffer(commandPool, "Procedurals", flag, procedurals, proceduralBuffer_, proceduralBufferMemory_);


// Upload all textures
textureImages_.reserve(textures_.size());
textureImageViewHandles_.resize(textures_.size());
textureSamplerHandles_.resize(textures_.size());

for (size_t i = 0; i != textures_.size(); ++i)
{
textureImages_.emplace_back(new TextureImage(commandPool, textures_[i]));
textureImageViewHandles_[i] = textureImages_[i]->ImageView().Handle();
textureSamplerHandles_[i] = textureImages_[i]->Sampler().Handle();
textureImages_.emplace_back(new TextureImage(commandPool, textures_[i]));
textureImageViewHandles_[i] = textureImages_[i]->ImageView().Handle();
textureSamplerHandles_[i] = textureImages_[i]->Sampler().Handle();
}
}

Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ set(src_files_vulkan
Vulkan/Application.hpp
Vulkan/Buffer.cpp
Vulkan/Buffer.hpp
Vulkan/BufferUtil.hpp
Vulkan/CommandBuffers.cpp
Vulkan/CommandBuffers.hpp
Vulkan/CommandPool.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/UserInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ void UserInterface::DrawSettings()
ImGui::Text("Profiler");
ImGui::Separator();
ImGui::Checkbox("Show heatmap", &Settings().ShowHeatmap);
ImGui::SliderFloat("Scaling", &Settings().HeatmapScale, 0.01f, 10.0f, "%.2f", 2);
ImGui::SliderFloat("Scaling", &Settings().HeatmapScale, 0.10f, 10.0f, "%.2f", ImGuiSliderFlags_Logarithmic);
ImGui::NewLine();
}
ImGui::End();
Expand Down
2 changes: 1 addition & 1 deletion src/Vulkan/Buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ VkDeviceAddress Buffer::GetDeviceAddress() const

void Buffer::CopyFrom(CommandPool& commandPool, const Buffer& src, VkDeviceSize size)
{
SingleTimeCommands::Submit(commandPool, [&] (VkCommandBuffer commandBuffer)
SingleTimeCommands::Submit(commandPool, [&](VkCommandBuffer commandBuffer)
{
VkBufferCopy copyRegion = {};
copyRegion.srcOffset = 0; // Optional
Expand Down
2 changes: 1 addition & 1 deletion src/Vulkan/Buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Vulkan.hpp"
#include "DeviceMemory.hpp"


namespace Vulkan
{
class CommandPool;
Expand Down Expand Up @@ -32,5 +33,4 @@ namespace Vulkan

VULKAN_HANDLE(VkBuffer, buffer_)
};

}
78 changes: 78 additions & 0 deletions src/Vulkan/BufferUtil.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once

#include "Buffer.hpp"
#include "CommandPool.hpp"
#include "Device.hpp"
#include "DeviceMemory.hpp"
#include <cstring>
#include <memory>
#include <string>
#include <vector>


namespace Vulkan
{
class BufferUtil final
{
public:

template <class T>
static void CopyFromStagingBuffer(CommandPool& commandPool, Buffer& dstBuffer, const std::vector<T>& content);

template <class T>
static void CreateDeviceBuffer(
CommandPool& commandPool,
const char* name,
VkBufferUsageFlags usage,
const std::vector<T>& content,
std::unique_ptr<Buffer>& buffer,
std::unique_ptr<DeviceMemory>& memory);
};

template <class T>
void BufferUtil::CopyFromStagingBuffer(CommandPool& commandPool, Buffer& dstBuffer, const std::vector<T>& content)
{
const auto& device = commandPool.Device();
const auto contentSize = sizeof(content[0]) * content.size();

// Create a temporary host-visible staging buffer.
auto stagingBuffer = std::make_unique<Buffer>(device, contentSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
auto stagingBufferMemory = stagingBuffer->AllocateMemory(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

// Copy the host data into the staging buffer.
const auto data = stagingBufferMemory.Map(0, contentSize);
std::memcpy(data, content.data(), contentSize);
stagingBufferMemory.Unmap();

// Copy the staging buffer to the device buffer.
dstBuffer.CopyFrom(commandPool, *stagingBuffer, contentSize);

// Delete the buffer before the memory
stagingBuffer.reset();
}

template <class T>
void BufferUtil::CreateDeviceBuffer(
CommandPool& commandPool,
const char* const name,
const VkBufferUsageFlags usage,
const std::vector<T>& content,
std::unique_ptr<Buffer>& buffer,
std::unique_ptr<DeviceMemory>& memory)
{
const auto& device = commandPool.Device();
const auto& debugUtils = device.DebugUtils();
const auto contentSize = sizeof(content[0]) * content.size();
const VkMemoryAllocateFlags allocateFlags = usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
? VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT
: 0;

buffer.reset(new Buffer(device, contentSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage));
memory.reset(new DeviceMemory(buffer->AllocateMemory(allocateFlags, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)));

debugUtils.SetObjectName(buffer->Handle(), (name + std::string(" Buffer")).c_str());
debugUtils.SetObjectName(memory->Handle(), (name + std::string(" Memory")).c_str());

CopyFromStagingBuffer(commandPool, *buffer, content);
}
}
Loading

0 comments on commit 8031f39

Please sign in to comment.