Using Vulkan C API
This commit is contained in:
parent
b3e6d84807
commit
e642e9dc3a
83 changed files with 8015 additions and 8163 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
BasedOnStyle: LLVM
|
BasedOnStyle: LLVM
|
||||||
AccessModifierOffset: '-2'
|
AccessModifierOffset: '-2'
|
||||||
AlignAfterOpenBracket: Align
|
AlignAfterOpenBracket: Align
|
||||||
AlignConsecutiveAssignments: 'true'
|
AlignConsecutiveAssignments: 'true'
|
||||||
|
|
@ -21,7 +21,7 @@ BreakBeforeBinaryOperators: NonAssignment
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakBeforeTernaryOperators: 'false'
|
BreakBeforeTernaryOperators: 'false'
|
||||||
BreakConstructorInitializersBeforeComma: 'true'
|
BreakConstructorInitializersBeforeComma: 'true'
|
||||||
ColumnLimit: '100'
|
ColumnLimit: '120'
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
|
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
|
||||||
Cpp11BracedListStyle: 'true'
|
Cpp11BracedListStyle: 'true'
|
||||||
IndentCaseLabels: 'true'
|
IndentCaseLabels: 'true'
|
||||||
|
|
@ -44,7 +44,7 @@ SpacesInSquareBrackets: 'false'
|
||||||
Standard: Cpp11
|
Standard: Cpp11
|
||||||
TabWidth: '2'
|
TabWidth: '2'
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
SortIncludes: 'true'
|
SortIncludes: 'false'
|
||||||
ReflowComments: 'false'
|
ReflowComments: 'false'
|
||||||
BraceWrapping: {
|
BraceWrapping: {
|
||||||
AfterClass: 'true'
|
AfterClass: 'true'
|
||||||
|
|
@ -58,7 +58,7 @@ BraceWrapping: {
|
||||||
BeforeElse: 'true'
|
BeforeElse: 'true'
|
||||||
IndentBraces: 'false'
|
IndentBraces: 'false'
|
||||||
}
|
}
|
||||||
PenaltyExcessCharacter: 9999
|
PenaltyExcessCharacter: 1
|
||||||
PenaltyBreakBeforeFirstCallParameter: 40
|
PenaltyBreakBeforeFirstCallParameter: 40
|
||||||
PenaltyBreakFirstLessLess: 1
|
PenaltyBreakFirstLessLess: 1
|
||||||
PenaltyBreakComment: 30
|
PenaltyBreakComment: 30
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,7 @@ void ObjLoader::loadModel(const std::string& filename)
|
||||||
m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]);
|
m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]);
|
||||||
m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]);
|
m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]);
|
||||||
m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]);
|
m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]);
|
||||||
m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1],
|
m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1], material.transmittance[2]);
|
||||||
material.transmittance[2]);
|
|
||||||
m.dissolve = material.dissolve;
|
m.dissolve = material.dissolve;
|
||||||
m.ior = material.ior;
|
m.ior = material.ior;
|
||||||
m.shininess = material.shininess;
|
m.shininess = material.shininess;
|
||||||
|
|
@ -67,8 +66,7 @@ void ObjLoader::loadModel(const std::string& filename)
|
||||||
{
|
{
|
||||||
m_vertices.reserve(shape.mesh.indices.size() + m_vertices.size());
|
m_vertices.reserve(shape.mesh.indices.size() + m_vertices.size());
|
||||||
m_indices.reserve(shape.mesh.indices.size() + m_indices.size());
|
m_indices.reserve(shape.mesh.indices.size() + m_indices.size());
|
||||||
m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(),
|
m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(), shape.mesh.material_ids.end());
|
||||||
shape.mesh.material_ids.end());
|
|
||||||
|
|
||||||
for(const auto& index : shape.mesh.indices)
|
for(const auto& index : shape.mesh.indices)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ The directory structure should be looking like:
|
||||||
**********************************************************
|
**********************************************************
|
||||||
|
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning CMake
|
||||||
**Run CMake** in vk_raytracing_tutorial_KHR.
|
**Run CMake** in vk_raytracing_tutorial_KHR.
|
||||||
|
|
||||||
!!! Warning Beta Vulkan SDK
|
!!! Warning Beta Vulkan SDK
|
||||||
|
|
|
||||||
|
|
@ -202,18 +202,18 @@ void HelloVulkan::createLanternIndirectBuffer()
|
||||||
|
|
||||||
// m_alloc behind the scenes uses cmdBuf to transfer data to the buffer.
|
// m_alloc behind the scenes uses cmdBuf to transfer data to the buffer.
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||||
|
|
||||||
using Usage = vk::BufferUsageFlagBits;
|
using Usage = VkBufferUsageFlagBits;
|
||||||
m_lanternIndirectBuffer =
|
m_lanternIndirectBuffer = m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount,
|
||||||
m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount,
|
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||||
Usage::eIndirectBuffer | Usage::eTransferDst
|
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||||
| Usage::eShaderDeviceAddress | Usage::eStorageBuffer,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
vk::MemoryPropertyFlagBits::eDeviceLocal);
|
|
||||||
|
|
||||||
std::vector<LanternIndirectEntry> entries(m_lanternCount);
|
std::vector<LanternIndirectEntry> entries(m_lanternCount);
|
||||||
for (size_t i = 0; i < m_lanternCount; ++i) entries[i].lantern = m_lanterns[i];
|
for(size_t i = 0; i < m_lanternCount; ++i)
|
||||||
cmdBuf.updateBuffer(m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data());
|
entries[i].lantern = m_lanterns[i];
|
||||||
|
vkCmdUpdateBuffer(cmdBuf, m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data());
|
||||||
|
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
cmdBufGet.submitAndWait(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -371,11 +371,11 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_lanternIndirectDescPool;
|
VkDescriptorPool m_lanternIndirectDescPool;
|
||||||
vk::DescriptorSetLayout m_lanternIndirectDescSetLayout;
|
VkDescriptorSetLayout m_lanternIndirectDescSetLayout;
|
||||||
vk::DescriptorSet m_lanternIndirectDescSet;
|
VkDescriptorSet m_lanternIndirectDescSet;
|
||||||
vk::PipelineLayout m_lanternIndirectCompPipelineLayout;
|
VkPipelineLayout m_lanternIndirectCompPipelineLayout;
|
||||||
vk::Pipeline m_lanternIndirectCompPipeline;
|
VkPipeline m_lanternIndirectCompPipeline;
|
||||||
````
|
````
|
||||||
|
|
||||||
`hello_vulkan.cpp`:
|
`hello_vulkan.cpp`:
|
||||||
|
|
@ -385,26 +385,25 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes.
|
||||||
// The compute shader just needs read/write access to the buffer of LanternIndirectEntry.
|
// The compute shader just needs read/write access to the buffer of LanternIndirectEntry.
|
||||||
void HelloVulkan::createLanternIndirectDescriptorSet()
|
void HelloVulkan::createLanternIndirectDescriptorSet()
|
||||||
{
|
{
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
|
||||||
|
|
||||||
// Lantern buffer (binding = 0)
|
// Lantern buffer (binding = 0)
|
||||||
m_lanternIndirectDescSetLayoutBind.addBinding( //
|
m_lanternIndirectDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||||
vkDSLB(0, vkDT::eStorageBuffer, 1, vkSS::eCompute));
|
|
||||||
|
|
||||||
m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device);
|
m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device);
|
||||||
m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device);
|
m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device);
|
||||||
m_lanternIndirectDescSet =
|
|
||||||
m_device.allocateDescriptorSets({m_lanternIndirectDescPool, 1, &m_lanternIndirectDescSetLayout})[0];
|
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||||
|
allocateInfo.descriptorPool = m_lanternIndirectDescPool;
|
||||||
|
allocateInfo.descriptorSetCount = 1;
|
||||||
|
allocateInfo.pSetLayouts = &m_lanternIndirectDescSetLayout;
|
||||||
|
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_lanternIndirectDescSet);
|
||||||
|
|
||||||
|
|
||||||
assert(m_lanternIndirectBuffer.buffer);
|
assert(m_lanternIndirectBuffer.buffer);
|
||||||
vk::DescriptorBufferInfo lanternBufferInfo{
|
VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)};
|
||||||
m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)};
|
|
||||||
|
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, &lanternBufferInfo));
|
writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, &lanternBufferInfo));
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create compute pipeline used to fill m_lanternIndirectBuffer with parameters
|
// Create compute pipeline used to fill m_lanternIndirectBuffer with parameters
|
||||||
|
|
@ -412,32 +411,31 @@ void HelloVulkan::createLanternIndirectDescriptorSet()
|
||||||
void HelloVulkan::createLanternIndirectCompPipeline()
|
void HelloVulkan::createLanternIndirectCompPipeline()
|
||||||
{
|
{
|
||||||
// Compile compute shader and package as stage.
|
// Compile compute shader and package as stage.
|
||||||
vk::ShaderModule computeShader =
|
VkShaderModule computeShader =
|
||||||
nvvk::createShaderModule(m_device, //
|
nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true));
|
||||||
nvh::loadFile("shaders/lanternIndirect.comp.spv", true, defaultSearchPaths, true));
|
VkPipelineShaderStageCreateInfo stageInfo{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
||||||
vk::PipelineShaderStageCreateInfo stageInfo;
|
stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||||
stageInfo.setStage(vk::ShaderStageFlagBits::eCompute);
|
stageInfo.module = computeShader;
|
||||||
stageInfo.setModule(computeShader);
|
stageInfo.pName = "main";
|
||||||
stageInfo.setPName("main");
|
|
||||||
|
|
||||||
// Set up push constant and pipeline layout.
|
// Set up push constant and pipeline layout.
|
||||||
constexpr auto pushSize = static_cast<uint32_t>(sizeof(m_lanternIndirectPushConstants));
|
constexpr auto pushSize = static_cast<uint32_t>(sizeof(m_lanternIndirectPushConstants));
|
||||||
vk::PushConstantRange pushCRange = {vk::ShaderStageFlagBits::eCompute, 0, pushSize};
|
VkPushConstantRange pushCRange = {VK_SHADER_STAGE_COMPUTE_BIT, 0, pushSize};
|
||||||
static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant");
|
static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant");
|
||||||
vk::PipelineLayoutCreateInfo layoutInfo;
|
VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
layoutInfo.setSetLayoutCount(1);
|
layoutInfo.setLayoutCount = 1;
|
||||||
layoutInfo.setPSetLayouts(&m_lanternIndirectDescSetLayout);
|
layoutInfo.pSetLayouts = &m_lanternIndirectDescSetLayout;
|
||||||
layoutInfo.setPushConstantRangeCount(1);
|
layoutInfo.pushConstantRangeCount = 1;
|
||||||
layoutInfo.setPPushConstantRanges(&pushCRange);
|
layoutInfo.pPushConstantRanges = &pushCRange;
|
||||||
m_lanternIndirectCompPipelineLayout = m_device.createPipelineLayout(layoutInfo);
|
vkCreatePipelineLayout(m_device, &layoutInfo, nullptr, &m_lanternIndirectCompPipelineLayout);
|
||||||
|
|
||||||
// Create compute pipeline.
|
// Create compute pipeline.
|
||||||
vk::ComputePipelineCreateInfo pipelineInfo;
|
VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
|
||||||
pipelineInfo.setStage(stageInfo);
|
pipelineInfo.stage = stageInfo;
|
||||||
pipelineInfo.setLayout(m_lanternIndirectCompPipelineLayout);
|
pipelineInfo.layout = m_lanternIndirectCompPipelineLayout;
|
||||||
m_lanternIndirectCompPipeline = static_cast<const vk::Pipeline&>(m_device.createComputePipeline({}, pipelineInfo));
|
vkCreateComputePipelines(m_device, {}, 1, &pipelineInfo, nullptr, &m_lanternIndirectCompPipeline);
|
||||||
|
|
||||||
m_device.destroy(computeShader);
|
vkDestroyShaderModule(m_device, computeShader, nullptr);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -464,28 +462,41 @@ pipeline barrier synchronizing access to the `LanternIndirectEntry` array
|
||||||
between the compute shader and indirect draw stages.
|
between the compute shader and indirect draw stages.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Ray Tracing the scene
|
||||||
|
//
|
||||||
|
// The raytracing is split into multiple passes:
|
||||||
|
//
|
||||||
|
// First pass fills in the initial values for every pixel in the output image.
|
||||||
|
// Illumination and shadow rays come from the main light.
|
||||||
|
//
|
||||||
|
// Subsequently, one lantern pass is run for each lantern in the scene. We run
|
||||||
|
// a compute shader to calculate a bounding scissor rectangle for each lantern's light
|
||||||
|
// effect. This is stored in m_lanternIndirectBuffer. Then an indirect trace rays command
|
||||||
|
// is run for every lantern within its scissor rectangle. The lanterns' light
|
||||||
|
// contribution is additively blended into the output image.
|
||||||
|
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
||||||
{
|
{
|
||||||
// Before tracing rays, we need to dispatch the compute shaders that
|
// Before tracing rays, we need to dispatch the compute shaders that
|
||||||
// fill in the ray trace indirect parameters for each lantern pass.
|
// fill in the ray trace indirect parameters for each lantern pass.
|
||||||
|
|
||||||
// First, barrier before, ensure writes aren't visible to previous frame.
|
// First, barrier before, ensure writes aren't visible to previous frame.
|
||||||
vk::BufferMemoryBarrier bufferBarrier;
|
VkBufferMemoryBarrier bufferBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eIndirectCommandRead);
|
bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
||||||
bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderWrite);
|
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
bufferBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
bufferBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
bufferBarrier.setBuffer(m_lanternIndirectBuffer.buffer);
|
bufferBarrier.buffer = m_lanternIndirectBuffer.buffer;
|
||||||
bufferBarrier.offset = 0;
|
bufferBarrier.offset = 0;
|
||||||
bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0];
|
bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0];
|
||||||
cmdBuf.pipelineBarrier( //
|
vkCmdPipelineBarrier(cmdBuf,
|
||||||
vk::PipelineStageFlagBits::eDrawIndirect, //
|
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, //
|
||||||
vk::PipelineStageFlagBits::eComputeShader,//
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
|
||||||
vk::DependencyFlags(0), //
|
VkDependencyFlags(0), //
|
||||||
{}, {bufferBarrier}, {});
|
0, nullptr, 1, &bufferBarrier, 0, nullptr);
|
||||||
|
|
||||||
// Bind compute shader, update push constant and descriptors, dispatch compute.
|
// Bind compute shader, update push constant and descriptors, dispatch compute.
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipeline);
|
||||||
nvmath::mat4 view = getViewMatrix();
|
nvmath::mat4 view = getViewMatrix();
|
||||||
m_lanternIndirectPushConstants.viewRowX = view.row(0);
|
m_lanternIndirectPushConstants.viewRowX = view.row(0);
|
||||||
m_lanternIndirectPushConstants.viewRowY = view.row(1);
|
m_lanternIndirectPushConstants.viewRowY = view.row(1);
|
||||||
|
|
@ -494,31 +505,29 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
|
||||||
m_lanternIndirectPushConstants.nearZ = nearZ;
|
m_lanternIndirectPushConstants.nearZ = nearZ;
|
||||||
m_lanternIndirectPushConstants.screenX = m_size.width;
|
m_lanternIndirectPushConstants.screenX = m_size.width;
|
||||||
m_lanternIndirectPushConstants.screenY = m_size.height;
|
m_lanternIndirectPushConstants.screenY = m_size.height;
|
||||||
m_lanternIndirectPushConstants.lanternCount = m_lanternCount;
|
m_lanternIndirectPushConstants.lanternCount = int32_t(m_lanternCount);
|
||||||
cmdBuf.pushConstants<LanternIndirectPushConstants>(
|
vkCmdPushConstants(cmdBuf, m_lanternIndirectCompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0,
|
||||||
m_lanternIndirectCompPipelineLayout,
|
sizeof(LanternIndirectPushConstants), &m_lanternIndirectPushConstants);
|
||||||
vk::ShaderStageFlagBits::eCompute,
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipelineLayout, 0, 1,
|
||||||
0, m_lanternIndirectPushConstants);
|
&m_lanternIndirectDescSet, 0, nullptr);
|
||||||
cmdBuf.bindDescriptorSets(
|
vkCmdDispatch(cmdBuf, 1, 1, 1);
|
||||||
vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipelineLayout, 0, {m_lanternIndirectDescSet}, {});
|
|
||||||
cmdBuf.dispatch(1, 1, 1);
|
|
||||||
|
|
||||||
// Ensure compute results are visible when doing indirect ray trace.
|
// Ensure compute results are visible when doing indirect ray trace.
|
||||||
bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eIndirectCommandRead);
|
bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
||||||
cmdBuf.pipelineBarrier( //
|
vkCmdPipelineBarrier(cmdBuf,
|
||||||
vk::PipelineStageFlagBits::eComputeShader, //
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
|
||||||
vk::PipelineStageFlagBits::eDrawIndirect, //
|
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, //
|
||||||
vk::DependencyFlags(0), //
|
VkDependencyFlags(0), //
|
||||||
{}, {bufferBarrier}, {});
|
0, nullptr, 1, &bufferBarrier, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
// Now move on to the actual ray tracing.
|
// Now move on to the actual ray tracing.
|
||||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
m_debug.beginLabel(cmdBuf, "Ray trace");
|
||||||
````
|
````
|
||||||
|
|
||||||
!!! TIP `eDrawIndirect`
|
!!! TIP `VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`
|
||||||
`vk::PipelineStageFlagBits::eDrawIndirect` (`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`)
|
`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`
|
||||||
covers the stage that sources indirect paramaters for compute and ray trace
|
covers the stage that sources indirect paramaters for compute and ray trace
|
||||||
indirect commands, not just graphics draw indirect commands.
|
indirect commands, not just graphics draw indirect commands.
|
||||||
|
|
||||||
|
|
@ -542,7 +551,7 @@ they were factored out to common code in `hello_vulkan.h`.
|
||||||
The function for updating the uniform buffer is tweaked to match.
|
The function for updating the uniform buffer is tweaked to match.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||||
|
|
||||||
|
|
@ -580,35 +589,35 @@ buffers. The relevent code in `HelloVulkan::createLanternModel` for creating the
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Package vertex and index buffers as BlasInput.
|
// Package vertex and index buffers as BlasInput.
|
||||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_lanternVertexBuffer.buffer});
|
VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternVertexBuffer.buffer);
|
||||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_lanternIndexBuffer.buffer});
|
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternIndexBuffer.buffer);
|
||||||
|
|
||||||
uint32_t maxPrimitiveCount = uint32_t(indices.size() / 3);
|
auto maxPrimitiveCount = uint32_t(indices.size() / 3);
|
||||||
|
|
||||||
// Describe buffer as packed array of float vec3.
|
// Describe buffer as packed array of float vec3.
|
||||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data.
|
triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
|
||||||
triangles.setVertexData(vertexAddress);
|
triangles.vertexData.deviceAddress = vertexAddress;
|
||||||
triangles.setVertexStride(sizeof(nvmath::vec3f));
|
triangles.vertexStride = sizeof(nvmath::vec3f);
|
||||||
// Describe index data (32-bit unsigned int)
|
// Describe index data (32-bit unsigned int)
|
||||||
triangles.setIndexType(vk::IndexType::eUint32);
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
triangles.setIndexData(indexAddress);
|
triangles.indexData.deviceAddress = indexAddress;
|
||||||
// Indicate identity transform by setting transformData to null device pointer.
|
// Indicate identity transform by setting transformData to null device pointer.
|
||||||
triangles.setTransformData({});
|
//triangles.transformData = {};
|
||||||
triangles.setMaxVertex(vertices.size());
|
triangles.maxVertex = uint32_t(vertices.size());
|
||||||
|
|
||||||
// Identify the above data as containing opaque triangles.
|
// Identify the above data as containing opaque triangles.
|
||||||
vk::AccelerationStructureGeometryKHR asGeom;
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||||
asGeom.geometry.setTriangles(triangles);
|
asGeom.geometry.triangles = triangles;
|
||||||
|
|
||||||
// The entire array will be used to build the BLAS.
|
// The entire array will be used to build the BLAS.
|
||||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||||
offset.setFirstVertex(0);
|
offset.firstVertex = 0;
|
||||||
offset.setPrimitiveCount(maxPrimitiveCount);
|
offset.primitiveCount = maxPrimitiveCount;
|
||||||
offset.setPrimitiveOffset(0);
|
offset.primitiveOffset = 0;
|
||||||
offset.setTransformOffset(0);
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
// Our blas is made from only one geometry, but could be made of many geometries
|
// Our blas is made from only one geometry, but could be made of many geometries
|
||||||
m_lanternBlasInput.asGeometry.emplace_back(asGeom);
|
m_lanternBlasInput.asGeometry.emplace_back(asGeom);
|
||||||
|
|
@ -647,7 +656,7 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
m_lanternBlasId = allBlas.size();
|
m_lanternBlasId = allBlas.size();
|
||||||
allBlas.emplace_back(m_lanternBlasInput);
|
allBlas.emplace_back(m_lanternBlasInput);
|
||||||
|
|
||||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -696,7 +705,7 @@ void HelloVulkan::createTopLevelAS()
|
||||||
tlas.emplace_back(lanternInstance);
|
tlas.emplace_back(lanternInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -749,25 +758,21 @@ The last task is done in `HelloVulkan::createRtDescriptorSet`
|
||||||
//
|
//
|
||||||
void HelloVulkan::createRtDescriptorSet()
|
void HelloVulkan::createRtDescriptorSet()
|
||||||
{
|
{
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
// Lantern buffer (binding = 2)
|
// Lantern buffer (binding = 2)
|
||||||
m_rtDescSetLayoutBind.addBinding( //
|
m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||||
vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
assert(m_lanternCount > 0);
|
assert(m_lanternCount > 0);
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &lanternBufferInfo));
|
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &lanternBufferInfo));
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -809,34 +814,36 @@ group after the OBJ hit group, to match the `hitGroupId`s assigned earlier in th
|
||||||
TLAS build.
|
TLAS build.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// OBJ Primary Ray Hit Group - Closest Hit + AnyHit (not used)
|
|
||||||
vk::ShaderModule chitSM =
|
|
||||||
nvvk::createShaderModule(m_device, //
|
|
||||||
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
|
|
||||||
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
enum StageIndices
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
{
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
// ...
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
eClosestHit,
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
eClosestHitLantern,
|
||||||
m_rtShaderGroups.push_back(hg);
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// OBJ Primary Ray Hit Group - Closest Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHit] = stage;
|
||||||
|
|
||||||
// Lantern Primary Ray Hit Group
|
// Lantern Primary Ray Hit Group
|
||||||
vk::ShaderModule lanternChitSM =
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
|
||||||
nvvk::createShaderModule(m_device, //
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
nvh::loadFile("shaders/lantern.rchit.spv", true, paths, true));
|
stages[eClosestHitLantern] = stage;
|
||||||
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR lanternHg{
|
|
||||||
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
|
||||||
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(lanternHg);
|
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
m_device.destroy(lanternChitSM);
|
// closest hit shader
|
||||||
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.closestHitShader = eClosestHit;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
group.closestHitShader = eClosestHitLantern;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
````
|
````
|
||||||
|
|
||||||
We don't have to modify `HelloVulkan::createRtShaderBindingTable`. Changes to the number of
|
We don't have to modify `HelloVulkan::createRtShaderBindingTable`. Changes to the number of
|
||||||
|
|
@ -1104,39 +1111,51 @@ after loading `raytraceShadow.rmiss.spv`.
|
||||||
```` C
|
```` C
|
||||||
// Miss shader 2 is invoked when a shadow ray for lantern lighting misses the
|
// Miss shader 2 is invoked when a shadow ray for lantern lighting misses the
|
||||||
// lantern. It shouldn't be invoked, but I include it just in case.
|
// lantern. It shouldn't be invoked, but I include it just in case.
|
||||||
vk::ShaderModule lanternmissSM = nvvk::createShaderModule(
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||||
m_device, nvh::loadFile("shaders/lanternShadow.rmiss.spv", true, paths, true));
|
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||||
|
stages[eMissLantern] = stage;
|
||||||
````
|
````
|
||||||
|
|
||||||
and add this code for loading the last 2 closest hit shaders after loading
|
and add this code for loading the last 2 closest hit shaders after loading
|
||||||
`lantern.rchit.spv`:
|
`lantern.rchit.spv`:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
|
// Lantern Primary Ray Hit Group
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHitLantern] = stage;
|
||||||
|
|
||||||
// OBJ Lantern Shadow Ray Hit Group
|
// OBJ Lantern Shadow Ray Hit Group
|
||||||
vk::ShaderModule lanternShadowObjChitSM =
|
stage.module =
|
||||||
nvvk::createShaderModule(m_device, //
|
nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true));
|
||||||
nvh::loadFile("shaders/lanternShadowObj.rchit.spv", true, paths, true));
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHitLanternShdObj] = stage;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Lantern Shadow Miss
|
||||||
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
|
group.generalShader = eMissLantern;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
|
||||||
|
// closest hit shader
|
||||||
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.closestHitShader = eClosestHit;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
group.closestHitShader = eClosestHitLantern;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
group.closestHitShader = eClosestHitLanternShdObj;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
group.closestHitShader = eClosestHitLanternShd;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{
|
|
||||||
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
|
||||||
lanternShadowObjHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(lanternShadowObjHg);
|
|
||||||
|
|
||||||
// Lantern Lantern Shadow Ray Hit Group
|
|
||||||
vk::ShaderModule lanternShadowLanternChitSM =
|
|
||||||
nvvk::createShaderModule(m_device, //
|
|
||||||
nvh::loadFile("shaders/lanternShadowLantern.rchit.spv", true, paths, true));
|
|
||||||
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowLanternHg{
|
|
||||||
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
|
||||||
lanternShadowLanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(lanternShadowLanternHg);
|
|
||||||
````
|
````
|
||||||
|
|
||||||
We need to destroy the added shader modules at the end of the function.
|
We need to destroy the added shader modules at the end of the function.
|
||||||
|
|
@ -1386,7 +1405,7 @@ pass. There are minimal changes from before, we just have to
|
||||||
to account for the added shaders.
|
to account for the added shaders.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
using Stride = vk::StridedDeviceAddressRegionKHR;
|
using Stride = VkStridedDeviceAddressRegionKHR;
|
||||||
std::array<Stride, 4> strideAddresses{
|
std::array<Stride, 4> strideAddresses{
|
||||||
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
|
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
|
||||||
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss
|
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss
|
||||||
|
|
@ -1394,9 +1413,7 @@ pass. There are minimal changes from before, we just have to
|
||||||
Stride{0u, 0u, 0u}}; // callable
|
Stride{0u, 0u, 0u}}; // callable
|
||||||
|
|
||||||
// First pass, illuminate scene with global light.
|
// First pass, illuminate scene with global light.
|
||||||
cmdBuf.traceRaysKHR(
|
vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3],
|
||||||
&strideAddresses[0], &strideAddresses[1], //
|
|
||||||
&strideAddresses[2], &strideAddresses[3], //
|
|
||||||
m_size.width, m_size.height, 1);
|
m_size.width, m_size.height, 1);
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -1413,24 +1430,22 @@ we need a barrier between every pass.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Barrier to ensure previous pass finished.
|
// Barrier to ensure previous pass finished.
|
||||||
vk::Image offscreenImage{m_offscreenColor.image};
|
VkImage offscreenImage{m_offscreenColor.image};
|
||||||
vk::ImageSubresourceRange colorRange(
|
VkImageSubresourceRange colorRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS};
|
||||||
vk::ImageAspectFlagBits::eColor, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS
|
VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||||
);
|
imageBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
vk::ImageMemoryBarrier imageBarrier;
|
imageBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
imageBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
imageBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
imageBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
imageBarrier.image = offscreenImage;
|
||||||
imageBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
imageBarrier.subresourceRange = colorRange;
|
||||||
imageBarrier.setImage(offscreenImage);
|
imageBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
imageBarrier.setSubresourceRange(colorRange);
|
imageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
imageBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
vkCmdPipelineBarrier(cmdBuf,
|
||||||
imageBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, //
|
||||||
cmdBuf.pipelineBarrier(
|
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, //
|
||||||
vk::PipelineStageFlagBits::eRayTracingShaderKHR, //
|
VkDependencyFlags(0), //
|
||||||
vk::PipelineStageFlagBits::eRayTracingShaderKHR, //
|
0, nullptr, 0, nullptr, 1, &imageBarrier);
|
||||||
vk::DependencyFlags(0), //
|
|
||||||
{}, {}, {imageBarrier});
|
|
||||||
````
|
````
|
||||||
|
|
||||||
Then, we can pass the number of the lantern pass being performed (`i`), and look
|
Then, we can pass the number of the lantern pass being performed (`i`), and look
|
||||||
|
|
@ -1443,17 +1458,18 @@ is the first member of `LanternIndirectEntry`.
|
||||||
```` C
|
```` C
|
||||||
// Set lantern pass number.
|
// Set lantern pass number.
|
||||||
m_rtPushConstants.lanternPassNumber = i;
|
m_rtPushConstants.lanternPassNumber = i;
|
||||||
cmdBuf.pushConstants<RtPushConstant>(m_rtPipelineLayout,
|
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
||||||
vk::ShaderStageFlagBits::eRaygenKHR
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
|
||||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
0, sizeof(RtPushConstant), &m_rtPushConstants);
|
||||||
| vk::ShaderStageFlagBits::eMissKHR,
|
|
||||||
0, m_rtPushConstants);
|
|
||||||
|
VkDeviceAddress indirectDeviceAddress =
|
||||||
|
nvvk::getBufferDeviceAddress(m_device, m_lanternIndirectBuffer.buffer) + i * sizeof(LanternIndirectEntry);
|
||||||
|
|
||||||
// Execute lantern pass.
|
// Execute lantern pass.
|
||||||
cmdBuf.traceRaysIndirectKHR(
|
vkCmdTraceRaysIndirectKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], //
|
||||||
&strideAddresses[0], &strideAddresses[1], //
|
|
||||||
&strideAddresses[2], &strideAddresses[3], //
|
&strideAddresses[2], &strideAddresses[3], //
|
||||||
m_device.getBufferAddress({m_lanternIndirectBuffer.buffer}) + i * sizeof(LanternIndirectEntry));
|
indirectDeviceAddress);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -1480,10 +1496,10 @@ void HelloVulkan::destroyResources()
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
// ...
|
// ...
|
||||||
m_device.destroy(m_lanternIndirectDescPool);
|
vkDestroyDescriptorPool(m_device, m_lanternIndirectDescPool, nullptr);
|
||||||
m_device.destroy(m_lanternIndirectDescSetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_lanternIndirectDescSetLayout, nullptr);
|
||||||
m_device.destroy(m_lanternIndirectCompPipeline);
|
vkDestroyPipeline(m_device, m_lanternIndirectCompPipeline, nullptr);
|
||||||
m_device.destroy(m_lanternIndirectCompPipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_lanternIndirectCompPipelineLayout, nullptr);
|
||||||
m_alloc.destroy(m_lanternIndirectBuffer);
|
m_alloc.destroy(m_lanternIndirectBuffer);
|
||||||
m_alloc.destroy(m_lanternVertexBuffer);
|
m_alloc.destroy(m_lanternVertexBuffer);
|
||||||
m_alloc.destroy(m_lanternIndexBuffer);
|
m_alloc.destroy(m_lanternIndexBuffer);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Licensed as public domain or BSD 2-clause, whichever is more convenient for you.
|
Licensed as public domain or BSD 2-clause, whichever is more convenient for you.
|
||||||
Originally from https://github.com/aras-p/markdeep-docs-style */
|
Originally from https://github.com/aras-p/markdeep-docs-style */
|
||||||
body {
|
body {
|
||||||
max-width: 50em;
|
max-width: 80em;
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
/*margin: 1.5em;*/
|
/*margin: 1.5em;*/
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,11 @@ cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
!!! Note Note
|
||||||
|
If you are not using Visual Studio 2019 and up, make sure to choose x64 platform. For 2019, it is the default
|
||||||
|
but not for previous versions.
|
||||||
|
|
||||||
|
|
||||||
## Tools Installation
|
## Tools Installation
|
||||||
|
|
||||||
You need a graphics card with support for the `VK_KHR_ray_tracing_pipeline` extension.
|
You need a graphics card with support for the `VK_KHR_ray_tracing_pipeline` extension.
|
||||||
|
|
@ -75,9 +80,10 @@ For NVIDIA graphics cards, you need a [Vulkan driver](https://developer.nvidia.c
|
||||||
released in 2021 or later.
|
released in 2021 or later.
|
||||||
|
|
||||||
The Vulkan SDK 1.2.161 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project.
|
The Vulkan SDK 1.2.161 and up which can be found under https://vulkan.lunarg.com/sdk/home will work with this project.
|
||||||
|
This version was tested with 1.2.176.1.
|
||||||
|
|
||||||
!!! Tip Visual Assist
|
!!! Tip Visual Assist
|
||||||
To get auto-completion, edit vulkan.hpp and change two places from:<br>
|
To get auto-completion with Vulkan CPP, edit vulkan.hpp and change two places from:<br>
|
||||||
`namespace VULKAN_HPP_NAMESPACE` to `namespace vk`
|
`namespace VULKAN_HPP_NAMESPACE` to `namespace vk`
|
||||||
|
|
||||||
# Compiling & Running
|
# Compiling & Running
|
||||||
|
|
@ -109,12 +115,10 @@ extensions will need to be added.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
&accelFeature);
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
|
||||||
&rtPipelineFeature);
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
|
|
@ -123,25 +127,15 @@ contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||||
````
|
````
|
||||||
|
|
||||||
Behind the scenes, the helper is selecting a physical device supporting the required `VK_KHR_*` extensions,
|
Behind the scenes, the helper is selecting a physical device supporting the required `VK_KHR_*` extensions,
|
||||||
then placing the `vk::PhysicalDevice*FeaturesKHR` structs on the `pNext` chain of `VkDeviceCreateInfo` before
|
then placing the `VkPhysicalDevice*FeaturesKHR` structs on the `pNext` chain of `VkDeviceCreateInfo` before
|
||||||
calling `vkCreateDevice`. This enables the ray tracing features and fills in the two structs with info on the
|
calling `vkCreateDevice`. This enables the ray tracing features and fills in the two structs with info on the
|
||||||
device's ray tracing capabilities.
|
device's ray tracing capabilities. If you are curious, this is done in the Vulkan context creation helper:
|
||||||
|
[`Context::initInstance()`](https://github.com/nvpro-samples/nvpro_core/blob/1c59039a1ab0d777c79a29b09879a2686ec286dc/nvvk/context_vk.cpp#L211).
|
||||||
|
|
||||||
!!! NOTE Loading function pointers
|
!!! NOTE Loading function pointers
|
||||||
As in OpenGL, when using extensions in Vulkan, you need to manually load in function pointers for extensions, using
|
As in OpenGL, when using extensions in Vulkan, you need to manually load in function pointers for extensions, using
|
||||||
`vkGetInstanceProcAddr` and `vkGetDeviceProcAddr`. The `nvvk::Context` class that this sample depends on magically does
|
`vkGetInstanceProcAddr` and `vkGetDeviceProcAddr`. The `nvvk::Context` class that this sample depends on magically does
|
||||||
this for you, for the Vulkan C API. For the Vulkan C++ API, the `nvvk::AppBase::setup` function follows the instructions
|
this for you, for the Vulkan C API by calling `load_VK_EXTENSION_SUBSET`.
|
||||||
at <a href="https://github.com/KhronosGroup/Vulkan-Hpp#extensions--per-device-function-pointers">the vulkan.hpp Github page</a>
|
|
||||||
to load the C++ entry points:
|
|
||||||
```` C
|
|
||||||
// Initialize function pointers
|
|
||||||
vk::DynamicLoader dl;
|
|
||||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
|
|
||||||
dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
|
|
||||||
````
|
|
||||||
|
|
||||||
In the `HelloVulkan` class in `hello_vulkan.h`, add an initialization function and a member storing the capabilities of
|
In the `HelloVulkan` class in `hello_vulkan.h`, add an initialization function and a member storing the capabilities of
|
||||||
the GPU for ray tracing:
|
the GPU for ray tracing:
|
||||||
|
|
@ -149,7 +143,7 @@ the GPU for ray tracing:
|
||||||
```` C
|
```` C
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
````
|
````
|
||||||
|
|
||||||
At the end of `hello_vulkan.cpp`, add the body of `initRayTracing()`, which will query the ray tracing capabilities
|
At the end of `hello_vulkan.cpp`, add the body of `initRayTracing()`, which will query the ray tracing capabilities
|
||||||
|
|
@ -167,20 +161,12 @@ needed in a later section for creating the shader binding table.
|
||||||
void HelloVulkan::initRayTracing()
|
void HelloVulkan::initRayTracing()
|
||||||
{
|
{
|
||||||
// Requesting ray tracing properties
|
// Requesting ray tracing properties
|
||||||
auto properties =
|
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
prop2.pNext = &m_rtProperties;
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
!!! Tip For readers unfamiliar with vulkan.hpp
|
|
||||||
The above code is creating a `pNext` structure chain consisting of a `VkPhysicalDeviceProperties2` followed
|
|
||||||
by `VkPhysicalDeviceRayTracingPipelinePropertiesKHR`, passing it to `vkGetPhysicalDeviceProperties2`,
|
|
||||||
then extracting the filled `VkPhysicalDeviceRayTracingPipelinePropertiesKHR` structure of the chain.
|
|
||||||
`auto` is a `C++11` feature for type deduction, allowing us to avoid redundantly specifying types
|
|
||||||
(specifically, `vk::StructureChain<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceRayTracingPipelineFeaturesKHR>`).
|
|
||||||
|
|
||||||
## main
|
## main
|
||||||
|
|
||||||
In `main.cpp`, in the `main()` function, we call the initialization method right after
|
In `main.cpp`, in the `main()` function, we call the initialization method right after
|
||||||
|
|
@ -244,12 +230,15 @@ m_rtBuilder.setup(m_device, m_alloc, m_graphicsQueueIndex);
|
||||||
````
|
````
|
||||||
|
|
||||||
!!! Note Memory Management
|
!!! Note Memory Management
|
||||||
The raytrace helper uses `"nvvk/resourceallocator_vk.hpp"` to avoid having to deal with vulkan memory management.
|
The raytrace helper uses [`"nvvk/resourceallocator_vk.hpp"`](https://github.com/nvpro-samples/nvpro_core/blob/master/nvvk/resourceallocator_vk.hpp)
|
||||||
|
to avoid having to deal with vulkan memory management.
|
||||||
This provides the `nvvk::AccelKHR` type, which consists of a `VkAccelerationStructureKHR` paired
|
This provides the `nvvk::AccelKHR` type, which consists of a `VkAccelerationStructureKHR` paired
|
||||||
with info needed by the allocator to manage the buffer memory backing it. `"nvvk/resourceallocator_vk.hpp"` requires a macro to
|
with info needed by the allocator to manage the buffer memory backing it. The resource allocation can use different
|
||||||
be defined before inclusion to select its memory allocation strategy. In this tutorial, we defined `NVVK_ALLOC_DEDICATED`.
|
memory allocation strategy (memory allocator). In this tutorial, we are using our own version
|
||||||
This selects the simple one-`VkDeviceMemory`-per-object strategy, which is easier to understand for
|
[DMA](https://github.com/nvpro-samples/nvpro_core/blob/master/nvvk/memallocator_dma_vk.hpp).
|
||||||
teaching purposes but not practical for production use.
|
Other memory allocators can be selected, such as the [Vulkan Memory Allocator (VMA)](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
|
||||||
|
and a dedicated memory allocator, which is the simple one-`VkDeviceMemory`-per-object strategy,
|
||||||
|
which is easiest to understand for teaching purposes but not practical for production use.
|
||||||
|
|
||||||
## Bottom-Level Acceleration Structure
|
## Bottom-Level Acceleration Structure
|
||||||
|
|
||||||
|
|
@ -264,6 +253,12 @@ class:
|
||||||
auto objectToVkGeometryKHR(const ObjModel& model);
|
auto objectToVkGeometryKHR(const ObjModel& model);
|
||||||
````
|
````
|
||||||
|
|
||||||
|
!!! Note Note
|
||||||
|
The `objectToVkGeometryKHR()` function is returning `nvvk::RaytracingBuilderKHR::BlasInput` but we are using the C++ `auto` as it is
|
||||||
|
automatically deducted by the compiler.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Its implementation will fill three structures that will eventually be passed to the AS builder (`vkCmdBuildAccelerationStructuresKHR`).
|
Its implementation will fill three structures that will eventually be passed to the AS builder (`vkCmdBuildAccelerationStructuresKHR`).
|
||||||
|
|
||||||
* `VkAccelerationStructureGeometryTrianglesDataKHR`: device pointer to the buffers holding triangle vertex/index data,
|
* `VkAccelerationStructureGeometryTrianglesDataKHR`: device pointer to the buffers holding triangle vertex/index data,
|
||||||
|
|
@ -275,10 +270,6 @@ Its implementation will fill three structures that will eventually be passed to
|
||||||
|
|
||||||
* `VkAccelerationStructureBuildRangeInfoKHR`: the indices within the vertex arrays to source input geometry for the BLAS.
|
* `VkAccelerationStructureBuildRangeInfoKHR`: the indices within the vertex arrays to source input geometry for the BLAS.
|
||||||
|
|
||||||
!!! Tip C++ types
|
|
||||||
Although the code uses C++ types, in the above C types names are used to ease searching for them online.
|
|
||||||
Generally, replace `vk::` with `Vk` to convert C++ type names to C names (functions names are less uniform).
|
|
||||||
|
|
||||||
!!! Tip VkAccelerationStructureGeometryKHR / VkAccelerationStructureBuildRangeInfoKHR split
|
!!! Tip VkAccelerationStructureGeometryKHR / VkAccelerationStructureBuildRangeInfoKHR split
|
||||||
A potential point of confusion is how `VkAccelerationStructureGeometryKHR` and `VkAccelerationStructureBuildRangeInfoKHR`
|
A potential point of confusion is how `VkAccelerationStructureGeometryKHR` and `VkAccelerationStructureBuildRangeInfoKHR`
|
||||||
are ultimately passed as separate arguments to the AS builder but work in concert to determine the actual memory to source
|
are ultimately passed as separate arguments to the AS builder but work in concert to determine the actual memory to source
|
||||||
|
|
@ -302,35 +293,38 @@ potential optimization. (More specifically, this disables calls to the anyhit sh
|
||||||
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
||||||
{
|
{
|
||||||
// BLAS builder requires raw device addresses.
|
// BLAS builder requires raw device addresses.
|
||||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
info.buffer = model.vertexBuffer.buffer;
|
||||||
|
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
info.buffer = model.indexBuffer.buffer;
|
||||||
|
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
|
||||||
uint32_t maxPrimitiveCount = model.nbIndices / 3;
|
uint32_t maxPrimitiveCount = model.nbIndices / 3;
|
||||||
|
|
||||||
// Describe buffer as array of VertexObj.
|
// Describe buffer as array of VertexObj.
|
||||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data.
|
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
|
||||||
triangles.setVertexData(vertexAddress);
|
triangles.vertexData.deviceAddress = vertexAddress;
|
||||||
triangles.setVertexStride(sizeof(VertexObj));
|
triangles.vertexStride = sizeof(VertexObj);
|
||||||
// Describe index data (32-bit unsigned int)
|
// Describe index data (32-bit unsigned int)
|
||||||
triangles.setIndexType(vk::IndexType::eUint32);
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
triangles.setIndexData(indexAddress);
|
triangles.indexData.deviceAddress = indexAddress;
|
||||||
// Indicate identity transform by setting transformData to null device pointer.
|
// Indicate identity transform by setting transformData to null device pointer.
|
||||||
triangles.setTransformData({});
|
//triangles.transformData = {};
|
||||||
triangles.setMaxVertex(model.nbVertices);
|
triangles.maxVertex = model.nbVertices;
|
||||||
|
|
||||||
// Identify the above data as containing opaque triangles.
|
// Identify the above data as containing opaque triangles.
|
||||||
vk::AccelerationStructureGeometryKHR asGeom;
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||||
asGeom.geometry.setTriangles(triangles);
|
asGeom.geometry.triangles = triangles;
|
||||||
|
|
||||||
// The entire array will be used to build the BLAS.
|
// The entire array will be used to build the BLAS.
|
||||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||||
offset.setFirstVertex(0);
|
offset.firstVertex = 0;
|
||||||
offset.setPrimitiveCount(maxPrimitiveCount);
|
offset.primitiveCount = maxPrimitiveCount;
|
||||||
offset.setPrimitiveOffset(0);
|
offset.primitiveOffset = 0;
|
||||||
offset.setTransformOffset(0);
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
// Our blas is made from only one geometry, but could be made of many geometries
|
// Our blas is made from only one geometry, but could be made of many geometries
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||||
|
|
@ -377,7 +371,7 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
// We could add more geometry in each BLAS, but we add only one for now
|
// We could add more geometry in each BLAS, but we add only one for now
|
||||||
allBlas.emplace_back(blas);
|
allBlas.emplace_back(blas);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -467,7 +461,7 @@ so we keep track of the maximum scratch memory ever needed. Later, we'll allocat
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
Behind the scenes, `m_alloc->createAllocation` is creating a buffer of the size indicated by the acceleration structure
|
Behind the scenes, `m_alloc->createAcceleration` is creating a buffer of the size indicated by the acceleration structure
|
||||||
size query, giving it the `VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR` and `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT`
|
size query, giving it the `VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR` and `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT`
|
||||||
usage bits (the latter is needed as the TLAS builder will need the raw address of the BLASes), and binding the acceleration structure
|
usage bits (the latter is needed as the TLAS builder will need the raw address of the BLASes), and binding the acceleration structure
|
||||||
to its allocated memory by filling in the `buffer` field of `VkAccelerationStructureCreateInfoKHR`. Unlike buffers and images,
|
to its allocated memory by filling in the `buffer` field of `VkAccelerationStructureCreateInfoKHR`. Unlike buffers and images,
|
||||||
|
|
@ -674,7 +668,7 @@ invoked upon hitting the object (`VkAccelerationStructureInstanceKHR::instanceSh
|
||||||
This index and the notion of hit group are tied to the definition of the ray tracing pipeline and the Shader Binding
|
This index and the notion of hit group are tied to the definition of the ray tracing pipeline and the Shader Binding
|
||||||
Table, described later in this tutorial and used to select determine which shaders are invoked at runtime. For now
|
Table, described later in this tutorial and used to select determine which shaders are invoked at runtime. For now
|
||||||
it suffices to say that we will use only one hit group for the whole scene, and hence the hit group index is always 0.
|
it suffices to say that we will use only one hit group for the whole scene, and hence the hit group index is always 0.
|
||||||
Finally, the instance may indicate culling preferences, such as backface culling, using its `vk::GeometryInstanceFlagsKHR
|
Finally, the instance may indicate culling preferences, such as backface culling, using its `VkGeometryInstanceFlagsKHR
|
||||||
flags` member. In our example we decide to disable culling altogether
|
flags` member. In our example we decide to disable culling altogether
|
||||||
for simplicity and independence on the winding of the input models.
|
for simplicity and independence on the winding of the input models.
|
||||||
|
|
||||||
|
|
@ -696,7 +690,7 @@ void HelloVulkan::createTopLevelAS()
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
tlas.emplace_back(rayInst);
|
tlas.emplace_back(rayInst);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -926,9 +920,9 @@ In the header `hello_vulkan.h`, we declare the objects related to this additiona
|
||||||
void createRtDescriptorSet();
|
void createRtDescriptorSet();
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
````
|
````
|
||||||
|
|
||||||
The acceleration structure will be accessible by the Ray Generation shader, as we want to call `TraceRayEXT()` from this
|
The acceleration structure will be accessible by the Ray Generation shader, as we want to call `TraceRayEXT()` from this
|
||||||
|
|
@ -942,30 +936,31 @@ RayGen shader.
|
||||||
//
|
//
|
||||||
void HelloVulkan::createRtDescriptorSet()
|
void HelloVulkan::createRtDescriptorSet()
|
||||||
{
|
{
|
||||||
using vkDT = vk::DescriptorType;
|
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // TLAS
|
||||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1,
|
||||||
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
|
||||||
m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1,
|
|
||||||
vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS
|
|
||||||
m_rtDescSetLayoutBind.addBinding(
|
|
||||||
vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image
|
|
||||||
|
|
||||||
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
||||||
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
||||||
m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0];
|
|
||||||
|
|
||||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo;
|
allocateInfo.descriptorPool = m_rtDescPool;
|
||||||
descASInfo.setAccelerationStructureCount(1);
|
allocateInfo.descriptorSetCount = 1;
|
||||||
descASInfo.setPAccelerationStructures(&tlas);
|
allocateInfo.pSetLayouts = &m_rtDescSetLayout;
|
||||||
vk::DescriptorImageInfo imageInfo{
|
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
|
||||||
{}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral};
|
|
||||||
|
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
|
||||||
|
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||||
|
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||||
|
descASInfo.accelerationStructureCount = 1;
|
||||||
|
descASInfo.pAccelerationStructures = &tlas;
|
||||||
|
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
|
||||||
|
|
||||||
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo));
|
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, 1, &imageInfo));
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -979,42 +974,39 @@ descriptor set as they semantically fit the Scene descriptor set.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Camera matrices (binding = 0)
|
// Camera matrices (binding = 0)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
|
||||||
vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR));
|
|
||||||
// Materials (binding = 1)
|
// Materials (binding = 1)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||||
vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
// Scene description (binding = 2)
|
// Scene description (binding = 2)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||||
vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
// Textures (binding = 3)
|
// Textures (binding = 3)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
|
||||||
vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
// Materials (binding = 4)
|
// Materials (binding = 4)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||||
vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
// Storing vertices (binding = 5)
|
// Storing vertices (binding = 5)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
|
|
||||||
// Storing indices (binding = 6)
|
// Storing indices (binding = 6)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
|
|
||||||
````
|
````
|
||||||
|
|
||||||
We set the actual contents of the descriptor set by adding those buffers in `updateDescriptorSet()`:
|
We set the actual contents of the descriptor set by adding those buffers in `updateDescriptorSet()`:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// All material buffers, 1 buffer per OBJ
|
// All material buffers, 1 buffer per OBJ
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiVert;
|
std::vector<VkDescriptorBufferInfo> dbiVert;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiIdx;
|
std::vector<VkDescriptorBufferInfo> dbiIdx;
|
||||||
for(size_t i = 0; i < m_objModel.size(); ++i)
|
for(auto& m : m_objModel)
|
||||||
{
|
{
|
||||||
dbiMat.push_back({m_objModel[i].matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiMatIdx.push_back({m_objModel[i].matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiVert.push_back({m_objModel[i].vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiIdx.push_back({m_objModel[i].indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
}
|
}
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||||
|
|
@ -1032,14 +1024,11 @@ and `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` bits.
|
||||||
We update the usage of the buffers in `loadModel`:
|
We update the usage of the buffers in `loadModel`:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
model.vertexBuffer =
|
VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
|
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||||
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
|
||||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
|
||||||
model.indexBuffer =
|
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_indices,
|
|
||||||
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
|
||||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
|
||||||
````
|
````
|
||||||
|
|
||||||
!!! Note: Array of Buffers
|
!!! Note: Array of Buffers
|
||||||
|
|
@ -1067,16 +1056,18 @@ The implementation is straightforward, just update the output image reference:
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateRtDescriptorSet()
|
void HelloVulkan::updateRtDescriptorSet()
|
||||||
{
|
{
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
|
|
||||||
// (1) Output buffer
|
// (1) Output buffer
|
||||||
vk::DescriptorImageInfo imageInfo{
|
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
|
||||||
{}, m_offscreenColor.descriptor.imageView, vk::ImageLayout::eGeneral};
|
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo);
|
||||||
vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo};
|
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
|
||||||
m_device.updateDescriptorSets(wds, nullptr);
|
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
!!! Note Note
|
||||||
|
We are using [`nvvk::DescriptorSetBindings`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkdescriptorsetbindings)
|
||||||
|
to help creating the descriptor sets. This removes a lot of duplacted code and potential errors.
|
||||||
|
|
||||||
|
|
||||||
We can then add the update call to the `onResize()` method to link it to the resizing event:
|
We can then add the update call to the `onResize()` method to link it to the resizing event:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
|
|
@ -1087,8 +1078,8 @@ The resources created in this section need to be destroyed when closing the appl
|
||||||
`destroyResources`:
|
`destroyResources`:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
m_device.destroy(m_rtDescPool);
|
vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr);
|
||||||
m_device.destroy(m_rtDescSetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr);
|
||||||
````
|
````
|
||||||
|
|
||||||
## main
|
## main
|
||||||
|
|
@ -1212,9 +1203,10 @@ pipeline:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
|
VkPipeline m_rtPipeline;
|
||||||
````
|
````
|
||||||
|
|
||||||
The pipeline will also use push constants to store global uniform values, namely the background color and
|
The pipeline will also use push constants to store global uniform values, namely the background color and
|
||||||
|
|
@ -1225,8 +1217,8 @@ the light source information:
|
||||||
{
|
{
|
||||||
nvmath::vec4f clearColor;
|
nvmath::vec4f clearColor;
|
||||||
nvmath::vec3f lightPosition;
|
nvmath::vec3f lightPosition;
|
||||||
float lightIntensity;
|
float lightIntensity{100.0f};
|
||||||
int lightType;
|
int lightType{0};
|
||||||
} m_rtPushConstants;
|
} m_rtPushConstants;
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -1235,13 +1227,10 @@ followed by the closest hit shader. Note that this order is arbitrary, as the ex
|
||||||
the pipeline in any order. The "stages" terminology is a holdover from the rasterization pipeline; in raytracing,
|
the pipeline in any order. The "stages" terminology is a holdover from the rasterization pipeline; in raytracing,
|
||||||
we orchestrate the order that shaders are invoked and the data flow between them ourselves.
|
we orchestrate the order that shaders are invoked and the data flow between them ourselves.
|
||||||
|
|
||||||
All stages are stored in an `std::vector` of `vk::PipelineShaderStageCreateInfo` objects. As mentioned, at this step,
|
All stages are stored in an `std::vector` of `VkPipelineShaderStageCreateInfo` objects. As mentioned, at this step,
|
||||||
indices within this vector will be used as unique identifiers for the shaders. These identifiers are stored in the
|
indices within this vector will be used as unique identifiers for the shaders. The 3 stages will be using the
|
||||||
`RayTracingShaderGroupCreateInfoKHR` structure. This structure first specifies a `type`, which represents the kind of
|
same entry point "main". Then we create a `vkCreateShaderModule` from the pre-compiled shader and defined which
|
||||||
shader group represented in the structure. Ray generation and miss shaders are called 'general' shaders. In this case the
|
stage it correspond to.
|
||||||
type is `eGeneral`, and only the `generalShader` member of the structure is filled. The other ones are set to
|
|
||||||
`VK_SHADER_UNUSED_KHR`. This is also the case for the callable shaders, not used in this tutorial. In our layout the ray
|
|
||||||
generation comes first (0), followed by the miss shader (1).
|
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -1249,78 +1238,105 @@ generation comes first (0), followed by the miss shader (1).
|
||||||
//
|
//
|
||||||
void HelloVulkan::createRtPipeline()
|
void HelloVulkan::createRtPipeline()
|
||||||
{
|
{
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
enum StageIndices
|
||||||
|
{
|
||||||
|
eRaygen,
|
||||||
|
eMiss,
|
||||||
|
eClosestHit,
|
||||||
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
|
||||||
vk::ShaderModule raygenSM =
|
// All stages
|
||||||
nvvk::createShaderModule(m_device, //
|
std::array<VkPipelineShaderStageCreateInfo, eShaderGroupCount> stages{};
|
||||||
nvh::loadFile("shaders/raytrace.rgen.spv", true, paths, true));
|
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
||||||
vk::ShaderModule missSM =
|
stage.pName = "main"; // All the same entry point
|
||||||
nvvk::createShaderModule(m_device, //
|
// Raygen
|
||||||
nvh::loadFile("shaders/raytrace.rmiss.spv", true, paths, true));
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||||
|
stages[eRaygen] = stage;
|
||||||
|
// Miss
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||||
|
stages[eMiss] = stage;
|
||||||
|
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
|
||||||
|
stage.module =
|
||||||
|
nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||||
|
stages[eMiss2] = stage;
|
||||||
|
// Hit Group - Closest Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHit] = stage;
|
||||||
|
````
|
||||||
|
|
||||||
std::vector<vk::PipelineShaderStageCreateInfo> stages;
|
These identifiers are stored in the
|
||||||
|
`VkRayTracingShaderGroupCreateInfoKHR` structure. This structure first specifies a `type`, which represents the kind of
|
||||||
|
shader group represented in the structure. Ray generation and miss shaders are called 'general' shaders. In this case the
|
||||||
|
type is `VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR`, and only the `generalShader` member of the structure is filled. The other ones are set to
|
||||||
|
`VK_SHADER_UNUSED_KHR`. This is also the case for the callable shaders, not used in this tutorial. In our layout the ray
|
||||||
|
generation comes first (0), followed by the miss shader (1).
|
||||||
|
|
||||||
|
````C
|
||||||
|
// Shader groups
|
||||||
|
VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
|
||||||
|
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
|
||||||
// Raygen
|
// Raygen
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.generalShader = eRaygen;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
m_rtShaderGroups.push_back(group);
|
||||||
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(rg);
|
|
||||||
// Miss
|
// Miss
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.generalShader = eMiss;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
m_rtShaderGroups.push_back(group);
|
||||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(mg);
|
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
As detailed before, intersections are managed by 3 kinds of shaders: the intersection shader computes the ray-geometry
|
As detailed before, intersections are managed by 3 kinds of shaders: the intersection shader computes the ray-geometry
|
||||||
intersections, the any-hit shader is run for every potential intersection, and the closest hit shader is applied to the
|
intersections, the any-hit shader is run for every potential intersection, and the closest hit shader is applied to the
|
||||||
closest hit point along the ray. Those 3 shaders are bound into a hit group. In our case the geometry is made of
|
closest hit point along the ray. Those 3 shaders are bound into a hit group. In our case the geometry is made of
|
||||||
triangles, so the `type` of the `RayTracingShaderGroupCreateInfoKHR` is `eTrianglesHitGroup`. Raytrace hardware therefore takes
|
triangles, so the `type` of the `VkRayTracingShaderGroupCreateInfoKHR` is `VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR`.
|
||||||
the place of the intersection shader, so, we set the `intersectionShader` member to `VK_SHADER_UNUSED_KHR`. We do not use an any-hit
|
We first reset the `generalShader` to `VK_SHADER_UNUSED_KHR`.
|
||||||
|
Raytrace hardware therefore takes
|
||||||
|
the place of the intersection shader, so, we leave the `intersectionShader` member to `VK_SHADER_UNUSED_KHR`. We do not use an any-hit
|
||||||
shader, letting the system use a built-in pass-through shader. Therefore, we also leave the `anyHitShader` to
|
shader, letting the system use a built-in pass-through shader. Therefore, we also leave the `anyHitShader` to
|
||||||
`VK_SHADER_UNUSED_KHR`. The only shader we define is then the closest hit shader, by setting the `closestHitShader`
|
`VK_SHADER_UNUSED_KHR`. The only shader we define is then the closest hit shader, by setting the `closestHitShader`
|
||||||
member to the index `2` (`stages.size()-1`), since the `stages` vector already contains the ray generation and miss
|
member to the index `2` (`chit`), since the `stages` vector already contains the ray generation and miss
|
||||||
shaders.
|
shaders.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Hit Group - Closest Hit + AnyHit
|
// closest hit shader
|
||||||
vk::ShaderModule chitSM =
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
nvvk::createShaderModule(m_device, //
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
|
group.closestHitShader = eClosestHit;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(hg);
|
|
||||||
````
|
````
|
||||||
|
|
||||||
Note that if the geometry were not triangles, we would have set the `type` to `eProceduralHitGroup`, and would have to
|
Note that if the geometry were not triangles, we would have set the `type` to `VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR`, and would have to
|
||||||
define an intersection shader.
|
define an intersection shader.
|
||||||
|
|
||||||
After creating the shader groups, we need to setup the pipeline layout that will describe how the pipeline
|
After creating the shader groups, we need to setup the pipeline layout that will describe how the pipeline
|
||||||
will access external data:
|
will access external data:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||||
````
|
````
|
||||||
|
|
||||||
We first add the push constant range to allow the ray tracing shaders to access the global uniform values:
|
We first add the push constant range to allow the ray tracing shaders to access the global uniform values:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Push constant: we want to be able to update constants used by the shaders
|
// Push constant: we want to be able to update constants used by the shaders
|
||||||
vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR
|
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
|
||||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
|
||||||
| vk::ShaderStageFlagBits::eMissKHR,
|
|
||||||
0, sizeof(RtPushConstant)};
|
0, sizeof(RtPushConstant)};
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant);
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
|
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
||||||
|
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant;
|
||||||
````
|
````
|
||||||
|
|
||||||
As described earlier, the pipeline uses two descriptor sets: `set=0` is specific to the ray tracing pipeline (TLAS and
|
As described earlier, the pipeline uses two descriptor sets: `set=0` is specific to the ray tracing pipeline (TLAS and
|
||||||
|
|
@ -1328,15 +1344,15 @@ output image), and `set=1` is shared with the rasterization (scene data):
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
||||||
std::vector<vk::DescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout};
|
std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout};
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(static_cast<uint32_t>(rtDescSetLayouts.size()));
|
pipelineLayoutCreateInfo.setLayoutCount = static_cast<uint32_t>(rtDescSetLayouts.size());
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data());
|
pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data();
|
||||||
````
|
````
|
||||||
|
|
||||||
The pipeline layout information is now complete, allowing us to create the layout itself.
|
The pipeline layout information is now complete, allowing us to create the layout itself.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
|
||||||
````
|
````
|
||||||
|
|
||||||
The creation of the ray tracing pipeline is different from the classical graphics pipeline. In the graphics pipeline we
|
The creation of the ray tracing pipeline is different from the classical graphics pipeline. In the graphics pipeline we
|
||||||
|
|
@ -1347,18 +1363,19 @@ We first provide all the stages that will be used:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
||||||
vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo;
|
VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
|
||||||
rayPipelineInfo.setStageCount(static_cast<uint32_t>(stages.size())); // Stages are shaders
|
rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size()); // Stages are shaders
|
||||||
rayPipelineInfo.setPStages(stages.data());
|
rayPipelineInfo.pStages = stages.data();
|
||||||
````
|
````
|
||||||
|
|
||||||
Then, we indicate how the shaders can be assembled into groups. A ray generation or miss shader is a group by
|
Then, we indicate how the shaders can be assembled into groups. A ray generation or miss shader is a group by
|
||||||
itself, but hit groups can comprise up to 3 shaders (intersection, any hit, closest hit).
|
itself, but hit groups can comprise up to 3 shaders (intersection, any hit, closest hit).
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
rayPipelineInfo.setGroupCount(
|
// In this case, m_rtShaderGroups.size() == 3: we have one raygen group,
|
||||||
static_cast<uint32_t>(m_rtShaderGroups.size()));
|
// one miss shader group, and one hit group.
|
||||||
rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
|
rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
|
||||||
|
rayPipelineInfo.pGroups = m_rtShaderGroups.data();
|
||||||
````
|
````
|
||||||
|
|
||||||
The ray generation and closest hit shaders can trace rays, making the ray tracing a potentially recursive process. To
|
The ray generation and closest hit shaders can trace rays, making the ray tracing a potentially recursive process. To
|
||||||
|
|
@ -1368,18 +1385,17 @@ recursion at all (i.e. a hit shader calling `TraceRayEXT()`). Note that it is pr
|
||||||
as low as possible, replacing it by a loop formulation instead.
|
as low as possible, replacing it by a loop formulation instead.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
rayPipelineInfo.setMaxPipelineRayRecursionDepth(1); // Ray depth
|
rayPipelineInfo.maxPipelineRayRecursionDepth = 1; // Ray depth
|
||||||
rayPipelineInfo.setLayout(m_rtPipelineLayout);
|
rayPipelineInfo.layout = m_rtPipelineLayout;
|
||||||
m_rtPipeline = static_cast<const vk::Pipeline&>(
|
|
||||||
m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo));
|
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
|
||||||
````
|
````
|
||||||
|
|
||||||
Once the pipeline has been created we discard the shader modules:
|
Once the pipeline has been created we discard the shader modules:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
m_device.destroy(raygenSM);
|
for(auto& s : stages)
|
||||||
m_device.destroy(missSM);
|
vkDestroyShaderModule(m_device, s.module, nullptr);
|
||||||
m_device.destroy(chitSM);
|
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -1387,8 +1403,8 @@ The pipeline layout and the pipeline itself also have to be cleaned up upon clos
|
||||||
`destroyResources`:
|
`destroyResources`:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
m_device.destroy(m_rtPipeline);
|
vkDestroyPipeline(m_device, m_rtPipeline, nullptr);
|
||||||
m_device.destroy(m_rtPipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr);
|
||||||
````
|
````
|
||||||
|
|
||||||
## main
|
## main
|
||||||
|
|
@ -1450,6 +1466,7 @@ In this function, we start by computing the size of the binding table from the n
|
||||||
aligned handle size so that we can allocate the SBT buffer.
|
aligned handle size so that we can allocate the SBT buffer.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
// The Shader Binding Table (SBT)
|
// The Shader Binding Table (SBT)
|
||||||
// - getting all shader handles and write them in a SBT buffer
|
// - getting all shader handles and write them in a SBT buffer
|
||||||
// - Besides exception, this could be always done like this
|
// - Besides exception, this could be always done like this
|
||||||
|
|
@ -1457,12 +1474,10 @@ aligned handle size so that we can allocate the SBT buffer.
|
||||||
//
|
//
|
||||||
void HelloVulkan::createRtShaderBindingTable()
|
void HelloVulkan::createRtShaderBindingTable()
|
||||||
{
|
{
|
||||||
auto groupCount =
|
auto groupCount = static_cast<uint32_t>(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit
|
||||||
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit
|
|
||||||
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
|
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
|
||||||
// Compute the actual size needed per SBT entry (round-up to alignment needed).
|
// Compute the actual size needed per SBT entry (round-up to alignment needed).
|
||||||
uint32_t groupSizeAligned =
|
uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
|
||||||
nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
|
|
||||||
// Bytes needed for the SBT.
|
// Bytes needed for the SBT.
|
||||||
uint32_t sbtSize = groupCount * groupSizeAligned;
|
uint32_t sbtSize = groupCount * groupSizeAligned;
|
||||||
````
|
````
|
||||||
|
|
@ -1476,16 +1491,15 @@ of SBT buffer, therefore the buffer need also the `VK_BUFFER_USAGE_SHADER_DEVICE
|
||||||
// Fetch all the shader handles used in the pipeline. This is opaque data,
|
// Fetch all the shader handles used in the pipeline. This is opaque data,
|
||||||
// so we store it in a vector of bytes.
|
// so we store it in a vector of bytes.
|
||||||
std::vector<uint8_t> shaderHandleStorage(sbtSize);
|
std::vector<uint8_t> shaderHandleStorage(sbtSize);
|
||||||
auto result = m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
|
auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data());
|
||||||
shaderHandleStorage.data());
|
|
||||||
assert(result == vk::Result::eSuccess);
|
assert(result == VK_SUCCESS);
|
||||||
|
|
||||||
// Allocate a buffer for storing the SBT. Give it a debug name for NSight.
|
// Allocate a buffer for storing the SBT. Give it a debug name for NSight.
|
||||||
m_rtSBTBuffer = m_alloc.createBuffer(
|
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize,
|
||||||
sbtSize,
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||||
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eShaderDeviceAddress
|
| VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
|
||||||
| vk::BufferUsageFlagBits::eShaderBindingTableKHR,
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
|
|
||||||
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
|
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
|
||||||
|
|
||||||
// Map the SBT buffer and write in the handles.
|
// Map the SBT buffer and write in the handles.
|
||||||
|
|
@ -1499,6 +1513,7 @@ of SBT buffer, therefore the buffer need also the `VK_BUFFER_USAGE_SHADER_DEVICE
|
||||||
m_alloc.unmap(m_rtSBTBuffer);
|
m_alloc.unmap(m_rtSBTBuffer);
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
m_alloc.finalizeAndReleaseStaging();
|
||||||
}
|
}
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
As with other resources, we destroy the SBT in `destroyResources`:
|
As with other resources, we destroy the SBT in `destroyResources`:
|
||||||
|
|
@ -1528,6 +1543,13 @@ As with other resources, we destroy the SBT in `destroyResources`:
|
||||||
array used to build the pipeline. In general though, the order of the SBT need not match
|
array used to build the pipeline. In general though, the order of the SBT need not match
|
||||||
the pipeline shader stage order.
|
the pipeline shader stage order.
|
||||||
|
|
||||||
|
!!! Tip SBTWrapper
|
||||||
|
To avoid potential issues in the contruction of the SBT, we have a wrapper that uses the information
|
||||||
|
sent to the creation of the ray tracing pipeline to allocate the SBT. In further tutorials
|
||||||
|
we might use the [`nnvk::SBTWrapper`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#sbtwrapper_vkhpp)
|
||||||
|
instead of manually describing all steps.
|
||||||
|
|
||||||
|
|
||||||
## main
|
## main
|
||||||
|
|
||||||
In the `main` function, we now add the construction of the Shader Binding Table:
|
In the `main` function, we now add the construction of the Shader Binding Table:
|
||||||
|
|
@ -1541,16 +1563,20 @@ In the `main` function, we now add the construction of the Shader Binding Table:
|
||||||
Let's create a function that will record commands to call the ray trace shaders. First, add the declaration to the header
|
Let's create a function that will record commands to call the ray trace shaders. First, add the declaration to the header
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
````
|
````
|
||||||
|
|
||||||
We first bind the pipeline and its layout, and set the push constants that will be available throughout the pipeline:
|
We first bind the pipeline and its layout, and set the push constants that will be available throughout the pipeline:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
|
m_alloc.unmap(m_rtSBTBuffer);
|
||||||
|
m_alloc.finalizeAndReleaseStaging();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Ray Tracing the scene
|
// Ray Tracing the scene
|
||||||
//
|
//
|
||||||
void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
||||||
{
|
{
|
||||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
m_debug.beginLabel(cmdBuf, "Ray trace");
|
||||||
// Initializing push constant values
|
// Initializing push constant values
|
||||||
|
|
@ -1559,14 +1585,14 @@ void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f&
|
||||||
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity;
|
m_rtPushConstants.lightIntensity = m_pushConstant.lightIntensity;
|
||||||
m_rtPushConstants.lightType = m_pushConstant.lightType;
|
m_rtPushConstants.lightType = m_pushConstant.lightType;
|
||||||
|
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline);
|
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0,
|
std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet};
|
||||||
{m_rtDescSet, m_descSet}, {});
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
|
||||||
cmdBuf.pushConstants<RtPushConstant>(m_rtPipelineLayout,
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0,
|
||||||
vk::ShaderStageFlagBits::eRaygenKHR
|
(uint32_t)descSets.size(), descSets.data(), 0, nullptr);
|
||||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
||||||
| vk::ShaderStageFlagBits::eMissKHR,
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
|
||||||
0, m_rtPushConstants);
|
0, sizeof(RtPushConstant), &m_rtPushConstants);
|
||||||
````
|
````
|
||||||
|
|
||||||
Since the structure of the Shader Binding Table is up to the developer, we need to indicate the ray tracing pipeline how
|
Since the structure of the Shader Binding Table is up to the developer, we need to indicate the ray tracing pipeline how
|
||||||
|
|
@ -1585,14 +1611,15 @@ The location for each array of the SBT is passed as a `VkStridedDeviceAddressReg
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Size of a program identifier
|
// Size of a program identifier
|
||||||
uint32_t groupSize =
|
uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
|
||||||
nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment);
|
|
||||||
uint32_t groupStride = groupSize;
|
uint32_t groupStride = groupSize;
|
||||||
vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer});
|
|
||||||
|
|
||||||
using Stride = vk::StridedDeviceAddressRegionKHR;
|
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||||
std::array<Stride, 4> strideAddresses{
|
info.buffer = m_rtSBTBuffer.buffer;
|
||||||
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
|
VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
|
||||||
|
using Stride = VkStridedDeviceAddressRegionKHR;
|
||||||
|
std::array<Stride, 4> strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
|
||||||
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 1}, // miss
|
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 1}, // miss
|
||||||
Stride{sbtAddress + 2u * groupSize, groupStride, groupSize * 1}, // hit
|
Stride{sbtAddress + 2u * groupSize, groupStride, groupSize * 1}, // hit
|
||||||
Stride{0u, 0u, 0u}}; // callable
|
Stride{0u, 0u, 0u}}; // callable
|
||||||
|
|
@ -1610,9 +1637,8 @@ three parameters are equivalent to the grid size of a compute launch, and repres
|
||||||
we want to trace one ray per pixel, the grid size has the width and height of the output image, and a depth of 1.
|
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
|
```` C
|
||||||
cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
|
vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3],
|
||||||
&strideAddresses[3], //
|
m_size.width, m_size.height, 1);
|
||||||
m_size.width, m_size.height, 1); //
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -1622,6 +1648,13 @@ we want to trace one ray per pixel, the grid size has the width and height of th
|
||||||
If you built a pipeline with multiple raygen shaders, the raygen shader can be selected by changing the
|
If you built a pipeline with multiple raygen shaders, the raygen shader can be selected by changing the
|
||||||
device address of the first `VkStridedDeviceAddressRegionKHR` structure (change the `0u` in `sbtAddress + 0u * groupSize`).
|
device address of the first `VkStridedDeviceAddressRegionKHR` structure (change the `0u` in `sbtAddress + 0u * groupSize`).
|
||||||
|
|
||||||
|
!!! TIP SBTWrapper
|
||||||
|
When using the SBTWrapper, the above could be replaced by
|
||||||
|
```
|
||||||
|
auto& regions = m_stbWrapper.getRegions();
|
||||||
|
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1);
|
||||||
|
```
|
||||||
|
|
||||||
# Let's Ray Trace
|
# Let's Ray Trace
|
||||||
|
|
||||||
Now we have everything set up to be able to trace rays: the acceleration structure, the descriptor sets, the ray tracing
|
Now we have everything set up to be able to trace rays: the acceleration structure, the descriptor sets, the ray tracing
|
||||||
|
|
@ -1650,13 +1683,13 @@ render modes, we replace that block by
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
{
|
{
|
||||||
helloVk.raytrace(cmdBuff, clearColor);
|
helloVk.raytrace(cmdBuf, clearColor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuff.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuff);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuff.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -1701,8 +1734,7 @@ hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
||||||
|
|
||||||
We also have to indicate that the UBO will be used in the raytracing shaders.
|
We also have to indicate that the UBO will be used in the raytracing shaders.
|
||||||
```` C
|
```` C
|
||||||
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader
|
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||||
| vk::PipelineStageFlagBits::eRayTracingShaderKHR;
|
|
||||||
````
|
````
|
||||||
|
|
||||||
## Ray generation (raytrace.rgen)
|
## Ray generation (raytrace.rgen)
|
||||||
|
|
@ -2126,21 +2158,33 @@ the GLSL file.
|
||||||
In the body of `createRtPipeline`, we need to define the new miss shader right after the previous miss shader:
|
In the body of `createRtPipeline`, we need to define the new miss shader right after the previous miss shader:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// The second miss shader is invoked when a shadow ray misses the geometry. It
|
enum StageIndices
|
||||||
// simply indicates that no occlusion has been found
|
{
|
||||||
vk::ShaderModule shadowmissSM =
|
eRaygen,
|
||||||
nvvk::createShaderModule(m_device,
|
eMiss,
|
||||||
nvh::loadFile("shaders/raytraceShadow.rmiss.spv", true, paths, true));
|
eMiss2,
|
||||||
|
eClosestHit,
|
||||||
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
````
|
||||||
|
|
||||||
|
And create the stage
|
||||||
|
|
||||||
|
```` C
|
||||||
|
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
|
||||||
|
stage.module =
|
||||||
|
nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||||
|
stages[eMiss2] = stage;
|
||||||
````
|
````
|
||||||
|
|
||||||
After pushing the miss shader `missSM`, we also push the miss shader for the shadow rays:
|
After pushing the miss shader `missSM`, we also push the miss shader for the shadow rays:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Shadow Miss
|
// Shadow Miss
|
||||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
|
group.generalShader = eMiss2;
|
||||||
m_rtShaderGroups.push_back(mg);
|
m_rtShaderGroups.push_back(group);
|
||||||
````
|
````
|
||||||
|
|
||||||
The pipeline now has to allow shooting rays from the closest hit program, which requires increasing the recursion level to 2:
|
The pipeline now has to allow shooting rays from the closest hit program, which requires increasing the recursion level to 2:
|
||||||
|
|
@ -2150,19 +2194,14 @@ The pipeline now has to allow shooting rays from the closest hit program, which
|
||||||
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
|
// 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
|
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
|
||||||
// in the ray generation to avoid deep recursion.
|
// in the ray generation to avoid deep recursion.
|
||||||
rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
|
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
|
||||||
````
|
````
|
||||||
|
|
||||||
At the end of the method, we destroy the shader module for the shadow miss shader:
|
|
||||||
|
|
||||||
```` C
|
|
||||||
m_device.destroy(shadowmissSM);
|
|
||||||
````
|
|
||||||
|
|
||||||
!!! WARNING Recursion Limit
|
!!! WARNING Recursion Limit
|
||||||
The spec does not guarantee a recursion check at runtime. If you exceed either
|
The spec does not guarantee a recursion check at runtime. If you exceed either
|
||||||
the recursion depth you reported in the raytrace pipeline create info, or the
|
the recursion depth you reported in the raytrace pipeline create info, or the
|
||||||
physical device recursion limit, undefined behaviour results.
|
physical device recursion limit, undefined behavior results.
|
||||||
|
|
||||||
The KHR raytracing spec lowers the minimum guaranteed recursion limit from
|
The KHR raytracing spec lowers the minimum guaranteed recursion limit from
|
||||||
31 (in the original NV spec) to the much more modest limit of 1 (i.e. no
|
31 (in the original NV spec) to the much more modest limit of 1 (i.e. no
|
||||||
|
|
@ -2203,19 +2242,19 @@ This also points out that in real-world applications the SBT should be embedded
|
||||||
automatically.
|
automatically.
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
vk::DeviceSize hitGroupOffset = 3u * progSize; // Jump over the raygen and 2 miss shaders
|
Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Jump over the raygen and 2 miss shaders
|
||||||
````
|
````
|
||||||
|
|
||||||
## `createRtDescriptorSet`
|
## `createRtDescriptorSet`
|
||||||
|
|
||||||
For each resource entry in the descriptor set, we indicated which shader stage would be able to use it. Since shadow
|
For each resource entry in the descriptor set, we indicated which shader stage would be able to use it. Since shadow
|
||||||
rays will be traced from the closest hit shader, we add `vkSS::eClosestHitKHR` to the acceleration structure binding:
|
rays will be traced from the closest hit shader, we add `VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR` to the acceleration structure binding:
|
||||||
|
|
||||||
```` C
|
```` C
|
||||||
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to
|
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to
|
||||||
// shoot shadow rays)
|
// shoot shadow rays)
|
||||||
m_rtDescSetLayoutBind.emplace_back(
|
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
|
||||||
vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
|
||||||
````
|
````
|
||||||
|
|
||||||
## `raytrace.rchit`
|
## `raytrace.rchit`
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
Project(${PROJNAME})
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
||||||
|
|
@ -28,6 +28,7 @@ file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
||||||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
||||||
include_directories(${TUTO_KHR_DIR}/common)
|
include_directories(${TUTO_KHR_DIR}/common)
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# GLSL to SPIR-V custom build
|
# GLSL to SPIR-V custom build
|
||||||
compile_glsl_directory(
|
compile_glsl_directory(
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
#define VMA_IMPLEMENTATION
|
#define VMA_IMPLEMENTATION
|
||||||
|
|
||||||
|
|
@ -29,6 +27,7 @@ extern std::vector<std::string> defaultSearchPaths;
|
||||||
#include "obj_loader.h"
|
#include "obj_loader.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
#include "hello_vulkan.h"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
|
|
@ -40,6 +39,9 @@ extern std::vector<std::string> defaultSearchPaths;
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
#include "nvvk/renderpasses_vk.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
extern std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// Holding the camera matrices
|
// Holding the camera matrices
|
||||||
struct CameraMatrices
|
struct CameraMatrices
|
||||||
{
|
{
|
||||||
|
|
@ -50,16 +52,14 @@ struct CameraMatrices
|
||||||
nvmath::mat4f projInverse;
|
nvmath::mat4f projInverse;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Keep the handle on the device
|
// Keep the handle on the device
|
||||||
// Initialize the tool to do all our allocations: buffers, images
|
// Initialize the tool to do all our allocations: buffers, images
|
||||||
//
|
//
|
||||||
void HelloVulkan::setup(const vk::Instance& instance,
|
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily)
|
|
||||||
{
|
{
|
||||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||||
m_alloc.init(instance, device, physicalDevice);
|
m_alloc.init(instance, device, physicalDevice);
|
||||||
m_debug.setup(m_device);
|
m_debug.setup(m_device);
|
||||||
|
|
||||||
|
|
@ -71,7 +71,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Called at each frame to update the camera matrix
|
// Called at each frame to update the camera matrix
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
// Prepare new UBO contents on host.
|
// Prepare new UBO contents on host.
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||||
|
|
@ -84,33 +84,33 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
||||||
|
|
||||||
// UBO on the device, and what stages access it.
|
// UBO on the device, and what stages access it.
|
||||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||||
auto uboUsageStages =
|
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||||
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
|
|
||||||
|
|
||||||
// Ensure that the modified UBO is not visible to previous frames.
|
// Ensure that the modified UBO is not visible to previous frames.
|
||||||
vk::BufferMemoryBarrier beforeBarrier;
|
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
beforeBarrier.setBuffer(deviceUBO);
|
beforeBarrier.buffer = deviceUBO;
|
||||||
beforeBarrier.setOffset(0);
|
beforeBarrier.offset = 0;
|
||||||
beforeBarrier.setSize(sizeof hostUBO);
|
beforeBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||||
// buffer so it is okay to deallocate when the function returns).
|
// buffer so it is okay to deallocate when the function returns).
|
||||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||||
|
|
||||||
// Making sure the updated UBO will be visible.
|
// Making sure the updated UBO will be visible.
|
||||||
vk::BufferMemoryBarrier afterBarrier;
|
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
afterBarrier.setBuffer(deviceUBO);
|
afterBarrier.buffer = deviceUBO;
|
||||||
afterBarrier.setOffset(0);
|
afterBarrier.offset = 0;
|
||||||
afterBarrier.setSize(sizeof hostUBO);
|
afterBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -118,39 +118,33 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
//
|
//
|
||||||
void HelloVulkan::createDescriptorSetLayout()
|
void HelloVulkan::createDescriptorSetLayout()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||||
|
|
||||||
// Camera matrices (binding = 0)
|
// Camera matrices (binding = 0)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
|
||||||
vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR));
|
|
||||||
// Materials (binding = 1)
|
// Materials (binding = 1)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj + 1,
|
||||||
vkDS(1, vkDT::eStorageBuffer, nbObj + 1, // Adding Implicit mat too
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
// Scene description (binding = 2)
|
// Scene description (binding = 2)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||||
vkDS(2, vkDT::eStorageBuffer, 1,
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
// Textures (binding = 3)
|
// Textures (binding = 3)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
|
||||||
vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
// Materials (binding = 4)
|
// Materials (binding = 4)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj,
|
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||||
vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
// Storing vertices (binding = 5)
|
// Storing vertices (binding = 5)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
|
||||||
// Storing indices (binding = 6)
|
// Storing indices (binding = 6)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
|
||||||
// Storing implicit obj (binding = 7)
|
// Storing implicit obj (binding = 7)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||||
vkDS(7, vkDT::eStorageBuffer, 1,
|
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR
|
||||||
vkSS::eClosestHitKHR | vkSS::eIntersectionKHR | vkSS::eAnyHitKHR));
|
| VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
|
|
||||||
|
|
||||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||||
|
|
@ -163,78 +157,76 @@ void HelloVulkan::createDescriptorSetLayout()
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateDescriptorSet()
|
void HelloVulkan::updateDescriptorSet()
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
|
|
||||||
// Camera matrices and scene description
|
// Camera matrices and scene description
|
||||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||||
|
|
||||||
// All material buffers, 1 buffer per OBJ
|
// All material buffers, 1 buffer per OBJ
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiVert;
|
std::vector<VkDescriptorBufferInfo> dbiVert;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiIdx;
|
std::vector<VkDescriptorBufferInfo> dbiIdx;
|
||||||
for(auto& model : m_objModel)
|
for(auto& m : m_objModel)
|
||||||
{
|
{
|
||||||
dbiMat.emplace_back(model.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiMatIdx.emplace_back(model.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiVert.emplace_back(model.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiIdx.emplace_back(model.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
}
|
}
|
||||||
dbiMat.emplace_back(m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE); // Adding implicit mat
|
dbiMat.push_back({m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE}); // Adding implicit mat
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data()));
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
|
||||||
|
|
||||||
// All texture samplers
|
// All texture samplers
|
||||||
std::vector<vk::DescriptorImageInfo> diit;
|
std::vector<VkDescriptorImageInfo> diit;
|
||||||
for(auto& texture : m_textures)
|
for(auto& texture : m_textures)
|
||||||
{
|
{
|
||||||
diit.emplace_back(texture.descriptor);
|
diit.emplace_back(texture.descriptor);
|
||||||
}
|
}
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||||
|
|
||||||
vk::DescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiImplDesc));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiImplDesc));
|
||||||
|
|
||||||
// Writing the information
|
// Writing the information
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating the pipeline layout
|
// Creating the pipeline layout
|
||||||
//
|
//
|
||||||
void HelloVulkan::createGraphicsPipeline()
|
void HelloVulkan::createGraphicsPipeline()
|
||||||
{
|
{
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstants)};
|
||||||
|
|
||||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
sizeof(ObjPushConstants)};
|
|
||||||
|
|
||||||
// Creating the Pipeline Layout
|
// Creating the Pipeline Layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
createInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
createInfo.pSetLayouts = &m_descSetLayout;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
createInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
|
||||||
|
|
||||||
// Creating the Pipeline
|
// Creating the Pipeline
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
std::vector<std::string> paths = defaultSearchPaths;
|
||||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass());
|
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass());
|
||||||
gpb.depthStencilState.depthTestEnable = true;
|
gpb.depthStencilState.depthTestEnable = true;
|
||||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||||
gpb.addAttributeDescriptions({
|
gpb.addAttributeDescriptions({
|
||||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||||
});
|
});
|
||||||
|
|
||||||
m_graphicsPipeline = gpb.createPipeline();
|
m_graphicsPipeline = gpb.createPipeline();
|
||||||
|
|
@ -246,8 +238,6 @@ void HelloVulkan::createGraphicsPipeline()
|
||||||
//
|
//
|
||||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
|
|
||||||
LOGI("Loading File: %s \n", filename.c_str());
|
LOGI("Loading File: %s \n", filename.c_str());
|
||||||
ObjLoader loader;
|
ObjLoader loader;
|
||||||
loader.loadModel(filename);
|
loader.loadModel(filename);
|
||||||
|
|
@ -272,17 +262,13 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
|
|
||||||
// Create the buffers on Device and copy vertices, indices and materials
|
// Create the buffers on Device and copy vertices, indices and materials
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||||
model.vertexBuffer =
|
VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
|
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||||
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
|
||||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
|
||||||
model.indexBuffer =
|
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_indices,
|
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
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
|
// Creates all textures found
|
||||||
createTextureImages(cmdBuf, loader.m_textures);
|
createTextureImages(cmdBuf, loader.m_textures);
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
cmdBufGet.submitAndWait(cmdBuf);
|
||||||
|
|
@ -298,17 +284,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
m_objInstance.emplace_back(instance);
|
m_objInstance.emplace_back(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating the uniform buffer holding the camera matrices
|
// Creating the uniform buffer holding the camera matrices
|
||||||
// - Buffer is host visible
|
// - Buffer is host visible
|
||||||
//
|
//
|
||||||
void HelloVulkan::createUniformBuffer()
|
void HelloVulkan::createUniformBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
using vkMP = vk::MemoryPropertyFlagBits;
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
|
||||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
|
||||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
|
||||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,11 +304,10 @@ void HelloVulkan::createUniformBuffer()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createSceneDescriptionBuffer()
|
void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
cmdGen.submitAndWait(cmdBuf);
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
m_alloc.finalizeAndReleaseStaging();
|
||||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||||
|
|
@ -333,15 +316,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating all textures and samplers
|
// Creating all textures and samplers
|
||||||
//
|
//
|
||||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
||||||
const std::vector<std::string>& textures)
|
|
||||||
{
|
{
|
||||||
using vkIU = vk::ImageUsageFlagBits;
|
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
samplerCreateInfo.maxLod = FLT_MAX;
|
||||||
|
|
||||||
vk::SamplerCreateInfo samplerCreateInfo{
|
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
|
||||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
|
||||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
|
||||||
|
|
||||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||||
if(textures.empty() && m_textures.empty())
|
if(textures.empty() && m_textures.empty())
|
||||||
|
|
@ -349,18 +332,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
nvvk::Texture texture;
|
nvvk::Texture texture;
|
||||||
|
|
||||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||||
vk::DeviceSize bufferSize = sizeof(color);
|
VkDeviceSize bufferSize = sizeof(color);
|
||||||
auto imgSize = vk::Extent2D(1, 1);
|
auto imgSize = VkExtent2D{1, 1};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||||
|
|
||||||
// Creating the VKImage
|
// Creating the dummy texture
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -373,8 +355,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
o << "media/textures/" << texture;
|
o << "media/textures/" << texture;
|
||||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||||
|
|
||||||
stbi_uc* stbi_pixels =
|
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
||||||
|
|
||||||
|
|
@ -387,15 +368,14 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||||
vk::ImageViewCreateInfo ivInfo =
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
|
|
@ -411,10 +391,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
//
|
//
|
||||||
void HelloVulkan::destroyResources()
|
void HelloVulkan::destroyResources()
|
||||||
{
|
{
|
||||||
m_device.destroy(m_graphicsPipeline);
|
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||||
m_device.destroy(m_pipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
m_device.destroy(m_descPool);
|
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||||
m_device.destroy(m_descSetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||||
|
|
||||||
m_alloc.destroy(m_cameraMat);
|
m_alloc.destroy(m_cameraMat);
|
||||||
m_alloc.destroy(m_sceneDesc);
|
m_alloc.destroy(m_sceneDesc);
|
||||||
m_alloc.destroy(m_implObjects.implBuf);
|
m_alloc.destroy(m_implObjects.implBuf);
|
||||||
|
|
@ -445,32 +426,31 @@ void HelloVulkan::destroyResources()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Drawing the scene in raster mode
|
// Drawing the scene in raster mode
|
||||||
//
|
//
|
||||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
using vkPBP = vk::PipelineBindPoint;
|
VkDeviceSize offset{0};
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
vk::DeviceSize offset{0};
|
|
||||||
|
|
||||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||||
|
|
||||||
// Dynamic Viewport
|
// Dynamic Viewport
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
setViewport(cmdBuf);
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
|
||||||
|
|
||||||
// Drawing all triangles
|
// Drawing all triangles
|
||||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& inst = m_objInstance[i];
|
auto& inst = m_objInstance[i];
|
||||||
auto& model = m_objModel[inst.objIndex];
|
auto& model = m_objModel[inst.objIndex];
|
||||||
m_pushConstants.instanceId = i; // Telling which instance is drawn
|
m_pushConstants.instanceId = i; // Telling which instance is drawn
|
||||||
cmdBuf.pushConstants<ObjPushConstants>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
m_pushConstants);
|
|
||||||
|
|
||||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
sizeof(ObjPushConstants), &m_pushConstants);
|
||||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||||
|
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -511,7 +491,7 @@ void HelloVulkan::initRayTracing()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Ray trace the scene
|
// Ray trace the scene
|
||||||
//
|
//
|
||||||
void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
||||||
{
|
{
|
||||||
updateFrame();
|
updateFrame();
|
||||||
if(m_pushConstants.frame >= m_maxFrames)
|
if(m_pushConstants.frame >= m_maxFrames)
|
||||||
|
|
@ -580,7 +560,7 @@ void HelloVulkan::addImplMaterial(const MaterialObj& mat)
|
||||||
//
|
//
|
||||||
void HelloVulkan::createImplictBuffers()
|
void HelloVulkan::createImplictBuffers()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
using vkBU = VkBufferUsageFlagBits;
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||||
|
|
||||||
// Not allowing empty buffers
|
// Not allowing empty buffers
|
||||||
|
|
@ -591,9 +571,9 @@ void HelloVulkan::createImplictBuffers()
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||||
m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl,
|
m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl,
|
||||||
vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress);
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
|
||||||
m_implObjects.implMatBuf =
|
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
|
||||||
m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, vkBU::eStorageBuffer);
|
m_implObjects.implMatBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
cmdGen.submitAndWait(cmdBuf);
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
m_alloc.finalizeAndReleaseStaging();
|
||||||
m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj");
|
m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj");
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/resourceallocator_vk.hpp"
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -56,25 +56,21 @@ using Allocator = nvvk::ResourceAllocatorDedicated;
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
Offscreen& offscreen() { return m_offscreen; }
|
Offscreen& offscreen() { return m_offscreen; }
|
||||||
Raytracer& raytracer() { return m_raytrace; }
|
Raytracer& raytracer() { return m_raytrace; }
|
||||||
|
|
@ -87,12 +83,12 @@ public:
|
||||||
|
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
int m_maxFrames{10};
|
int m_maxFrames{10};
|
||||||
void resetFrame();
|
void resetFrame();
|
||||||
|
|
@ -115,7 +111,7 @@ public:
|
||||||
Raytracer m_raytrace;
|
Raytracer m_raytrace;
|
||||||
|
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
// Implicit
|
// Implicit
|
||||||
ImplInst m_implObjects;
|
ImplInst m_implObjects;
|
||||||
|
|
|
||||||
|
|
@ -23,21 +23,18 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
#include "hello_vulkan.h"
|
||||||
|
#include "imgui/imgui_camera_widget.h"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
#include "imgui/imgui_camera_widget.h"
|
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -47,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -70,18 +68,15 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
|
|
||||||
if(helloVk.m_pushConstants.lightType < 2)
|
if(helloVk.m_pushConstants.lightType < 2)
|
||||||
{
|
{
|
||||||
changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x,
|
changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, -20.f, 20.f);
|
||||||
-20.f, 20.f);
|
|
||||||
}
|
}
|
||||||
if(helloVk.m_pushConstants.lightType > 0)
|
if(helloVk.m_pushConstants.lightType > 0)
|
||||||
{
|
{
|
||||||
changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x,
|
changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, -1.f, 1.f);
|
||||||
-1.f, 1.f);
|
|
||||||
}
|
}
|
||||||
if(helloVk.m_pushConstants.lightType < 2)
|
if(helloVk.m_pushConstants.lightType < 2)
|
||||||
{
|
{
|
||||||
changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f,
|
changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f);
|
||||||
500.f);
|
|
||||||
}
|
}
|
||||||
if(helloVk.m_pushConstants.lightType == 1)
|
if(helloVk.m_pushConstants.lightType == 1)
|
||||||
{
|
{
|
||||||
|
|
@ -121,8 +116,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -151,7 +145,7 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -163,18 +157,16 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -189,11 +181,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -202,12 +193,11 @@ int main(int argc, char** argv)
|
||||||
// Setup Imgui
|
// Setup Imgui
|
||||||
helloVk.initGUI(0); // Using sub-pass 0
|
helloVk.initGUI(0); // Using sub-pass 0
|
||||||
|
|
||||||
// Creating scene
|
// Creation of the example
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
|
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
|
||||||
nvmath::scale_mat4(nvmath::vec3f(0.5f))
|
nvmath::scale_mat4(nvmath::vec3f(0.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f)));
|
||||||
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f)));
|
|
||||||
|
|
||||||
std::random_device rd; // Will be used to obtain a seed for the random number engine
|
std::random_device rd; // Will be used to obtain a seed for the random number engine
|
||||||
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
|
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
|
||||||
|
|
@ -278,11 +268,12 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
// Start the Dear ImGui frame
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
ImGui::NewFrame();
|
|
||||||
ImGuiH::Panel::Begin();
|
ImGuiH::Panel::Begin();
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
// Edit 3 floats representing a color
|
// Edit 3 floats representing a color
|
||||||
|
|
@ -292,11 +283,8 @@ int main(int argc, char** argv)
|
||||||
if(changed)
|
if(changed)
|
||||||
helloVk.resetFrame();
|
helloVk.resetFrame();
|
||||||
|
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -306,27 +294,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(offscreen.renderPass());
|
offscreenRenderPassBeginInfo.renderPass = offscreen.renderPass();
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(offscreen.frameBuffer());
|
offscreenRenderPassBeginInfo.framebuffer = offscreen.frameBuffer();
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -335,40 +324,41 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
offscreen.draw(cmdBuf, helloVk.getSize());
|
offscreen.draw(cmdBuf, helloVk.getSize());
|
||||||
|
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,7 @@ extern std::vector<std::string> defaultSearchPaths;
|
||||||
// Post-processing
|
// Post-processing
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void Offscreen::setup(const vk::Device& device,
|
void Offscreen::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
nvvk::ResourceAllocator* allocator,
|
|
||||||
uint32_t queueFamily)
|
|
||||||
{
|
{
|
||||||
m_device = device;
|
m_device = device;
|
||||||
m_alloc = allocator;
|
m_alloc = allocator;
|
||||||
|
|
@ -46,14 +43,14 @@ void Offscreen::setup(const vk::Device& device,
|
||||||
|
|
||||||
void Offscreen::destroy()
|
void Offscreen::destroy()
|
||||||
{
|
{
|
||||||
m_device.destroy(m_pipeline);
|
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
||||||
m_device.destroy(m_pipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
m_device.destroy(m_descPool);
|
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||||
m_device.destroy(m_dsetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_dsetLayout, nullptr);
|
||||||
|
vkDestroyRenderPass(m_device, m_renderPass, nullptr);
|
||||||
|
vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
|
||||||
m_alloc->destroy(m_colorTexture);
|
m_alloc->destroy(m_colorTexture);
|
||||||
m_alloc->destroy(m_depthTexture);
|
m_alloc->destroy(m_depthTexture);
|
||||||
m_device.destroy(m_renderPass);
|
|
||||||
m_device.destroy(m_framebuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -66,30 +63,28 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
|
||||||
|
|
||||||
// Creating the color image
|
// Creating the color image
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(size, m_colorFormat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
size, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_colorTexture = m_alloc->createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
|
||||||
|
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
m_colorTexture = m_alloc->createTexture(image, ivInfo, sampler);
|
||||||
m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creating the depth buffer
|
// Creating the depth buffer
|
||||||
{
|
{
|
||||||
auto depthCreateInfo =
|
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(size, m_depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
nvvk::makeImage2DCreateInfo(size, m_depthFormat,
|
|
||||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
|
||||||
nvvk::Image image = m_alloc->createImage(depthCreateInfo);
|
nvvk::Image image = m_alloc->createImage(depthCreateInfo);
|
||||||
|
|
||||||
vk::ImageViewCreateInfo depthStencilView;
|
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
depthStencilView.setFormat(m_depthFormat);
|
depthStencilView.format = m_depthFormat;
|
||||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||||
depthStencilView.setImage(image.image);
|
depthStencilView.image = image.image;
|
||||||
|
|
||||||
m_depthTexture = m_alloc->createTexture(image, depthStencilView);
|
m_depthTexture = m_alloc->createTexture(image, depthStencilView);
|
||||||
}
|
}
|
||||||
|
|
@ -98,11 +93,9 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
|
||||||
{
|
{
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
vk::ImageLayout::eGeneral);
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, vk::ImageLayout::eUndefined,
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
|
||||||
vk::ImageAspectFlagBits::eDepth);
|
|
||||||
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
genCmdBuf.submitAndWait(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -111,49 +104,45 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
|
||||||
if(!m_renderPass)
|
if(!m_renderPass)
|
||||||
{
|
{
|
||||||
m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true,
|
m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true,
|
||||||
vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
|
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating the frame buffer for offscreen
|
// Creating the frame buffer for offscreen
|
||||||
std::vector<vk::ImageView> attachments = {m_colorTexture.descriptor.imageView,
|
std::vector<VkImageView> attachments = {m_colorTexture.descriptor.imageView, m_depthTexture.descriptor.imageView};
|
||||||
m_depthTexture.descriptor.imageView};
|
|
||||||
|
|
||||||
m_device.destroy(m_framebuffer);
|
vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
|
||||||
vk::FramebufferCreateInfo info;
|
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||||
info.setRenderPass(m_renderPass);
|
info.renderPass = m_renderPass;
|
||||||
info.setAttachmentCount(2);
|
info.attachmentCount = 2;
|
||||||
info.setPAttachments(attachments.data());
|
info.pAttachments = attachments.data();
|
||||||
info.setWidth(size.width);
|
info.width = size.width;
|
||||||
info.setHeight(size.height);
|
info.height = size.height;
|
||||||
info.setLayers(1);
|
info.layers = 1;
|
||||||
m_framebuffer = m_device.createFramebuffer(info);
|
vkCreateFramebuffer(m_device, &info, nullptr, &m_framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
|
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
|
||||||
// The incoming render pass, is in which rendering pass it will be displayed (framebuffer)
|
// The incoming render pass, is in which rendering pass it will be displayed (framebuffer)
|
||||||
//
|
//
|
||||||
void Offscreen::createPipeline(vk::RenderPass& renderPass)
|
void Offscreen::createPipeline(VkRenderPass& renderPass)
|
||||||
{
|
{
|
||||||
// Push constants in the fragment shader
|
// Push constants in the fragment shader
|
||||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||||
|
|
||||||
// Creating the pipeline layout
|
// Creating the pipeline layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
pipelineLayoutCreateInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_dsetLayout);
|
pipelineLayoutCreateInfo.pSetLayouts = &m_dsetLayout;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_pipelineLayout);
|
||||||
|
|
||||||
// Pipeline: completely generic, no vertices
|
// Pipeline: completely generic, no vertices
|
||||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass);
|
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass);
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
true),
|
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vk::ShaderStageFlagBits::eVertex);
|
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
|
||||||
vk::ShaderStageFlagBits::eFragment);
|
|
||||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
|
||||||
m_pipeline = pipelineGenerator.createPipeline();
|
m_pipeline = pipelineGenerator.createPipeline();
|
||||||
m_debug.setObjectName(m_pipeline, "post");
|
m_debug.setObjectName(m_pipeline, "post");
|
||||||
}
|
}
|
||||||
|
|
@ -164,11 +153,7 @@ void Offscreen::createPipeline(vk::RenderPass& renderPass)
|
||||||
//
|
//
|
||||||
void Offscreen::createDescriptor()
|
void Offscreen::createDescriptor()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
m_dsetLayoutBinding.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
|
|
||||||
m_dsetLayoutBinding.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
|
||||||
m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device);
|
m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device);
|
||||||
m_descPool = m_dsetLayoutBinding.createPool(m_device);
|
m_descPool = m_dsetLayoutBinding.createPool(m_device);
|
||||||
m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout);
|
m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout);
|
||||||
|
|
@ -179,26 +164,28 @@ void Offscreen::createDescriptor()
|
||||||
//
|
//
|
||||||
void Offscreen::updateDescriptorSet()
|
void Offscreen::updateDescriptorSet()
|
||||||
{
|
{
|
||||||
vk::WriteDescriptorSet writeDescriptorSets =
|
VkWriteDescriptorSet writeDescriptorSets = m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor);
|
||||||
m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor);
|
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
||||||
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Draw a full screen quad with the attached image
|
// Draw a full screen quad with the attached image
|
||||||
//
|
//
|
||||||
void Offscreen::draw(vk::CommandBuffer cmdBuf, VkExtent2D& size)
|
void Offscreen::draw(VkCommandBuffer cmdBuf, VkExtent2D& size)
|
||||||
{
|
{
|
||||||
m_debug.beginLabel(cmdBuf, "Post");
|
m_debug.beginLabel(cmdBuf, "Post");
|
||||||
|
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)size.width, (float)size.height, 0, 1)});
|
VkViewport viewport{0, 0, (float)size.width, (float)size.height, 0, 1};
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {size.width, size.height}}});
|
vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
|
||||||
|
VkRect2D scissor{{0, 0}, {size.width, size.height}};
|
||||||
|
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
|
||||||
|
|
||||||
|
|
||||||
auto aspectRatio = static_cast<float>(size.width) / static_cast<float>(size.height);
|
auto aspectRatio = static_cast<float>(size.width) / static_cast<float>(size.height);
|
||||||
cmdBuf.pushConstants<float>(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, aspectRatio);
|
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_pipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_pipelineLayout, 0, m_dset, {});
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_dset, 0, nullptr);
|
||||||
cmdBuf.draw(3, 1, 0, 0);
|
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/resourceallocator_vk.hpp"
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
@ -33,40 +31,36 @@
|
||||||
class Offscreen
|
class Offscreen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Device& device,
|
void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
nvvk::ResourceAllocator* allocator,
|
|
||||||
uint32_t queueFamily);
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
void createFramebuffer(VkExtent2D& size);
|
void createFramebuffer(VkExtent2D& size);
|
||||||
void createPipeline(vk::RenderPass& renderPass);
|
void createPipeline(VkRenderPass& renderPass);
|
||||||
void createDescriptor();
|
void createDescriptor();
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void draw(vk::CommandBuffer cmdBuf, VkExtent2D& size);
|
void draw(VkCommandBuffer cmdBuf, VkExtent2D& size);
|
||||||
|
|
||||||
const vk::RenderPass& renderPass() { return m_renderPass; }
|
const VkRenderPass& renderPass() { return m_renderPass; }
|
||||||
const vk::Framebuffer& frameBuffer() { return m_framebuffer; }
|
const VkFramebuffer& frameBuffer() { return m_framebuffer; }
|
||||||
const nvvk::Texture& colorTexture() { return m_colorTexture; }
|
const nvvk::Texture& colorTexture() { return m_colorTexture; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nvvk::DescriptorSetBindings m_dsetLayoutBinding;
|
nvvk::DescriptorSetBindings m_dsetLayoutBinding;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_dsetLayout;
|
VkDescriptorSetLayout m_dsetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_dset;
|
VkDescriptorSet m_dset{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_pipeline;
|
VkPipeline m_pipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_renderPass;
|
VkRenderPass m_renderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_framebuffer;
|
VkFramebuffer m_framebuffer{VK_NULL_HANDLE};
|
||||||
|
|
||||||
nvvk::Texture m_colorTexture;
|
nvvk::Texture m_colorTexture;
|
||||||
vk::Format m_colorFormat{vk::Format::eR32G32B32A32Sfloat};
|
VkFormat m_colorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
nvvk::Texture m_depthTexture;
|
nvvk::Texture m_depthTexture;
|
||||||
vk::Format m_depthFormat{vk::Format::eX8D24UnormPack32};
|
VkFormat m_depthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
nvvk::ResourceAllocator* m_alloc{
|
nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
|
||||||
nullptr}; // Allocator for buffer, images, acceleration structures
|
VkDevice m_device;
|
||||||
vk::Device m_device;
|
|
||||||
int m_graphicsQueueIndex{0};
|
int m_graphicsQueueIndex{0};
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,12 @@
|
||||||
#include "nvh/alignment.hpp"
|
#include "nvh/alignment.hpp"
|
||||||
#include "nvvk/shaders_vk.hpp"
|
#include "nvvk/shaders_vk.hpp"
|
||||||
#include "obj_loader.h"
|
#include "obj_loader.h"
|
||||||
|
#include "nvvk/buffers_vk.hpp"
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
extern std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
void Raytracer::setup(const vk::Device& device,
|
void Raytracer::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
nvvk::ResourceAllocator* allocator,
|
|
||||||
uint32_t queueFamily)
|
|
||||||
{
|
{
|
||||||
m_device = device;
|
m_device = device;
|
||||||
m_physicalDevice = physicalDevice;
|
m_physicalDevice = physicalDevice;
|
||||||
|
|
@ -40,12 +38,11 @@ void Raytracer::setup(const vk::Device& device,
|
||||||
m_graphicsQueueIndex = queueFamily;
|
m_graphicsQueueIndex = queueFamily;
|
||||||
|
|
||||||
// Requesting ray tracing properties
|
// Requesting ray tracing properties
|
||||||
auto properties =
|
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
prop2.pNext = &m_rtProperties;
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
|
||||||
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
|
|
||||||
|
|
||||||
|
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
|
||||||
m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties);
|
m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties);
|
||||||
m_debug.setup(device);
|
m_debug.setup(device);
|
||||||
}
|
}
|
||||||
|
|
@ -55,10 +52,10 @@ void Raytracer::destroy()
|
||||||
{
|
{
|
||||||
m_sbtWrapper.destroy();
|
m_sbtWrapper.destroy();
|
||||||
m_rtBuilder.destroy();
|
m_rtBuilder.destroy();
|
||||||
m_device.destroy(m_rtDescPool);
|
vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr);
|
||||||
m_device.destroy(m_rtDescSetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr);
|
||||||
m_device.destroy(m_rtPipeline);
|
vkDestroyPipeline(m_device, m_rtPipeline, nullptr);
|
||||||
m_device.destroy(m_rtPipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr);
|
||||||
m_alloc->destroy(m_rtSBTBuffer);
|
m_alloc->destroy(m_rtSBTBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,30 +65,30 @@ void Raytracer::destroy()
|
||||||
auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
||||||
{
|
{
|
||||||
// Building part
|
// Building part
|
||||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
||||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
||||||
|
|
||||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
triangles.setVertexData(vertexAddress);
|
triangles.vertexData.deviceAddress = vertexAddress;
|
||||||
triangles.setVertexStride(sizeof(VertexObj));
|
triangles.vertexStride = sizeof(VertexObj);
|
||||||
triangles.setIndexType(vk::IndexType::eUint32);
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
triangles.setIndexData(indexAddress);
|
triangles.indexData.deviceAddress = indexAddress;
|
||||||
triangles.setTransformData({});
|
triangles.transformData = {};
|
||||||
triangles.setMaxVertex(model.nbVertices);
|
triangles.maxVertex = model.nbVertices;
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
// Setting up the build info of the acceleration
|
||||||
vk::AccelerationStructureGeometryKHR asGeom;
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit
|
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
|
||||||
asGeom.geometry.setTriangles(triangles);
|
asGeom.geometry.triangles = triangles;
|
||||||
|
|
||||||
|
|
||||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||||
offset.setFirstVertex(0);
|
offset.firstVertex = 0;
|
||||||
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
|
offset.primitiveCount = model.nbIndices / 3; // Nb triangles
|
||||||
offset.setPrimitiveOffset(0);
|
offset.primitiveOffset = 0;
|
||||||
offset.setTransformOffset(0);
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||||
input.asGeometry.emplace_back(asGeom);
|
input.asGeometry.emplace_back(asGeom);
|
||||||
|
|
@ -105,11 +102,11 @@ auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
||||||
//
|
//
|
||||||
auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
||||||
{
|
{
|
||||||
vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer});
|
VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, implicitObj.implBuf.buffer);
|
||||||
|
|
||||||
vk::AccelerationStructureGeometryAabbsDataKHR aabbs;
|
VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR};
|
||||||
aabbs.setData(dataAddress);
|
aabbs.data.deviceAddress = dataAddress;
|
||||||
aabbs.setStride(sizeof(ObjImplicit));
|
aabbs.stride = sizeof(ObjImplicit);
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
// Setting up the build info of the acceleration
|
||||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
|
|
@ -118,11 +115,11 @@ auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
||||||
asGeom.geometry.aabbs = aabbs;
|
asGeom.geometry.aabbs = aabbs;
|
||||||
|
|
||||||
|
|
||||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||||
offset.setFirstVertex(0);
|
offset.firstVertex = 0;
|
||||||
offset.setPrimitiveCount(static_cast<uint32_t>(implicitObj.objImpl.size())); // Nb aabb
|
offset.primitiveCount = static_cast<uint32_t>(implicitObj.objImpl.size()); // Nb aabb
|
||||||
offset.setPrimitiveOffset(0);
|
offset.primitiveOffset = 0;
|
||||||
offset.setTransformOffset(0);
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||||
input.asGeometry.emplace_back(asGeom);
|
input.asGeometry.emplace_back(asGeom);
|
||||||
|
|
@ -153,8 +150,8 @@ void Raytracer::createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& imp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
|
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR
|
||||||
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowCompaction);
|
| VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj)
|
void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj)
|
||||||
|
|
@ -177,45 +174,47 @@ void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst&
|
||||||
{
|
{
|
||||||
nvvk::RaytracingBuilderKHR::Instance rayInst;
|
nvvk::RaytracingBuilderKHR::Instance rayInst;
|
||||||
rayInst.transform = implicitObj.transform; // Position of the instance
|
rayInst.transform = implicitObj.transform; // Position of the instance
|
||||||
rayInst.instanceCustomId =
|
rayInst.instanceCustomId = static_cast<uint32_t>(implicitObj.blasId); // Same for material index
|
||||||
static_cast<uint32_t>(implicitObj.blasId); // Same for material index
|
|
||||||
rayInst.blasId = static_cast<uint32_t>(implicitObj.blasId);
|
rayInst.blasId = static_cast<uint32_t>(implicitObj.blasId);
|
||||||
rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one)
|
rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one)
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
tlas.emplace_back(rayInst);
|
tlas.emplace_back(rayInst);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// This descriptor set holds the Acceleration structure and the output image
|
// This descriptor set holds the Acceleration structure and the output image
|
||||||
//
|
//
|
||||||
void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage)
|
void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
|
||||||
{
|
{
|
||||||
using vkDT = vk::DescriptorType;
|
using vkDSLB = VkDescriptorSetLayoutBinding;
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
|
||||||
|
|
||||||
m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1,
|
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
|
||||||
vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
|
||||||
m_rtDescSetLayoutBind.addBinding(
|
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
|
||||||
vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image
|
|
||||||
|
|
||||||
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
||||||
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
||||||
m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0];
|
|
||||||
|
|
||||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo;
|
allocateInfo.descriptorPool = m_rtDescPool;
|
||||||
descASInfo.setAccelerationStructureCount(1);
|
allocateInfo.descriptorSetCount = 1;
|
||||||
descASInfo.setPAccelerationStructures(&tlas);
|
allocateInfo.pSetLayouts = &m_rtDescSetLayout;
|
||||||
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral};
|
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
|
||||||
|
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||||
|
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||||
|
descASInfo.accelerationStructureCount = 1;
|
||||||
|
descASInfo.pAccelerationStructures = &tlas;
|
||||||
|
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo));
|
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, 1, &imageInfo));
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -223,168 +222,187 @@ void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage)
|
||||||
// Writes the output image to the descriptor set
|
// Writes the output image to the descriptor set
|
||||||
// - Required when changing resolution
|
// - Required when changing resolution
|
||||||
//
|
//
|
||||||
void Raytracer::updateRtDescriptorSet(const vk::ImageView& outputImage)
|
void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage)
|
||||||
{
|
{
|
||||||
using vkDT = vk::DescriptorType;
|
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
|
||||||
|
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo);
|
||||||
// (1) Output buffer
|
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
|
||||||
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral};
|
|
||||||
vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo};
|
|
||||||
m_device.updateDescriptorSets(wds, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Pipeline for the ray tracer: all shaders, raygen, chit, miss
|
// Pipeline for the ray tracer: all shaders, raygen, chit, miss
|
||||||
//
|
//
|
||||||
void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
|
void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout)
|
||||||
{
|
{
|
||||||
vk::ShaderModule raygenSM = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
|
||||||
vk::ShaderModule missSM = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
|
||||||
|
|
||||||
// The second miss shader is invoked when a shadow ray misses the geometry. It
|
enum StageIndices
|
||||||
// simply indicates that no occlusion has been found
|
{
|
||||||
vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
|
eRaygen,
|
||||||
m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
eMiss,
|
||||||
|
eMiss2,
|
||||||
|
eClosestHit,
|
||||||
|
eAnyHit,
|
||||||
|
eClosestHit1,
|
||||||
|
eAnyHit1,
|
||||||
|
eIntersect,
|
||||||
|
eCall0,
|
||||||
|
eCall1,
|
||||||
|
eCall2,
|
||||||
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
|
||||||
|
// All stages
|
||||||
|
std::array<VkPipelineShaderStageCreateInfo, eShaderGroupCount> stages{};
|
||||||
|
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
||||||
|
stage.pName = "main"; // All the same entry point
|
||||||
|
// Raygen
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||||
|
stages[eRaygen] = stage;
|
||||||
|
// Miss
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||||
|
stages[eMiss] = stage;
|
||||||
|
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
|
||||||
|
stage.module =
|
||||||
|
nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||||
|
stages[eMiss2] = stage;
|
||||||
|
// Hit Group - Closest Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHit] = stage;
|
||||||
|
// Hit Group - Closest Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||||
|
stages[eAnyHit] = stage;
|
||||||
|
// Hit Group - 1
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHit1] = stage;
|
||||||
|
// Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||||
|
stages[eAnyHit1] = stage;
|
||||||
|
// Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
|
||||||
|
stages[eIntersect] = stage;
|
||||||
|
|
||||||
|
// Call0
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||||
|
stages[eCall0] = stage;
|
||||||
|
// Call1
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||||
|
stages[eCall1] = stage;
|
||||||
|
// Call2
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||||
|
stages[eCall2] = stage;
|
||||||
|
|
||||||
|
|
||||||
std::vector<vk::PipelineShaderStageCreateInfo> stages;
|
// Shader groups
|
||||||
|
VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
|
||||||
|
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
|
||||||
// Raygen
|
// Raygen
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.generalShader = eRaygen;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
m_rtShaderGroups.push_back(group);
|
||||||
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(rg); // 0
|
|
||||||
|
|
||||||
// Miss
|
// Miss
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.generalShader = eMiss;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
m_rtShaderGroups.push_back(group);
|
||||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(mg); // 1
|
|
||||||
// Shadow Miss
|
// Shadow Miss
|
||||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
|
group.generalShader = eMiss2;
|
||||||
m_rtShaderGroups.push_back(mg); // 2
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
// Hit Group0 - Closest Hit + AnyHit
|
// closest hit shader
|
||||||
vk::ShaderModule chitSM = nvvk::createShaderModule(
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
vk::ShaderModule ahitSM = nvvk::createShaderModule(
|
group.closestHitShader = eClosestHit;
|
||||||
m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
group.anyHitShader = eAnyHit;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
// closest hit shader
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
group.closestHitShader = eClosestHit1;
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
group.anyHitShader = eAnyHit1;
|
||||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
group.intersectionShader = eIntersect;
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
|
m_rtShaderGroups.push_back(group);
|
||||||
m_rtShaderGroups.push_back(hg); // 3
|
|
||||||
|
|
||||||
|
|
||||||
// Hit Group1 - Closest Hit + Intersection (procedural)
|
|
||||||
vk::ShaderModule chit2SM = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
|
||||||
vk::ShaderModule ahit2SM = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
|
|
||||||
vk::ShaderModule rintSM = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
|
|
||||||
{
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
|
|
||||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit2SM, "main"});
|
|
||||||
hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(hg); // 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callable shaders
|
// Callable shaders
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.generalShader = eCall0;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
group.generalShader = eCall1;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
group.generalShader = eCall2;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
vk::ShaderModule call0 = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
|
||||||
vk::ShaderModule call1 = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
|
||||||
vk::ShaderModule call2 = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
|
||||||
|
|
||||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
|
|
||||||
m_rtShaderGroups.push_back(callGroup); // 5
|
|
||||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
|
|
||||||
m_rtShaderGroups.push_back(callGroup); // 6
|
|
||||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
|
|
||||||
m_rtShaderGroups.push_back(callGroup); //7
|
|
||||||
|
|
||||||
|
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
|
||||||
|
|
||||||
// Push constant: we want to be able to update constants used by the shaders
|
// Push constant: we want to be able to update constants used by the shaders
|
||||||
vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR
|
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
|
||||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
| VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
||||||
| vk::ShaderStageFlagBits::eMissKHR
|
|
||||||
| vk::ShaderStageFlagBits::eCallableKHR,
|
|
||||||
0, sizeof(RtPushConstants)};
|
0, sizeof(RtPushConstants)};
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant);
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
|
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
||||||
|
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant;
|
||||||
|
|
||||||
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
||||||
std::vector<vk::DescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
|
std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(static_cast<uint32_t>(rtDescSetLayouts.size()));
|
pipelineLayoutCreateInfo.setLayoutCount = static_cast<uint32_t>(rtDescSetLayouts.size());
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data());
|
pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data();
|
||||||
|
|
||||||
|
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
|
||||||
|
|
||||||
m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
|
||||||
|
|
||||||
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
||||||
vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo;
|
VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
|
||||||
rayPipelineInfo.setStageCount(static_cast<uint32_t>(stages.size())); // Stages are shaders
|
rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size()); // Stages are shaders
|
||||||
rayPipelineInfo.setPStages(stages.data());
|
rayPipelineInfo.pStages = stages.data();
|
||||||
|
|
||||||
rayPipelineInfo.setGroupCount(static_cast<uint32_t>(
|
rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
|
||||||
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
|
rayPipelineInfo.pGroups = m_rtShaderGroups.data();
|
||||||
rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
|
|
||||||
|
|
||||||
rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
|
// The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
|
||||||
rayPipelineInfo.setLayout(m_rtPipelineLayout);
|
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
|
||||||
|
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
|
||||||
|
// in the ray generation to avoid deep recursion.
|
||||||
|
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
|
||||||
|
rayPipelineInfo.layout = m_rtPipelineLayout;
|
||||||
|
|
||||||
m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value;
|
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
|
||||||
|
|
||||||
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
|
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
|
||||||
|
|
||||||
m_device.destroy(raygenSM);
|
|
||||||
m_device.destroy(missSM);
|
for(auto& s : stages)
|
||||||
m_device.destroy(shadowmissSM);
|
vkDestroyShaderModule(m_device, s.module, nullptr);
|
||||||
m_device.destroy(chitSM);
|
|
||||||
m_device.destroy(ahitSM);
|
|
||||||
m_device.destroy(chit2SM);
|
|
||||||
m_device.destroy(ahit2SM);
|
|
||||||
m_device.destroy(rintSM);
|
|
||||||
m_device.destroy(call0);
|
|
||||||
m_device.destroy(call1);
|
|
||||||
m_device.destroy(call2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Ray Tracing the scene
|
// Ray Tracing the scene
|
||||||
//
|
//
|
||||||
void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
|
void Raytracer::raytrace(const VkCommandBuffer& cmdBuf,
|
||||||
const nvmath::vec4f& clearColor,
|
const nvmath::vec4f& clearColor,
|
||||||
vk::DescriptorSet& sceneDescSet,
|
VkDescriptorSet& sceneDescSet,
|
||||||
vk::Extent2D& size,
|
VkExtent2D& size,
|
||||||
ObjPushConstants& sceneConstants)
|
ObjPushConstants& sceneConstants)
|
||||||
{
|
{
|
||||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
m_debug.beginLabel(cmdBuf, "Ray trace");
|
||||||
|
|
@ -398,19 +416,19 @@ void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
|
||||||
m_rtPushConstants.lightType = sceneConstants.lightType;
|
m_rtPushConstants.lightType = sceneConstants.lightType;
|
||||||
m_rtPushConstants.frame = sceneConstants.frame;
|
m_rtPushConstants.frame = sceneConstants.frame;
|
||||||
|
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline);
|
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0,
|
std::vector<VkDescriptorSet> descSets{m_rtDescSet, sceneDescSet};
|
||||||
{m_rtDescSet, sceneDescSet}, {});
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
|
||||||
cmdBuf.pushConstants<RtPushConstants>(m_rtPipelineLayout,
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0,
|
||||||
vk::ShaderStageFlagBits::eRaygenKHR
|
(uint32_t)descSets.size(), descSets.data(), 0, nullptr);
|
||||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
||||||
| vk::ShaderStageFlagBits::eMissKHR
|
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR
|
||||||
| vk::ShaderStageFlagBits::eCallableKHR,
|
| VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
||||||
0, m_rtPushConstants);
|
0, sizeof(RtPushConstants), &m_rtPushConstants);
|
||||||
|
|
||||||
|
|
||||||
auto regions = m_sbtWrapper.getRegions();
|
auto& regions = m_sbtWrapper.getRegions();
|
||||||
cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], size.width, size.height, 1);
|
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1);
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#include "nvmath/nvmath.h"
|
#include "nvmath/nvmath.h"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -29,43 +27,39 @@
|
||||||
class Raytracer
|
class Raytracer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Device& device,
|
void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
nvvk::ResourceAllocator* allocator,
|
|
||||||
uint32_t queueFamily);
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
auto objectToVkGeometryKHR(const ObjModel& model);
|
auto objectToVkGeometryKHR(const ObjModel& model);
|
||||||
auto implicitToVkGeometryKHR(const ImplInst& implicitObj);
|
auto implicitToVkGeometryKHR(const ImplInst& implicitObj);
|
||||||
void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj);
|
void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj);
|
||||||
void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj);
|
void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj);
|
||||||
void createRtDescriptorSet(const vk::ImageView& outputImage);
|
void createRtDescriptorSet(const VkImageView& outputImage);
|
||||||
void updateRtDescriptorSet(const vk::ImageView& outputImage);
|
void updateRtDescriptorSet(const VkImageView& outputImage);
|
||||||
void createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout);
|
void createRtPipeline(VkDescriptorSetLayout& sceneDescLayout);
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf,
|
void raytrace(const VkCommandBuffer& cmdBuf,
|
||||||
const nvmath::vec4f& clearColor,
|
const nvmath::vec4f& clearColor,
|
||||||
vk::DescriptorSet& sceneDescSet,
|
VkDescriptorSet& sceneDescSet,
|
||||||
vk::Extent2D& size,
|
VkExtent2D& size,
|
||||||
ObjPushConstants& sceneConstants);
|
ObjPushConstants& sceneConstants);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nvvk::ResourceAllocator* m_alloc{
|
nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
|
||||||
nullptr}; // Allocator for buffer, images, acceleration structures
|
VkPhysicalDevice m_physicalDevice;
|
||||||
vk::PhysicalDevice m_physicalDevice;
|
VkDevice m_device;
|
||||||
vk::Device m_device;
|
|
||||||
int m_graphicsQueueIndex{0};
|
int m_graphicsQueueIndex{0};
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
nvvk::SBTWrapper m_sbtWrapper;
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
|
|
||||||
struct RtPushConstants
|
struct RtPushConstants
|
||||||
|
|
|
||||||
|
|
@ -19,23 +19,24 @@
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "obj_loader.h"
|
#include "obj_loader.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
#include "hello_vulkan.h"
|
||||||
|
#include "nvh/alignment.hpp"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
|
#include "nvh/fileoperations.hpp"
|
||||||
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/images_vk.hpp"
|
#include "nvvk/images_vk.hpp"
|
||||||
#include "nvvk/pipeline_vk.hpp"
|
#include "nvvk/pipeline_vk.hpp"
|
||||||
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
#include "nvvk/renderpasses_vk.hpp"
|
||||||
|
#include "nvvk/shaders_vk.hpp"
|
||||||
|
|
||||||
|
extern std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// Holding the camera matrices
|
// Holding the camera matrices
|
||||||
|
|
@ -50,13 +51,10 @@ struct CameraMatrices
|
||||||
// Keep the handle on the device
|
// Keep the handle on the device
|
||||||
// Initialize the tool to do all our allocations: buffers, images
|
// Initialize the tool to do all our allocations: buffers, images
|
||||||
//
|
//
|
||||||
void HelloVulkan::setup(const vk::Instance& instance,
|
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily)
|
|
||||||
{
|
{
|
||||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||||
m_alloc.init(device, physicalDevice);
|
m_alloc.init(instance, device, physicalDevice);
|
||||||
m_debug.setup(m_device);
|
m_debug.setup(m_device);
|
||||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +62,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Called at each frame to update the camera matrix
|
// Called at each frame to update the camera matrix
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
// Prepare new UBO contents on host.
|
// Prepare new UBO contents on host.
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||||
|
|
@ -75,32 +73,33 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
||||||
|
|
||||||
// UBO on the device, and what stages access it.
|
// UBO on the device, and what stages access it.
|
||||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||||
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader;
|
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||||
|
|
||||||
// Ensure that the modified UBO is not visible to previous frames.
|
// Ensure that the modified UBO is not visible to previous frames.
|
||||||
vk::BufferMemoryBarrier beforeBarrier;
|
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
beforeBarrier.setBuffer(deviceUBO);
|
beforeBarrier.buffer = deviceUBO;
|
||||||
beforeBarrier.setOffset(0);
|
beforeBarrier.offset = 0;
|
||||||
beforeBarrier.setSize(sizeof hostUBO);
|
beforeBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||||
// buffer so it is okay to deallocate when the function returns).
|
// buffer so it is okay to deallocate when the function returns).
|
||||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||||
|
|
||||||
// Making sure the updated UBO will be visible.
|
// Making sure the updated UBO will be visible.
|
||||||
vk::BufferMemoryBarrier afterBarrier;
|
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
afterBarrier.setBuffer(deviceUBO);
|
afterBarrier.buffer = deviceUBO;
|
||||||
afterBarrier.setOffset(0);
|
afterBarrier.offset = 0;
|
||||||
afterBarrier.setSize(sizeof hostUBO);
|
afterBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -108,25 +107,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
//
|
//
|
||||||
void HelloVulkan::createDescriptorSetLayout()
|
void HelloVulkan::createDescriptorSetLayout()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||||
|
|
||||||
// Camera matrices (binding = 0)
|
// Camera matrices (binding = 0)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex));
|
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
// Materials (binding = 1)
|
// Materials (binding = 1)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment));
|
|
||||||
// Scene description (binding = 2)
|
// Scene description (binding = 2)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment));
|
|
||||||
// Textures (binding = 3)
|
// Textures (binding = 3)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment));
|
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
|
||||||
// Materials (binding = 4)
|
// Materials (binding = 4)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
|
||||||
|
|
||||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||||
|
|
@ -139,27 +132,27 @@ void HelloVulkan::createDescriptorSetLayout()
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateDescriptorSet()
|
void HelloVulkan::updateDescriptorSet()
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
|
|
||||||
// Camera matrices and scene description
|
// Camera matrices and scene description
|
||||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||||
|
|
||||||
// All material buffers, 1 buffer per OBJ
|
// All material buffers, 1 buffer per OBJ
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||||
for(auto& m : m_objModel)
|
for(auto& m : m_objModel)
|
||||||
{
|
{
|
||||||
dbiMat.emplace_back(m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiMatIdx.emplace_back(m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
}
|
}
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||||
|
|
||||||
// All texture samplers
|
// All texture samplers
|
||||||
std::vector<vk::DescriptorImageInfo> diit;
|
std::vector<VkDescriptorImageInfo> diit;
|
||||||
for(auto& texture : m_textures)
|
for(auto& texture : m_textures)
|
||||||
{
|
{
|
||||||
diit.emplace_back(texture.descriptor);
|
diit.emplace_back(texture.descriptor);
|
||||||
|
|
@ -167,7 +160,7 @@ void HelloVulkan::updateDescriptorSet()
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||||
|
|
||||||
// Writing the information
|
// Writing the information
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -176,32 +169,29 @@ void HelloVulkan::updateDescriptorSet()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createGraphicsPipeline()
|
void HelloVulkan::createGraphicsPipeline()
|
||||||
{
|
{
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
|
||||||
|
|
||||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
sizeof(ObjPushConstant)};
|
|
||||||
|
|
||||||
// Creating the Pipeline Layout
|
// Creating the Pipeline Layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
createInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
createInfo.pSetLayouts = &m_descSetLayout;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
createInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
|
||||||
|
|
||||||
// Creating the Pipeline
|
// Creating the Pipeline
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
std::vector<std::string> paths = defaultSearchPaths;
|
||||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
||||||
gpb.depthStencilState.depthTestEnable = true;
|
gpb.depthStencilState.depthTestEnable = true;
|
||||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||||
gpb.addAttributeDescriptions({
|
gpb.addAttributeDescriptions({
|
||||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||||
});
|
});
|
||||||
|
|
||||||
m_graphicsPipeline = gpb.createPipeline();
|
m_graphicsPipeline = gpb.createPipeline();
|
||||||
|
|
@ -213,8 +203,6 @@ void HelloVulkan::createGraphicsPipeline()
|
||||||
//
|
//
|
||||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
|
|
||||||
LOGI("Loading File: %s \n", filename.c_str());
|
LOGI("Loading File: %s \n", filename.c_str());
|
||||||
ObjLoader loader;
|
ObjLoader loader;
|
||||||
loader.loadModel(filename);
|
loader.loadModel(filename);
|
||||||
|
|
@ -239,11 +227,11 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
|
|
||||||
// Create the buffers on Device and copy vertices, indices and materials
|
// Create the buffers on Device and copy vertices, indices and materials
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, vkBU::eVertexBuffer);
|
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, vkBU::eIndexBuffer);
|
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
||||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
|
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
|
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
// Creates all textures found
|
// Creates all textures found
|
||||||
createTextureImages(cmdBuf, loader.m_textures);
|
createTextureImages(cmdBuf, loader.m_textures);
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
cmdBufGet.submitAndWait(cmdBuf);
|
||||||
|
|
@ -266,11 +254,8 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
//
|
//
|
||||||
void HelloVulkan::createUniformBuffer()
|
void HelloVulkan::createUniformBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
using vkMP = vk::MemoryPropertyFlagBits;
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
|
||||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
|
||||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
|
||||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -282,11 +267,10 @@ void HelloVulkan::createUniformBuffer()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createSceneDescriptionBuffer()
|
void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
cmdGen.submitAndWait(cmdBuf);
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
m_alloc.finalizeAndReleaseStaging();
|
||||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||||
|
|
@ -295,15 +279,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating all textures and samplers
|
// Creating all textures and samplers
|
||||||
//
|
//
|
||||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
||||||
const std::vector<std::string>& textures)
|
|
||||||
{
|
{
|
||||||
using vkIU = vk::ImageUsageFlagBits;
|
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
samplerCreateInfo.maxLod = FLT_MAX;
|
||||||
|
|
||||||
vk::SamplerCreateInfo samplerCreateInfo{
|
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
|
||||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
|
||||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
|
||||||
|
|
||||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||||
if(textures.empty() && m_textures.empty())
|
if(textures.empty() && m_textures.empty())
|
||||||
|
|
@ -311,18 +295,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
nvvk::Texture texture;
|
nvvk::Texture texture;
|
||||||
|
|
||||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||||
vk::DeviceSize bufferSize = sizeof(color);
|
VkDeviceSize bufferSize = sizeof(color);
|
||||||
auto imgSize = vk::Extent2D(1, 1);
|
auto imgSize = VkExtent2D{1, 1};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||||
|
|
||||||
// Creating the dummy texture
|
// Creating the dummy texture
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -335,8 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
o << "media/textures/" << texture;
|
o << "media/textures/" << texture;
|
||||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||||
|
|
||||||
stbi_uc* stbi_pixels =
|
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
||||||
|
|
||||||
|
|
@ -349,15 +331,14 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||||
vk::ImageViewCreateInfo ivInfo =
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
|
|
@ -373,10 +354,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
//
|
//
|
||||||
void HelloVulkan::destroyResources()
|
void HelloVulkan::destroyResources()
|
||||||
{
|
{
|
||||||
m_device.destroy(m_graphicsPipeline);
|
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||||
m_device.destroy(m_pipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
m_device.destroy(m_descPool);
|
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||||
m_device.destroy(m_descSetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||||
|
|
||||||
m_alloc.destroy(m_cameraMat);
|
m_alloc.destroy(m_cameraMat);
|
||||||
m_alloc.destroy(m_sceneDesc);
|
m_alloc.destroy(m_sceneDesc);
|
||||||
|
|
||||||
|
|
@ -394,14 +376,14 @@ void HelloVulkan::destroyResources()
|
||||||
}
|
}
|
||||||
|
|
||||||
//#Post
|
//#Post
|
||||||
m_device.destroy(m_postPipeline);
|
|
||||||
m_device.destroy(m_postPipelineLayout);
|
|
||||||
m_device.destroy(m_postDescPool);
|
|
||||||
m_device.destroy(m_postDescSetLayout);
|
|
||||||
m_alloc.destroy(m_offscreenColor);
|
m_alloc.destroy(m_offscreenColor);
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
m_alloc.destroy(m_offscreenDepth);
|
||||||
m_device.destroy(m_offscreenRenderPass);
|
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
||||||
m_device.destroy(m_offscreenFramebuffer);
|
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
||||||
|
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
||||||
|
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
||||||
|
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||||
|
|
||||||
m_alloc.deinit();
|
m_alloc.deinit();
|
||||||
}
|
}
|
||||||
|
|
@ -409,33 +391,31 @@ void HelloVulkan::destroyResources()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Drawing the scene in raster mode
|
// Drawing the scene in raster mode
|
||||||
//
|
//
|
||||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
using vkPBP = vk::PipelineBindPoint;
|
VkDeviceSize offset{0};
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
vk::DeviceSize offset{0};
|
|
||||||
|
|
||||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||||
|
|
||||||
// Dynamic Viewport
|
// Dynamic Viewport
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
setViewport(cmdBuf);
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
|
||||||
|
|
||||||
|
|
||||||
// Drawing all triangles
|
// Drawing all triangles
|
||||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& inst = m_objInstance[i];
|
auto& inst = m_objInstance[i];
|
||||||
auto& model = m_objModel[inst.objIndex];
|
auto& model = m_objModel[inst.objIndex];
|
||||||
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
||||||
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
m_pushConstant);
|
|
||||||
|
|
||||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
sizeof(ObjPushConstant), &m_pushConstant);
|
||||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||||
|
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -466,29 +446,28 @@ void HelloVulkan::createOffscreenRender()
|
||||||
// Creating the color image
|
// Creating the color image
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
| vk::ImageUsageFlagBits::eSampled
|
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
||||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating the depth buffer
|
// Creating the depth buffer
|
||||||
auto depthCreateInfo =
|
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
|
|
||||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
|
||||||
{
|
{
|
||||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
||||||
|
|
||||||
vk::ImageViewCreateInfo depthStencilView;
|
|
||||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||||
depthStencilView.setFormat(m_offscreenDepthFormat);
|
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
depthStencilView.format = m_offscreenDepthFormat;
|
||||||
depthStencilView.setImage(image.image);
|
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||||
|
depthStencilView.image = image.image;
|
||||||
|
|
||||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
||||||
}
|
}
|
||||||
|
|
@ -497,11 +476,9 @@ void HelloVulkan::createOffscreenRender()
|
||||||
{
|
{
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
vk::ImageLayout::eGeneral);
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
|
||||||
vk::ImageAspectFlagBits::eDepth);
|
|
||||||
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
genCmdBuf.submitAndWait(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -509,25 +486,23 @@ void HelloVulkan::createOffscreenRender()
|
||||||
// Creating a renderpass for the offscreen
|
// Creating a renderpass for the offscreen
|
||||||
if(!m_offscreenRenderPass)
|
if(!m_offscreenRenderPass)
|
||||||
{
|
{
|
||||||
m_offscreenRenderPass =
|
m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
||||||
nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creating the frame buffer for offscreen
|
// Creating the frame buffer for offscreen
|
||||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
|
||||||
m_offscreenDepth.descriptor.imageView};
|
|
||||||
|
|
||||||
m_device.destroy(m_offscreenFramebuffer);
|
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||||
vk::FramebufferCreateInfo info;
|
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||||
info.setRenderPass(m_offscreenRenderPass);
|
info.renderPass = m_offscreenRenderPass;
|
||||||
info.setAttachmentCount(2);
|
info.attachmentCount = 2;
|
||||||
info.setPAttachments(attachments.data());
|
info.pAttachments = attachments.data();
|
||||||
info.setWidth(m_size.width);
|
info.width = m_size.width;
|
||||||
info.setHeight(m_size.height);
|
info.height = m_size.height;
|
||||||
info.setLayers(1);
|
info.layers = 1;
|
||||||
m_offscreenFramebuffer = m_device.createFramebuffer(info);
|
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -536,25 +511,22 @@ void HelloVulkan::createOffscreenRender()
|
||||||
void HelloVulkan::createPostPipeline()
|
void HelloVulkan::createPostPipeline()
|
||||||
{
|
{
|
||||||
// Push constants in the fragment shader
|
// Push constants in the fragment shader
|
||||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||||
|
|
||||||
// Creating the pipeline layout
|
// Creating the pipeline layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
createInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout);
|
createInfo.pSetLayouts = &m_postDescSetLayout;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
createInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
||||||
|
|
||||||
|
|
||||||
// Pipeline: completely generic, no vertices
|
// Pipeline: completely generic, no vertices
|
||||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
|
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
||||||
m_renderPass);
|
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
true),
|
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||||
vk::ShaderStageFlagBits::eVertex);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
|
||||||
vk::ShaderStageFlagBits::eFragment);
|
|
||||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
|
||||||
m_postPipeline = pipelineGenerator.createPipeline();
|
m_postPipeline = pipelineGenerator.createPipeline();
|
||||||
m_debug.setObjectName(m_postPipeline, "post");
|
m_debug.setObjectName(m_postPipeline, "post");
|
||||||
}
|
}
|
||||||
|
|
@ -565,11 +537,7 @@ void HelloVulkan::createPostPipeline()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createPostDescriptor()
|
void HelloVulkan::createPostDescriptor()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
|
|
||||||
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
|
||||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
||||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
||||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
||||||
|
|
@ -581,28 +549,25 @@ void HelloVulkan::createPostDescriptor()
|
||||||
//
|
//
|
||||||
void HelloVulkan::updatePostDescriptorSet()
|
void HelloVulkan::updatePostDescriptorSet()
|
||||||
{
|
{
|
||||||
vk::WriteDescriptorSet writeDescriptorSets =
|
VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
||||||
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
||||||
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Draw a full screen quad with the attached image
|
// Draw a full screen quad with the attached image
|
||||||
//
|
//
|
||||||
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
||||||
{
|
{
|
||||||
m_debug.beginLabel(cmdBuf, "Post");
|
m_debug.beginLabel(cmdBuf, "Post");
|
||||||
|
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
setViewport(cmdBuf);
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
|
||||||
|
|
||||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
||||||
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0,
|
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||||
aspectRatio);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline);
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0,
|
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||||
m_postDescSet, {});
|
|
||||||
cmdBuf.draw(3, 1, 0, 0);
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
|
@ -33,25 +32,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -88,12 +83,12 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
|
|
@ -109,18 +104,18 @@ public:
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -89,14 +86,12 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0),
|
CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0), nvmath::vec3f(0, 1, 0));
|
||||||
nvmath::vec3f(0, 1, 0));
|
|
||||||
|
|
||||||
// Setup Vulkan
|
// Setup Vulkan
|
||||||
if(!glfwVulkanSupported())
|
if(!glfwVulkanSupported())
|
||||||
|
|
@ -147,11 +142,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -196,8 +190,7 @@ int main(int argc, char** argv)
|
||||||
ImGuiH::Panel::Begin();
|
ImGuiH::Panel::Begin();
|
||||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -207,61 +200,62 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
@ -76,4 +76,3 @@ _finalize_target( ${PROJNAME} )
|
||||||
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -18,12 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -35,25 +35,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -90,39 +86,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -133,25 +131,25 @@ public:
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void createRtShaderBindingTable();
|
void createRtShaderBindingTable();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
{
|
{
|
||||||
nvmath::vec4f clearColor;
|
nvmath::vec4f clearColor;
|
||||||
nvmath::vec3f lightPosition;
|
nvmath::vec3f lightPosition;
|
||||||
float lightIntensity;
|
float lightIntensity{100.0f};
|
||||||
int lightType;
|
int lightType{0};
|
||||||
} m_rtPushConstants;
|
} m_rtPushConstants;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -87,8 +86,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -117,7 +115,7 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -127,19 +125,19 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
&accelFeature);
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
|
||||||
&rtPipelineFeature);
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||||
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
vkctx.initInstance(contextInfo);
|
vkctx.initInstance(contextInfo);
|
||||||
|
|
@ -149,16 +147,14 @@ int main(int argc, char** argv)
|
||||||
// Use a compatible device
|
// Use a compatible device
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||||
|
|
||||||
|
|
||||||
// Create example
|
// Create example
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -219,9 +215,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -231,27 +225,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -260,40 +255,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
|
|
@ -62,17 +62,20 @@ void HelloVulkan::animationInstances(float time)
|
||||||
Next, we update the buffer that describes the scene, which is used by the rasterizer to set each object's position, and also by the ray tracer to compute shading normals.
|
Next, we update the buffer that describes the scene, which is used by the rasterizer to set each object's position, and also by the ray tracer to compute shading normals.
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Update the buffer
|
// Update the buffer
|
||||||
vk::DeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance);
|
VkDeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance);
|
||||||
nvvkBuffer stagingBuffer = m_alloc.createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc,
|
nvvk::Buffer stagingBuffer =
|
||||||
vk::MemoryPropertyFlagBits::eHostVisible);
|
m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||||
// Copy data to staging buffer
|
// Copy data to staging buffer
|
||||||
auto* gInst = m_alloc.map(stagingBuffer);
|
auto* gInst = m_alloc.map(stagingBuffer);
|
||||||
memcpy(gInst, m_objInstance.data(), bufferSize);
|
memcpy(gInst, m_objInstance.data(), bufferSize);
|
||||||
m_alloc.unmap(stagingBuffer);
|
m_alloc.unmap(stagingBuffer);
|
||||||
// Copy staging buffer to the Scene Description buffer
|
// Copy staging buffer to the Scene Description buffer
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||||
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
||||||
cmdBuf.copyBuffer(stagingBuffer.buffer, m_sceneDesc.buffer, vk::BufferCopy(0, 0, bufferSize));
|
|
||||||
|
VkBufferCopy region{0, 0, bufferSize};
|
||||||
|
vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_sceneDesc.buffer, 1, ®ion);
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
genCmdBuf.submitAndWait(cmdBuf);
|
||||||
m_alloc.destroy(stagingBuffer);
|
m_alloc.destroy(stagingBuffer);
|
||||||
|
|
@ -115,7 +118,7 @@ std::vector<nvvk::RaytracingBuilder::Instance> m_tlas;
|
||||||
|
|
||||||
Make sure to rename it to `m_tlas`, instead of `tlas`.
|
Make sure to rename it to `m_tlas`, instead of `tlas`.
|
||||||
|
|
||||||
One important point is that we need to set the TLAS build flags to allow updates, by adding the`vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate` flag.
|
One important point is that we need to set the TLAS build flags to allow updates, by adding the`VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR` flag.
|
||||||
This is absolutely needed, since otherwise the TLAS cannot be updated.
|
This is absolutely needed, since otherwise the TLAS cannot be updated.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
|
|
@ -124,16 +127,17 @@ void HelloVulkan::createTopLevelAS()
|
||||||
m_tlas.reserve(m_objInstance.size());
|
m_tlas.reserve(m_objInstance.size());
|
||||||
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
|
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
|
||||||
{
|
{
|
||||||
nvvk::RaytracingBuilder::Instance rayInst;
|
nvvk::RaytracingBuilderKHR::Instance rayInst;
|
||||||
rayInst.transform = m_objInstance[i].transform; // Position of the instance
|
rayInst.transform = m_objInstance[i].transform; // Position of the instance
|
||||||
rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT
|
rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT
|
||||||
rayInst.blasId = m_objInstance[i].objIndex;
|
rayInst.blasId = m_objInstance[i].objIndex;
|
||||||
rayInst.hitGroupId = m_objInstance[i].hitgroup;
|
rayInst.hitGroupId = 0;
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV;
|
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
m_tlas.emplace_back(rayInst);
|
m_tlas.emplace_back(rayInst);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildTlas(m_tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
|
|
||||||
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate);
|
m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
|
||||||
|
m_rtBuilder.buildTlas(m_tlas, m_rtFlags);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -203,11 +207,11 @@ Add all of the following members to the `HelloVulkan` class:
|
||||||
void createCompPipelines();
|
void createCompPipelines();
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_compDescPool;
|
VkDescriptorPool m_compDescPool;
|
||||||
vk::DescriptorSetLayout m_compDescSetLayout;
|
VkDescriptorSetLayout m_compDescSetLayout;
|
||||||
vk::DescriptorSet m_compDescSet;
|
VkDescriptorSet m_compDescSet;
|
||||||
vk::Pipeline m_compPipeline;
|
VkPipeline m_compPipeline;
|
||||||
vk::PipelineLayout m_compPipelineLayout;
|
VkPipelineLayout m_compPipelineLayout;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The compute shader will work on a single `VertexObj` buffer.
|
The compute shader will work on a single `VertexObj` buffer.
|
||||||
|
|
@ -215,8 +219,7 @@ The compute shader will work on a single `VertexObj` buffer.
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
void HelloVulkan::createCompDescriptors()
|
void HelloVulkan::createCompDescriptors()
|
||||||
{
|
{
|
||||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding(
|
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||||
0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute));
|
|
||||||
|
|
||||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||||
|
|
@ -227,12 +230,12 @@ void HelloVulkan::createCompDescriptors()
|
||||||
`updateCompDescriptors` will set the set the descriptor to the buffer of `VertexObj` objects to which the animation will be applied.
|
`updateCompDescriptors` will set the set the descriptor to the buffer of `VertexObj` objects to which the animation will be applied.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
void HelloVulkan::updateCompDescriptors(nvvkBuffer& vertex)
|
void HelloVulkan::updateCompDescriptors(nvvk::Buffer& vertex)
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
vk::DescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, dbiUnif));
|
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &dbiUnif));
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -243,27 +246,37 @@ to set the animation time.
|
||||||
void HelloVulkan::createCompPipelines()
|
void HelloVulkan::createCompPipelines()
|
||||||
{
|
{
|
||||||
// pushing time
|
// pushing time
|
||||||
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(float)};
|
VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float)};
|
||||||
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants};
|
|
||||||
m_compPipelineLayout = m_device.createPipelineLayout(layout_info);
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
|
createInfo.setLayoutCount = 1;
|
||||||
|
createInfo.pSetLayouts = &m_compDescSetLayout;
|
||||||
|
createInfo.pushConstantRangeCount = 1;
|
||||||
|
createInfo.pPushConstantRanges = &push_constants;
|
||||||
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_compPipelineLayout);
|
||||||
|
|
||||||
|
|
||||||
|
VkComputePipelineCreateInfo computePipelineCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
|
||||||
|
computePipelineCreateInfo.layout = m_compPipelineLayout;
|
||||||
|
|
||||||
computePipelineCreateInfo.stage =
|
computePipelineCreateInfo.stage =
|
||||||
nvvk::createShaderStageInfo(m_device,
|
nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true),
|
||||||
nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths),
|
|
||||||
VK_SHADER_STAGE_COMPUTE_BIT);
|
VK_SHADER_STAGE_COMPUTE_BIT);
|
||||||
m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo, nullptr);
|
|
||||||
m_device.destroy(computePipelineCreateInfo.stage.module);
|
vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_compPipeline);
|
||||||
|
|
||||||
|
vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Finally, destroy the resources in `HelloVulkan::destroyResources()`:
|
Finally, destroy the resources in `HelloVulkan::destroyResources()`:
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
m_device.destroy(m_compDescPool);
|
// #VK_compute
|
||||||
m_device.destroy(m_compDescSetLayout);
|
vkDestroyPipeline(m_device, m_compPipeline, nullptr);
|
||||||
m_device.destroy(m_compPipeline);
|
vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr);
|
||||||
m_device.destroy(m_compPipelineLayout);
|
vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### `anim.comp`
|
### `anim.comp`
|
||||||
|
|
@ -338,14 +351,13 @@ void HelloVulkan::animationObject(float time)
|
||||||
updateCompDescriptors(model.vertexBuffer);
|
updateCompDescriptors(model.vertexBuffer);
|
||||||
|
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||||
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||||
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||||
|
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time);
|
||||||
|
vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1);
|
||||||
|
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
|
||||||
{m_compDescSet}, {});
|
|
||||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(float),
|
|
||||||
&time);
|
|
||||||
cmdBuf.dispatch(model.nbVertices, 1, 1);
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
genCmdBuf.submitAndWait(cmdBuf);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
@ -457,8 +469,8 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
// We could add more geometry in each BLAS, but we add only one for now
|
// We could add more geometry in each BLAS, but we add only one for now
|
||||||
m_blas.push_back(blas);
|
m_blas.push_back(blas);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildBlas(m_blas, vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate
|
m_rtBuilder.buildBlas(m_blas, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR
|
||||||
| vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastBuild);
|
| VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -36,25 +36,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -91,39 +87,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -133,18 +131,18 @@ public:
|
||||||
void createRtDescriptorSet();
|
void createRtDescriptorSet();
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
nvvk::SBTWrapper m_sbtWrapper;
|
||||||
|
|
||||||
std::vector<nvvk::RaytracingBuilderKHR::Instance> m_tlas;
|
std::vector<nvvk::RaytracingBuilderKHR::Instance> m_tlas;
|
||||||
|
|
@ -168,11 +166,11 @@ public:
|
||||||
void createCompPipelines();
|
void createCompPipelines();
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_compDescPool;
|
VkDescriptorPool m_compDescPool;
|
||||||
vk::DescriptorSetLayout m_compDescSetLayout;
|
VkDescriptorSetLayout m_compDescSetLayout;
|
||||||
vk::DescriptorSet m_compDescSet;
|
VkDescriptorSet m_compDescSet;
|
||||||
vk::Pipeline m_compPipeline;
|
VkPipeline m_compPipeline;
|
||||||
vk::PipelineLayout m_compPipelineLayout;
|
VkPipelineLayout m_compPipelineLayout;
|
||||||
|
|
||||||
vk::BuildAccelerationStructureFlagsKHR m_rtFlags;
|
VkBuildAccelerationStructureFlagsKHR m_rtFlags;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -33,13 +32,10 @@
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -47,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -74,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -88,12 +86,11 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
CameraManip.setLookat(nvmath::vec3f(4, 4, 4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
|
CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
|
||||||
|
|
||||||
// Setup Vulkan
|
// Setup Vulkan
|
||||||
if(!glfwVulkanSupported())
|
if(!glfwVulkanSupported())
|
||||||
|
|
@ -131,16 +128,14 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -155,11 +150,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -229,8 +223,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -245,27 +238,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -274,40 +268,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
|
|
@ -108,25 +108,30 @@ The any hit shader will be part of the hit shader group. Currently, the hit shad
|
||||||
In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahit.spv`
|
In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahit.spv`
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
vk::ShaderModule ahitSM =
|
enum StageIndices
|
||||||
nvvk::createShaderModule(m_device, //
|
{
|
||||||
nvh::loadFile("shaders/raytrace.rahit.spv", true, paths));
|
...
|
||||||
|
eAnyHit,
|
||||||
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hit Group - Any Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||||
|
stages[eAnyHit] = stage;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
add the any hit shader to the hit group
|
The Any Hit goes in the same Hit group as the Closest Hit, so we need to
|
||||||
|
add the Any Hit stage index and push back the shader module to the stages.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
// closest hit shader
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
// Payload 0
|
||||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
m_rtShaderGroups.push_back(hg);
|
group.closestHitShader = eClosestHit;
|
||||||
~~~~
|
group.anyHitShader = eAnyHit;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
and at the end, delete it:
|
|
||||||
|
|
||||||
~~~~ C++
|
|
||||||
m_device.destroy(ahitSM);
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## Give access of the buffers to the Any Hit shader
|
## Give access of the buffers to the Any Hit shader
|
||||||
|
|
@ -137,38 +142,37 @@ This is the case for the material and scene description buffers
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Materials (binding = 1)
|
// Materials (binding = 1)
|
||||||
m_descSetLayoutBind.emplace_back(
|
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||||
vkDS(1, vkDT::eStorageBuffer, nbObj,
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
// Scene description (binding = 2)
|
// Scene description (binding = 2)
|
||||||
m_descSetLayoutBind.emplace_back( //
|
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||||
vkDS(2, vkDT::eStorageBuffer, 1,
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
and also for the vertex, index and material index buffers:
|
and also for the vertex, index and material index buffers:
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Materials (binding = 4)
|
// Materials (binding = 4)
|
||||||
m_descSetLayoutBind.emplace_back( //
|
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||||
vkDS(4, vkDT::eStorageBuffer, nbObj,
|
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
|
||||||
// Storing vertices (binding = 5)
|
// Storing vertices (binding = 5)
|
||||||
m_descSetLayoutBind.emplace_back( //
|
m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||||
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
// Storing indices (binding = 6)
|
// Storing indices (binding = 6)
|
||||||
m_descSetLayoutBind.emplace_back( //
|
m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||||
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## Opaque Flag
|
## Opaque Flag
|
||||||
|
|
||||||
In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `vk::GeometryFlagBitsKHR::eOpaque`. However, this avoided invoking the any hit shader.
|
In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `VK_GEOMETRY_OPAQUE_BIT_KHR`. However, this avoided invoking the any hit shader.
|
||||||
|
|
||||||
We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `eNoDuplicateAnyHitInvocation` flag:
|
We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR` flag:
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
geometry.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation);
|
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // Avoid double hits;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## Ray Generation Shader
|
## Ray Generation Shader
|
||||||
|
|
@ -364,8 +368,6 @@ traceRayEXT(topLevelAS, // acceleration structure
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Ray tracing Pipeline
|
### Ray tracing Pipeline
|
||||||
|
|
||||||
The final step is to add the new Hit Group. This is a change in `HelloVulkan::createRtPipeline()`.
|
The final step is to add the new Hit Group. This is a change in `HelloVulkan::createRtPipeline()`.
|
||||||
|
|
@ -373,22 +375,42 @@ We need to load the new any hit shader and create a new Hit Group.
|
||||||
|
|
||||||
Replace the `"shaders/raytrace.rahit.spv"` for `"shaders/raytrace_0.rahit.spv"`
|
Replace the `"shaders/raytrace.rahit.spv"` for `"shaders/raytrace_0.rahit.spv"`
|
||||||
|
|
||||||
|
Load the new shader module.
|
||||||
|
|
||||||
|
~~~~ C
|
||||||
|
enum StageIndices
|
||||||
|
{
|
||||||
|
eRaygen,
|
||||||
|
eMiss,
|
||||||
|
eMiss2,
|
||||||
|
eClosestHit,
|
||||||
|
eAnyHit,
|
||||||
|
eAnyHit2,
|
||||||
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hit Group - Any Hit
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_0.rahit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||||
|
stages[eAnyHit] = stage;
|
||||||
|
//
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||||
|
stages[eAnyHit2] = stage;
|
||||||
|
~~~~
|
||||||
|
|
||||||
Then, after the creating of the first Hit Group, create a new one, where only the any hit using payload 1
|
Then, after the creating of the first Hit Group, create a new one, where only the any hit using payload 1
|
||||||
is added. We are skipping the closest hit shader in the trace call, so we can ignore it in the Hit Group.
|
is added. We are skipping the closest hit shader in the trace call, so we can ignore it in the Hit Group.
|
||||||
|
|
||||||
~~~~ C
|
~~~~ C
|
||||||
// Payload 1
|
// Payload 1
|
||||||
vk::ShaderModule ahit1SM =
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
nvvk::createShaderModule(m_device, //
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths));
|
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped)
|
group.anyHitShader = eAnyHit2;
|
||||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
m_rtShaderGroups.push_back(group);
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(hg);
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
At the end of the function, delete the shader module `ahit1SM`.
|
|
||||||
|
|
||||||
|
|
||||||
**Note:** Re-Run
|
**Note:** Re-Run
|
||||||
Everything should work as before, but now it does it right.
|
Everything should work as before, but now it does it right.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -35,25 +35,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -90,39 +86,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -133,19 +131,19 @@ public:
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void createRtShaderBindingTable();
|
void createRtShaderBindingTable();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
void resetFrame();
|
void resetFrame();
|
||||||
void updateFrame();
|
void updateFrame();
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
int m_maxFrames{10000};
|
int m_maxFrames{10000};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -33,11 +32,9 @@
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -87,8 +86,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -117,7 +115,7 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -131,13 +129,10 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
&accelFeature);
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
|
||||||
&rtPipelineFeature);
|
|
||||||
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
|
|
@ -156,11 +151,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -172,8 +166,7 @@ int main(int argc, char** argv)
|
||||||
// Creation of the example
|
// Creation of the example
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true),
|
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true),
|
||||||
nvmath::scale_mat4(nvmath::vec3f(1.5f))
|
nvmath::scale_mat4(nvmath::vec3f(1.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
|
||||||
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -215,6 +208,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -223,8 +217,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -234,27 +227,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -263,40 +257,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -36,35 +36,33 @@ The following are the buffers are they can be seen in [NSight Graphics](https://
|
||||||
|
|
||||||
## G-Buffer
|
## G-Buffer
|
||||||
|
|
||||||
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `vk::Format::eR32G32B32A32Sfloat` to store the position and normal and one `vk::Format::eR32Sfloat` for the ambient occlusion.
|
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
| vk::ImageUsageFlagBits::eSampled
|
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||||
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ambient occlusion result (r32)
|
// The ambient occlusion result (r32)
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
| vk::ImageUsageFlagBits::eSampled
|
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||||
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +74,7 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
||||||
|
|
||||||
```
|
```
|
||||||
// Creating the frame buffer for offscreen
|
// Creating the frame buffer for offscreen
|
||||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||||
m_gBuffer.descriptor.imageView,
|
m_gBuffer.descriptor.imageView,
|
||||||
m_offscreenDepth.descriptor.imageView};
|
m_offscreenDepth.descriptor.imageView};
|
||||||
```
|
```
|
||||||
|
|
@ -86,7 +84,7 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
||||||
This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth)
|
This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth)
|
||||||
|
|
||||||
```
|
```
|
||||||
vk::ClearValue clearValues[3];
|
std::array<VkClearValue, 3> clearValues{};
|
||||||
```
|
```
|
||||||
|
|
||||||
Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section.
|
Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section.
|
||||||
|
|
@ -94,14 +92,14 @@ Since the clear value will be re-used by the offscreen (3 attachments) and the p
|
||||||
```
|
```
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
|
clearValues[1].color = {{0, 0, 0, 0}};
|
||||||
clearValues[2].setDepthStencil({1.0f, 0});
|
clearValues[2].depthStencil = {1.0f, 0};
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fragment shader
|
### Fragment shader
|
||||||
|
|
@ -138,12 +136,9 @@ The shader takes two inputs, the G-Buffer and the TLAS, and has one output, the
|
||||||
//
|
//
|
||||||
void HelloVulkan::createCompDescriptors()
|
void HelloVulkan::createCompDescriptors()
|
||||||
{
|
{
|
||||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
|
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
|
||||||
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
|
||||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
|
m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
|
||||||
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
|
||||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
|
|
||||||
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
|
|
||||||
|
|
||||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||||
|
|
@ -162,15 +157,17 @@ when resizing the window and the G-Buffer and AO buffer are resized.
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateCompDescriptors()
|
void HelloVulkan::updateCompDescriptors()
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
|
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
|
||||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
|
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
|
||||||
|
|
||||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
|
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||||
|
descASInfo.accelerationStructureCount = 1;
|
||||||
|
descASInfo.pAccelerationStructures = &tlas;
|
||||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
||||||
|
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -200,40 +197,38 @@ struct AoControl
|
||||||
The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)).
|
The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)).
|
||||||
This sets the current frame index, which allows us to accumulate AO samples over time.
|
This sets the current frame index, which allows us to accumulate AO samples over time.
|
||||||
|
|
||||||
Next, we are adding a `vk::ImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
||||||
// before the compute shader is using the buffer
|
// before the compute shader is using the buffer
|
||||||
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
|
VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||||
vk::ImageMemoryBarrier imgMemBarrier;
|
VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||||
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
imgMemBarrier.setImage(m_gBuffer.image);
|
imgMemBarrier.image = m_gBuffer.image;
|
||||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
imgMemBarrier.setSubresourceRange(range);
|
imgMemBarrier.subresourceRange = range;
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
|
|
||||||
vk::PipelineStageFlagBits::eComputeShader,
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Folowing is the call to dispatch the compute shader
|
Folowing is the call to dispatch the compute shader
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Preparing for the compute shader
|
// Preparing for the compute shader
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||||
{m_compDescSet}, {});
|
|
||||||
|
|
||||||
// Sending the push constant information
|
// Sending the push constant information
|
||||||
aoControl.frame = m_frame;
|
aoControl.frame = m_frame;
|
||||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
|
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
|
||||||
sizeof(AoControl), &aoControl);
|
|
||||||
|
|
||||||
// Dispatching the shader
|
// Dispatching the shader
|
||||||
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
|
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||||
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Then we are adding a final barrier to make sure the compute shader is done
|
Then we are adding a final barrier to make sure the compute shader is done
|
||||||
|
|
@ -242,13 +237,9 @@ writing the AO so that the fragment shader (post) can use it.
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Adding a barrier to be sure the compute shader has finished
|
// Adding a barrier to be sure the compute shader has finished
|
||||||
// writing to the AO buffer before the post shader is using it
|
// writing to the AO buffer before the post shader is using it
|
||||||
imgMemBarrier.setImage(m_aoBuffer.image);
|
imgMemBarrier.image = m_aoBuffer.image;
|
||||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||||
imgMemBarrier.setSubresourceRange(range);
|
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
|
|
||||||
vk::PipelineStageFlagBits::eFragmentShader,
|
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## Update Frame
|
## Update Frame
|
||||||
|
|
@ -450,9 +441,9 @@ We have also have added `AoControl aoControl;` somwhere in main() and passing th
|
||||||
~~~~
|
~~~~
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
helloVk.runCompute(cmdBuf, aoControl);
|
helloVk.runCompute(cmdBuf, aoControl);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
@ -463,10 +454,10 @@ The post shader will combine the result of the fragment (color) and the result o
|
||||||
In `createPostDescriptor` we will need to add the descriptor
|
In `createPostDescriptor` we will need to add the descriptor
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
And the equivalent in `updatePostDescriptorSet`
|
And the equivalent in `updatePostDescriptorSet()`
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
||||||
|
|
|
||||||
|
|
@ -19,25 +19,25 @@
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "obj_loader.h"
|
#include "obj_loader.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
#include "hello_vulkan.h"
|
||||||
|
#include "nvh/alignment.hpp"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
|
#include "nvh/fileoperations.hpp"
|
||||||
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/images_vk.hpp"
|
#include "nvvk/images_vk.hpp"
|
||||||
#include "nvvk/pipeline_vk.hpp"
|
#include "nvvk/pipeline_vk.hpp"
|
||||||
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
#include "nvvk/renderpasses_vk.hpp"
|
||||||
#include "nvvk/shaders_vk.hpp"
|
#include "nvvk/shaders_vk.hpp"
|
||||||
|
|
||||||
|
extern std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// Holding the camera matrices
|
// Holding the camera matrices
|
||||||
struct CameraMatrices
|
struct CameraMatrices
|
||||||
|
|
@ -45,21 +45,17 @@ struct CameraMatrices
|
||||||
nvmath::mat4f view;
|
nvmath::mat4f view;
|
||||||
nvmath::mat4f proj;
|
nvmath::mat4f proj;
|
||||||
nvmath::mat4f viewInverse;
|
nvmath::mat4f viewInverse;
|
||||||
// #VKRay
|
|
||||||
nvmath::mat4f projInverse;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Keep the handle on the device
|
// Keep the handle on the device
|
||||||
// Initialize the tool to do all our allocations: buffers, images
|
// Initialize the tool to do all our allocations: buffers, images
|
||||||
//
|
//
|
||||||
void HelloVulkan::setup(const vk::Instance& instance,
|
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily)
|
|
||||||
{
|
{
|
||||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||||
m_alloc.init(device, physicalDevice);
|
m_alloc.init(instance, device, physicalDevice);
|
||||||
m_debug.setup(m_device);
|
m_debug.setup(m_device);
|
||||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +63,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Called at each frame to update the camera matrix
|
// Called at each frame to update the camera matrix
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
// Prepare new UBO contents on host.
|
// Prepare new UBO contents on host.
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||||
|
|
@ -76,37 +72,35 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||||
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
||||||
// #VKRay
|
|
||||||
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
|
||||||
|
|
||||||
// UBO on the device, and what stages access it.
|
// UBO on the device, and what stages access it.
|
||||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||||
auto uboUsageStages =
|
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||||
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
|
|
||||||
|
|
||||||
// Ensure that the modified UBO is not visible to previous frames.
|
// Ensure that the modified UBO is not visible to previous frames.
|
||||||
vk::BufferMemoryBarrier beforeBarrier;
|
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
beforeBarrier.setBuffer(deviceUBO);
|
beforeBarrier.buffer = deviceUBO;
|
||||||
beforeBarrier.setOffset(0);
|
beforeBarrier.offset = 0;
|
||||||
beforeBarrier.setSize(sizeof hostUBO);
|
beforeBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||||
// buffer so it is okay to deallocate when the function returns).
|
// buffer so it is okay to deallocate when the function returns).
|
||||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||||
|
|
||||||
// Making sure the updated UBO will be visible.
|
// Making sure the updated UBO will be visible.
|
||||||
vk::BufferMemoryBarrier afterBarrier;
|
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
afterBarrier.setBuffer(deviceUBO);
|
afterBarrier.buffer = deviceUBO;
|
||||||
afterBarrier.setOffset(0);
|
afterBarrier.offset = 0;
|
||||||
afterBarrier.setSize(sizeof hostUBO);
|
afterBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -114,22 +108,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
//
|
//
|
||||||
void HelloVulkan::createDescriptorSetLayout()
|
void HelloVulkan::createDescriptorSetLayout()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||||
|
|
||||||
// Camera matrices (binding = 0)
|
// Camera matrices (binding = 0)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex));
|
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
// Materials (binding = 1)
|
// Materials (binding = 1)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
// Scene description (binding = 2)
|
// Scene description (binding = 2)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment));
|
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
// Textures (binding = 3)
|
// Textures (binding = 3)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment));
|
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
// Materials (binding = 4)
|
// Materials (binding = 4)
|
||||||
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
|
||||||
|
|
||||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||||
|
|
@ -142,40 +133,39 @@ void HelloVulkan::createDescriptorSetLayout()
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateDescriptorSet()
|
void HelloVulkan::updateDescriptorSet()
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
|
|
||||||
// Camera matrices and scene description
|
// Camera matrices and scene description
|
||||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||||
|
|
||||||
// All material buffers, 1 buffer per OBJ
|
// All material buffers, 1 buffer per OBJ
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiVert;
|
std::vector<VkDescriptorBufferInfo> dbiVert;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiIdx;
|
std::vector<VkDescriptorBufferInfo> dbiIdx;
|
||||||
for(auto& obj : m_objModel)
|
for(auto& m : m_objModel)
|
||||||
{
|
{
|
||||||
dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
}
|
}
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||||
|
|
||||||
// All texture samplers
|
// All texture samplers
|
||||||
std::vector<vk::DescriptorImageInfo> diit;
|
std::vector<VkDescriptorImageInfo> diit;
|
||||||
for(auto& texture : m_textures)
|
for(auto& texture : m_textures)
|
||||||
{
|
{
|
||||||
diit.emplace_back(texture.descriptor);
|
diit.emplace_back(texture.descriptor);
|
||||||
}
|
}
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||||
|
|
||||||
|
|
||||||
// Writing the information
|
// Writing the information
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -183,37 +173,34 @@ void HelloVulkan::updateDescriptorSet()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createGraphicsPipeline()
|
void HelloVulkan::createGraphicsPipeline()
|
||||||
{
|
{
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
|
||||||
|
|
||||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
sizeof(ObjPushConstant)};
|
|
||||||
|
|
||||||
// Creating the Pipeline Layout
|
// Creating the Pipeline Layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
createInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
createInfo.pSetLayouts = &m_descSetLayout;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
createInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
|
||||||
|
|
||||||
// Creating the Pipeline
|
// Creating the Pipeline
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
std::vector<std::string> paths = defaultSearchPaths;
|
||||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
||||||
gpb.depthStencilState.depthTestEnable = true;
|
gpb.depthStencilState.depthTestEnable = true;
|
||||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||||
gpb.addAttributeDescriptions({
|
gpb.addAttributeDescriptions({
|
||||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||||
});
|
});
|
||||||
|
|
||||||
vk::PipelineColorBlendAttachmentState res;
|
VkPipelineColorBlendAttachmentState res{};
|
||||||
res.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
|
res.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
|
res.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
gpb.addBlendAttachmentState(res);
|
gpb.addBlendAttachmentState(res);
|
||||||
|
|
||||||
m_graphicsPipeline = gpb.createPipeline();
|
m_graphicsPipeline = gpb.createPipeline();
|
||||||
|
|
@ -225,8 +212,6 @@ void HelloVulkan::createGraphicsPipeline()
|
||||||
//
|
//
|
||||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
|
|
||||||
LOGI("Loading File: %s \n", filename.c_str());
|
LOGI("Loading File: %s \n", filename.c_str());
|
||||||
ObjLoader loader;
|
ObjLoader loader;
|
||||||
loader.loadModel(filename);
|
loader.loadModel(filename);
|
||||||
|
|
@ -251,17 +236,13 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
|
|
||||||
// Create the buffers on Device and copy vertices, indices and materials
|
// Create the buffers on Device and copy vertices, indices and materials
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||||
model.vertexBuffer =
|
VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
|
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||||
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
|
||||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
|
||||||
model.indexBuffer =
|
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_indices,
|
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
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
|
// Creates all textures found
|
||||||
createTextureImages(cmdBuf, loader.m_textures);
|
createTextureImages(cmdBuf, loader.m_textures);
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
cmdBufGet.submitAndWait(cmdBuf);
|
||||||
|
|
@ -277,17 +258,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
m_objInstance.emplace_back(instance);
|
m_objInstance.emplace_back(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating the uniform buffer holding the camera matrices
|
// Creating the uniform buffer holding the camera matrices
|
||||||
// - Buffer is host visible
|
// - Buffer is host visible
|
||||||
//
|
//
|
||||||
void HelloVulkan::createUniformBuffer()
|
void HelloVulkan::createUniformBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
using vkMP = vk::MemoryPropertyFlagBits;
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
|
||||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
|
||||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
|
||||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,11 +278,10 @@ void HelloVulkan::createUniformBuffer()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createSceneDescriptionBuffer()
|
void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
cmdGen.submitAndWait(cmdBuf);
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
m_alloc.finalizeAndReleaseStaging();
|
||||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||||
|
|
@ -312,15 +290,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating all textures and samplers
|
// Creating all textures and samplers
|
||||||
//
|
//
|
||||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
||||||
const std::vector<std::string>& textures)
|
|
||||||
{
|
{
|
||||||
using vkIU = vk::ImageUsageFlagBits;
|
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
samplerCreateInfo.maxLod = FLT_MAX;
|
||||||
|
|
||||||
vk::SamplerCreateInfo samplerCreateInfo{
|
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
|
||||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
|
||||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
|
||||||
|
|
||||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||||
if(textures.empty() && m_textures.empty())
|
if(textures.empty() && m_textures.empty())
|
||||||
|
|
@ -328,18 +306,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
nvvk::Texture texture;
|
nvvk::Texture texture;
|
||||||
|
|
||||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||||
vk::DeviceSize bufferSize = sizeof(color);
|
VkDeviceSize bufferSize = sizeof(color);
|
||||||
auto imgSize = vk::Extent2D(1, 1);
|
auto imgSize = VkExtent2D{1, 1};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||||
|
|
||||||
// Creating the VKImage
|
// Creating the dummy texture
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -352,8 +329,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
o << "media/textures/" << texture;
|
o << "media/textures/" << texture;
|
||||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||||
|
|
||||||
stbi_uc* stbi_pixels =
|
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
||||||
|
|
||||||
|
|
@ -366,15 +342,14 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||||
vk::ImageViewCreateInfo ivInfo =
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
|
|
@ -390,10 +365,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
//
|
//
|
||||||
void HelloVulkan::destroyResources()
|
void HelloVulkan::destroyResources()
|
||||||
{
|
{
|
||||||
m_device.destroy(m_graphicsPipeline);
|
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||||
m_device.destroy(m_pipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
m_device.destroy(m_descPool);
|
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||||
m_device.destroy(m_descSetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||||
|
|
||||||
m_alloc.destroy(m_cameraMat);
|
m_alloc.destroy(m_cameraMat);
|
||||||
m_alloc.destroy(m_sceneDesc);
|
m_alloc.destroy(m_sceneDesc);
|
||||||
|
|
||||||
|
|
@ -411,22 +387,22 @@ void HelloVulkan::destroyResources()
|
||||||
}
|
}
|
||||||
|
|
||||||
//#Post
|
//#Post
|
||||||
m_device.destroy(m_postPipeline);
|
|
||||||
m_device.destroy(m_postPipelineLayout);
|
|
||||||
m_device.destroy(m_postDescPool);
|
|
||||||
m_device.destroy(m_postDescSetLayout);
|
|
||||||
m_alloc.destroy(m_offscreenColor);
|
m_alloc.destroy(m_offscreenColor);
|
||||||
m_alloc.destroy(m_gBuffer);
|
m_alloc.destroy(m_gBuffer);
|
||||||
m_alloc.destroy(m_aoBuffer);
|
m_alloc.destroy(m_aoBuffer);
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
m_alloc.destroy(m_offscreenDepth);
|
||||||
m_device.destroy(m_offscreenRenderPass);
|
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
||||||
m_device.destroy(m_offscreenFramebuffer);
|
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
||||||
|
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
||||||
|
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
||||||
|
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||||
|
|
||||||
// Compute
|
// Compute
|
||||||
m_device.destroy(m_compDescPool);
|
vkDestroyPipeline(m_device, m_compPipeline, nullptr);
|
||||||
m_device.destroy(m_compDescSetLayout);
|
vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr);
|
||||||
m_device.destroy(m_compPipeline);
|
vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr);
|
||||||
m_device.destroy(m_compPipelineLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
m_rtBuilder.destroy();
|
m_rtBuilder.destroy();
|
||||||
|
|
@ -436,32 +412,31 @@ void HelloVulkan::destroyResources()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Drawing the scene in raster mode
|
// Drawing the scene in raster mode
|
||||||
//
|
//
|
||||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
using vkPBP = vk::PipelineBindPoint;
|
VkDeviceSize offset{0};
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
vk::DeviceSize offset{0};
|
|
||||||
|
|
||||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||||
|
|
||||||
// Dynamic Viewport
|
// Dynamic Viewport
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
setViewport(cmdBuf);
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
|
||||||
|
|
||||||
// Drawing all triangles
|
// Drawing all triangles
|
||||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& inst = m_objInstance[i];
|
auto& inst = m_objInstance[i];
|
||||||
auto& model = m_objModel[inst.objIndex];
|
auto& model = m_objModel[inst.objIndex];
|
||||||
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
||||||
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
m_pushConstant);
|
|
||||||
|
|
||||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
sizeof(ObjPushConstant), &m_pushConstant);
|
||||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||||
|
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -491,64 +466,62 @@ void HelloVulkan::createOffscreenRender()
|
||||||
m_alloc.destroy(m_aoBuffer);
|
m_alloc.destroy(m_aoBuffer);
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
m_alloc.destroy(m_offscreenDepth);
|
||||||
|
|
||||||
|
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
|
||||||
// Creating the color image
|
// Creating the color image
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
| vk::ImageUsageFlagBits::eSampled
|
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
||||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
m_debug.setObjectName(m_offscreenColor.image, "offscreen");
|
m_debug.setObjectName(m_offscreenColor.image, "offscreen");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
| vk::ImageUsageFlagBits::eSampled
|
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||||
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ambient occlusion result (r32)
|
// The ambient occlusion result (r32)
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
| vk::ImageUsageFlagBits::eSampled
|
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||||
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creating the depth buffer
|
// Creating the depth buffer
|
||||||
auto depthCreateInfo =
|
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
|
|
||||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
|
||||||
{
|
{
|
||||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
||||||
|
|
||||||
vk::ImageViewCreateInfo depthStencilView;
|
|
||||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||||
depthStencilView.setFormat(m_offscreenDepthFormat);
|
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
depthStencilView.format = m_offscreenDepthFormat;
|
||||||
depthStencilView.setImage(image.image);
|
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||||
|
depthStencilView.image = image.image;
|
||||||
|
|
||||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
||||||
}
|
}
|
||||||
|
|
@ -557,15 +530,11 @@ void HelloVulkan::createOffscreenRender()
|
||||||
{
|
{
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
vk::ImageLayout::eGeneral);
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
vk::ImageLayout::eGeneral);
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, vk::ImageLayout::eUndefined,
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
vk::ImageLayout::eGeneral);
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
|
|
||||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
|
||||||
vk::ImageAspectFlagBits::eDepth);
|
|
||||||
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
genCmdBuf.submitAndWait(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -574,26 +543,23 @@ void HelloVulkan::createOffscreenRender()
|
||||||
if(!m_offscreenRenderPass)
|
if(!m_offscreenRenderPass)
|
||||||
{
|
{
|
||||||
m_offscreenRenderPass =
|
m_offscreenRenderPass =
|
||||||
nvvk::createRenderPass(m_device,
|
nvvk::createRenderPass(m_device, {m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
|
||||||
{m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
|
m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
m_offscreenDepthFormat, 1, true, true, vk::ImageLayout::eGeneral,
|
|
||||||
vk::ImageLayout::eGeneral);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating the frame buffer for offscreen
|
// Creating the frame buffer for offscreen
|
||||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_gBuffer.descriptor.imageView,
|
||||||
m_gBuffer.descriptor.imageView,
|
|
||||||
m_offscreenDepth.descriptor.imageView};
|
m_offscreenDepth.descriptor.imageView};
|
||||||
|
|
||||||
m_device.destroy(m_offscreenFramebuffer);
|
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||||
vk::FramebufferCreateInfo info;
|
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||||
info.setRenderPass(m_offscreenRenderPass);
|
info.renderPass = m_offscreenRenderPass;
|
||||||
info.setAttachmentCount(static_cast<int>(attachments.size()));
|
info.attachmentCount = static_cast<int>(attachments.size());
|
||||||
info.setPAttachments(attachments.data());
|
info.pAttachments = attachments.data();
|
||||||
info.setWidth(m_size.width);
|
info.width = m_size.width;
|
||||||
info.setHeight(m_size.height);
|
info.height = m_size.height;
|
||||||
info.setLayers(1);
|
info.layers = 1;
|
||||||
m_offscreenFramebuffer = m_device.createFramebuffer(info);
|
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -602,25 +568,22 @@ void HelloVulkan::createOffscreenRender()
|
||||||
void HelloVulkan::createPostPipeline()
|
void HelloVulkan::createPostPipeline()
|
||||||
{
|
{
|
||||||
// Push constants in the fragment shader
|
// Push constants in the fragment shader
|
||||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||||
|
|
||||||
// Creating the pipeline layout
|
// Creating the pipeline layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
createInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout);
|
createInfo.pSetLayouts = &m_postDescSetLayout;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
createInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
||||||
|
|
||||||
|
|
||||||
// Pipeline: completely generic, no vertices
|
// Pipeline: completely generic, no vertices
|
||||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
|
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
||||||
m_renderPass);
|
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
true),
|
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||||
vk::ShaderStageFlagBits::eVertex);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
|
||||||
vk::ShaderStageFlagBits::eFragment);
|
|
||||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
|
||||||
m_postPipeline = pipelineGenerator.createPipeline();
|
m_postPipeline = pipelineGenerator.createPipeline();
|
||||||
m_debug.setObjectName(m_postPipeline, "post");
|
m_debug.setObjectName(m_postPipeline, "post");
|
||||||
}
|
}
|
||||||
|
|
@ -631,12 +594,8 @@ void HelloVulkan::createPostPipeline()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createPostDescriptor()
|
void HelloVulkan::createPostDescriptor()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
using vkDT = vk::DescriptorType;
|
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
|
|
||||||
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
|
||||||
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
|
||||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
||||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
||||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
||||||
|
|
@ -647,36 +606,32 @@ void HelloVulkan::createPostDescriptor()
|
||||||
//
|
//
|
||||||
void HelloVulkan::updatePostDescriptorSet()
|
void HelloVulkan::updatePostDescriptorSet()
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
writes.emplace_back(
|
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
|
||||||
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
|
|
||||||
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Draw a full screen quad with the attached image
|
// Draw a full screen quad with the attached image
|
||||||
//
|
//
|
||||||
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
||||||
{
|
{
|
||||||
m_debug.beginLabel(cmdBuf, "Post");
|
m_debug.beginLabel(cmdBuf, "Post");
|
||||||
|
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
setViewport(cmdBuf);
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
|
||||||
|
|
||||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
||||||
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0,
|
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||||
aspectRatio);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline);
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0,
|
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||||
m_postDescSet, {});
|
|
||||||
cmdBuf.draw(3, 1, 0, 0);
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Raytracing, creation of BLAS and TLAS
|
//////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -685,45 +640,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
||||||
void HelloVulkan::initRayTracing()
|
void HelloVulkan::initRayTracing()
|
||||||
{
|
{
|
||||||
// Requesting ray tracing properties
|
// Requesting ray tracing properties
|
||||||
auto properties =
|
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
prop2.pNext = &m_rtProperties;
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
|
||||||
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
|
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS
|
// Convert an OBJ model into the ray tracing geometry used to build the BLAS
|
||||||
//
|
//
|
||||||
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
||||||
{
|
{
|
||||||
// Building part
|
// BLAS builder requires raw device addresses.
|
||||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
info.buffer = model.vertexBuffer.buffer;
|
||||||
|
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
info.buffer = model.indexBuffer.buffer;
|
||||||
|
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
|
||||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
uint32_t maxPrimitiveCount = model.nbIndices / 3;
|
||||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
|
||||||
triangles.setVertexData(vertexAddress);
|
|
||||||
triangles.setVertexStride(sizeof(VertexObj));
|
|
||||||
triangles.setIndexType(vk::IndexType::eUint32);
|
|
||||||
triangles.setIndexData(indexAddress);
|
|
||||||
triangles.setTransformData({});
|
|
||||||
triangles.setMaxVertex(model.nbVertices);
|
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
// Describe buffer as array of VertexObj.
|
||||||
vk::AccelerationStructureGeometryKHR asGeom;
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
|
||||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
triangles.vertexData.deviceAddress = vertexAddress;
|
||||||
asGeom.geometry.setTriangles(triangles);
|
triangles.vertexStride = sizeof(VertexObj);
|
||||||
|
// Describe index data (32-bit unsigned int)
|
||||||
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
|
triangles.indexData.deviceAddress = indexAddress;
|
||||||
|
// Indicate identity transform by setting transformData to null device pointer.
|
||||||
|
//triangles.transformData = {};
|
||||||
|
triangles.maxVertex = model.nbVertices;
|
||||||
|
|
||||||
// The primitive itself
|
// Identify the above data as containing opaque triangles.
|
||||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
offset.setFirstVertex(0);
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||||
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
|
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||||
offset.setPrimitiveOffset(0);
|
asGeom.geometry.triangles = triangles;
|
||||||
offset.setTransformOffset(0);
|
|
||||||
|
|
||||||
// Our blas is only one geometry, but could be made of many geometries
|
// The entire array will be used to build the BLAS.
|
||||||
|
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||||
|
offset.firstVertex = 0;
|
||||||
|
offset.primitiveCount = maxPrimitiveCount;
|
||||||
|
offset.primitiveOffset = 0;
|
||||||
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
|
// Our blas is made from only one geometry, but could be made of many geometries
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||||
input.asGeometry.emplace_back(asGeom);
|
input.asGeometry.emplace_back(asGeom);
|
||||||
input.asBuildOffsetInfo.emplace_back(offset);
|
input.asBuildOffsetInfo.emplace_back(offset);
|
||||||
|
|
@ -746,7 +709,7 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
// We could add more geometry in each BLAS, but we add only one for now
|
// We could add more geometry in each BLAS, but we add only one for now
|
||||||
allBlas.emplace_back(blas);
|
allBlas.emplace_back(blas);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HelloVulkan::createTopLevelAS()
|
void HelloVulkan::createTopLevelAS()
|
||||||
|
|
@ -763,7 +726,7 @@ void HelloVulkan::createTopLevelAS()
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
tlas.emplace_back(rayInst);
|
tlas.emplace_back(rayInst);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -776,12 +739,9 @@ void HelloVulkan::createTopLevelAS()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createCompDescriptors()
|
void HelloVulkan::createCompDescriptors()
|
||||||
{
|
{
|
||||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
|
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
|
||||||
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
|
||||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
|
m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
|
||||||
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
|
||||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
|
|
||||||
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
|
|
||||||
|
|
||||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||||
|
|
@ -793,15 +753,17 @@ void HelloVulkan::createCompDescriptors()
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateCompDescriptors()
|
void HelloVulkan::updateCompDescriptors()
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
|
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
|
||||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
|
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
|
||||||
|
|
||||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
|
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||||
|
descASInfo.accelerationStructureCount = 1;
|
||||||
|
descASInfo.pAccelerationStructures = &tlas;
|
||||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
||||||
|
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -810,24 +772,29 @@ void HelloVulkan::updateCompDescriptors()
|
||||||
void HelloVulkan::createCompPipelines()
|
void HelloVulkan::createCompPipelines()
|
||||||
{
|
{
|
||||||
// pushing time
|
// pushing time
|
||||||
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(AoControl)};
|
VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl)};
|
||||||
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants};
|
VkPipelineLayoutCreateInfo plCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
m_compPipelineLayout = m_device.createPipelineLayout(layout_info);
|
plCreateInfo.setLayoutCount = 1;
|
||||||
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
|
plCreateInfo.pSetLayouts = &m_compDescSetLayout;
|
||||||
|
plCreateInfo.pushConstantRangeCount = 1;
|
||||||
|
plCreateInfo.pPushConstantRanges = &push_constants;
|
||||||
|
vkCreatePipelineLayout(m_device, &plCreateInfo, nullptr, &m_compPipelineLayout);
|
||||||
|
|
||||||
computePipelineCreateInfo.stage =
|
VkComputePipelineCreateInfo cpCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
|
||||||
nvvk::createShaderStageInfo(m_device,
|
cpCreateInfo.layout = m_compPipelineLayout;
|
||||||
nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
|
cpCreateInfo.stage = nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
|
||||||
VK_SHADER_STAGE_COMPUTE_BIT);
|
VK_SHADER_STAGE_COMPUTE_BIT);
|
||||||
m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo).value;
|
|
||||||
m_device.destroy(computePipelineCreateInfo.stage.module);
|
vkCreateComputePipelines(m_device, {}, 1, &cpCreateInfo, nullptr, &m_compPipeline);
|
||||||
|
|
||||||
|
vkDestroyShaderModule(m_device, cpCreateInfo.stage.module, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Running compute shader
|
// Running compute shader
|
||||||
//
|
//
|
||||||
#define GROUP_SIZE 16 // Same group size as in compute shader
|
#define GROUP_SIZE 16 // Same group size as in compute shader
|
||||||
void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
|
void HelloVulkan::runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl)
|
||||||
{
|
{
|
||||||
updateFrame();
|
updateFrame();
|
||||||
|
|
||||||
|
|
@ -839,43 +806,38 @@ void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
|
||||||
|
|
||||||
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
||||||
// before the compute shader is using the buffer
|
// before the compute shader is using the buffer
|
||||||
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
|
VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||||
vk::ImageMemoryBarrier imgMemBarrier;
|
VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||||
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
imgMemBarrier.setImage(m_gBuffer.image);
|
imgMemBarrier.image = m_gBuffer.image;
|
||||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
imgMemBarrier.setSubresourceRange(range);
|
imgMemBarrier.subresourceRange = range;
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
|
|
||||||
vk::PipelineStageFlagBits::eComputeShader,
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||||
|
|
||||||
|
|
||||||
// Preparing for the compute shader
|
// Preparing for the compute shader
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||||
{m_compDescSet}, {});
|
|
||||||
|
|
||||||
// Sending the push constant information
|
// Sending the push constant information
|
||||||
aoControl.frame = m_frame;
|
aoControl.frame = m_frame;
|
||||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
|
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
|
||||||
sizeof(AoControl), &aoControl);
|
|
||||||
|
|
||||||
// Dispatching the shader
|
// Dispatching the shader
|
||||||
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
|
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||||
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
|
||||||
|
|
||||||
|
|
||||||
// Adding a barrier to be sure the compute shader has finished
|
// Adding a barrier to be sure the compute shader has finished
|
||||||
// writing to the AO buffer before the post shader is using it
|
// writing to the AO buffer before the post shader is using it
|
||||||
imgMemBarrier.setImage(m_aoBuffer.image);
|
imgMemBarrier.image = m_aoBuffer.image;
|
||||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||||
imgMemBarrier.setSubresourceRange(range);
|
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
|
|
||||||
vk::PipelineStageFlagBits::eFragmentShader,
|
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -46,25 +46,21 @@ struct AoControl
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -89,7 +85,7 @@ public:
|
||||||
// Information pushed at each draw call
|
// Information pushed at each draw call
|
||||||
struct ObjPushConstant
|
struct ObjPushConstant
|
||||||
{
|
{
|
||||||
nvmath::vec3f lightPosition{3.5f, 8.f, 5.f};
|
nvmath::vec3f lightPosition{10.f, 15.f, 8.f};
|
||||||
int instanceId{0}; // To retrieve the transformation matrix
|
int instanceId{0}; // To retrieve the transformation matrix
|
||||||
float lightIntensity{100.f};
|
float lightIntensity{100.f};
|
||||||
int lightType{0}; // 0: point, 1: infinite
|
int lightType{0}; // 0: point, 1: infinite
|
||||||
|
|
@ -101,41 +97,43 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
nvvk::Texture m_offscreenColor;
|
nvvk::Texture m_offscreenColor;
|
||||||
|
nvvk::Texture m_offscreenDepth;
|
||||||
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
nvvk::Texture m_gBuffer;
|
nvvk::Texture m_gBuffer;
|
||||||
nvvk::Texture m_aoBuffer;
|
nvvk::Texture m_aoBuffer;
|
||||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
|
||||||
nvvk::Texture m_offscreenDepth;
|
|
||||||
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
|
|
||||||
|
|
||||||
// #Tuto_rayquery
|
// #Tuto_rayquery
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -143,7 +141,8 @@ public:
|
||||||
void createBottomLevelAS();
|
void createBottomLevelAS();
|
||||||
void createTopLevelAS();
|
void createTopLevelAS();
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
|
||||||
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -151,14 +150,14 @@ public:
|
||||||
void createCompDescriptors();
|
void createCompDescriptors();
|
||||||
void updateCompDescriptors();
|
void updateCompDescriptors();
|
||||||
void createCompPipelines();
|
void createCompPipelines();
|
||||||
void runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl);
|
void runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_compDescPool;
|
VkDescriptorPool m_compDescPool;
|
||||||
vk::DescriptorSetLayout m_compDescSetLayout;
|
VkDescriptorSetLayout m_compDescSetLayout;
|
||||||
vk::DescriptorSet m_compDescSet;
|
VkDescriptorSet m_compDescSet;
|
||||||
vk::Pipeline m_compPipeline;
|
VkPipeline m_compPipeline;
|
||||||
vk::PipelineLayout m_compPipelineLayout;
|
VkPipelineLayout m_compPipelineLayout;
|
||||||
|
|
||||||
// #Tuto_jitter_cam
|
// #Tuto_jitter_cam
|
||||||
void updateFrame();
|
void updateFrame();
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,6 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
|
|
@ -36,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -48,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -75,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -89,8 +87,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -117,9 +114,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -129,19 +126,20 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures;
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeatures);
|
||||||
&accelFeatures);
|
VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR};
|
||||||
vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures;
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
|
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
|
||||||
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
vkctx.initInstance(contextInfo);
|
vkctx.initInstance(contextInfo);
|
||||||
|
|
@ -151,16 +149,14 @@ int main(int argc, char** argv)
|
||||||
// Use a compatible device
|
// Use a compatible device
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||||
|
|
||||||
|
|
||||||
// Create example
|
// Create example
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -241,8 +237,7 @@ int main(int argc, char** argv)
|
||||||
helloVk.resetFrame();
|
helloVk.resetFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -252,65 +247,66 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 3> clearValues;
|
std::array<VkClearValue, 3> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
|
||||||
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
|
clearValues[1].color = {{0, 0, 0, 0}};
|
||||||
clearValues[2].setDepthStencil({1.0f, 0});
|
clearValues[2].depthStencil = {1.0f, 0};
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(3);
|
offscreenRenderPassBeginInfo.clearValueCount = (uint32_t)clearValues.size();
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
helloVk.runCompute(cmdBuf, aoControl);
|
helloVk.runCompute(cmdBuf, aoControl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
catch(const std::system_error& e)
|
catch(const std::system_error& e)
|
||||||
{
|
{
|
||||||
if(e.code() == vk::Result::eErrorDeviceLost)
|
if(e.code().value() == VK_ERROR_DEVICE_LOST)
|
||||||
{
|
{
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
|
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
|
||||||
|
|
@ -322,10 +318,10 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
|
|
@ -63,39 +63,50 @@ executeCallableEXT(pushC.lightType, 0);
|
||||||
In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit shader, we will add
|
In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit shader, we will add
|
||||||
3 callable shaders, for each type of light.
|
3 callable shaders, for each type of light.
|
||||||
|
|
||||||
|
First create the shader modules
|
||||||
|
~~~~ C++
|
||||||
|
enum StageIndices
|
||||||
|
{
|
||||||
|
eRaygen,
|
||||||
|
eMiss,
|
||||||
|
eMiss2,
|
||||||
|
eClosestHit,
|
||||||
|
eCall0,
|
||||||
|
eCall1,
|
||||||
|
eCall2,
|
||||||
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
||||||
|
// Call0
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||||
|
stages[eCall0] = stage;
|
||||||
|
// Call1
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||||
|
stages[eCall1] = stage;
|
||||||
|
// Call2
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||||
|
stages[eCall2] = stage;
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Then 3 groups of callable shaders and the stages that goes with it.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Callable shaders
|
// Callable shaders
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
group.generalShader = eCall0;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
vk::ShaderModule call0 =
|
group.generalShader = eCall1;
|
||||||
nvvk::createShaderModule(m_device,
|
m_rtShaderGroups.push_back(group);
|
||||||
nvh::loadFile("shaders/light_point.rcall.spv", true, paths));
|
group.generalShader = eCall2;
|
||||||
vk::ShaderModule call1 =
|
m_rtShaderGroups.push_back(group);
|
||||||
nvvk::createShaderModule(m_device,
|
|
||||||
nvh::loadFile("shaders/light_spot.rcall.spv", true, paths));
|
|
||||||
vk::ShaderModule call2 =
|
|
||||||
nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths));
|
|
||||||
|
|
||||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
|
|
||||||
m_rtShaderGroups.push_back(callGroup);
|
|
||||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
|
|
||||||
m_rtShaderGroups.push_back(callGroup);
|
|
||||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
|
|
||||||
m_rtShaderGroups.push_back(callGroup);
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
And at the end of the function, delete the shaders.
|
|
||||||
|
|
||||||
~~~~ C++
|
|
||||||
m_device.destroy(call0);
|
|
||||||
m_device.destroy(call1);
|
|
||||||
m_device.destroy(call2);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
#### Shaders
|
#### Shaders
|
||||||
|
|
||||||
|
|
@ -106,29 +117,44 @@ Here are the source of all shaders
|
||||||
* [light_inf.rcall](shaders/light_inf.rcall)
|
* [light_inf.rcall](shaders/light_inf.rcall)
|
||||||
|
|
||||||
|
|
||||||
### Passing Callable to traceRaysKHR
|
### Shading Binding Table
|
||||||
|
|
||||||
|
In this example, we will use the `nvvk::SBTWrapper`. It is using the information to create the ray tracing pipeline, to
|
||||||
|
create the buffers for the shading binding table.
|
||||||
|
|
||||||
|
In the `hello_vulkan.h` header, include the wrapper and add a new member.
|
||||||
|
|
||||||
|
~~~~C
|
||||||
|
#include "nvvk/sbtwrapper_vk.hpp"
|
||||||
|
...
|
||||||
|
nvvk::SBTWrapper m_sbtWrapper;
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
In `HelloVulkan::initRayTracing()`, initialize it the following way.
|
||||||
|
|
||||||
|
~~~~C
|
||||||
|
m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties);
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
In `HelloVulkan::createRtPipeline()`, immediately after creating the pipeline call to `vkCreateRayTracingPipelinesKHR()`,
|
||||||
|
create the SBT with the following command.
|
||||||
|
|
||||||
|
~~~~C
|
||||||
|
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Since they were added after the hit shader, we have in the SBT the following.
|
In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Since they were added after the hit shader, we have in the SBT the following.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
The SBT wrapper class give back the information we need. So instead of computing the various offsets, we can get directly the
|
||||||
Therefore, the callable starts at `4 * progSize`
|
`VkStridedDeviceAddressRegionKHR` for each group type.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
std::array<stride, 4> strideAddresses{
|
auto& regions = m_sbtWrapper.getRegions();
|
||||||
stride{sbtAddress + 0u * progSize, progSize, progSize * 1}, // raygen
|
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1);
|
||||||
stride{sbtAddress + 1u * progSize, progSize, progSize * 2}, // miss
|
|
||||||
stride{sbtAddress + 3u * progSize, progSize, progSize * 1}, // hit
|
|
||||||
stride{sbtAddress + 4u * progSize, progSize, progSize * 1}}; // callable
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Then we can call `traceRaysKHR`
|
|
||||||
|
|
||||||
~~~~ C++
|
|
||||||
cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
|
|
||||||
&strideAddresses[3], //
|
|
||||||
m_size.width, m_size.height, 1); //
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## Calling the Callable Shaders
|
## Calling the Callable Shaders
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,17 +19,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
#include "nvvk/sbtwrapper_vk.hpp"
|
#include "nvvk/sbtwrapper_vk.hpp"
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Simple rasterizer of OBJ objects
|
// Simple rasterizer of OBJ objects
|
||||||
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
|
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
|
||||||
|
|
@ -37,25 +36,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -95,39 +90,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -137,19 +134,18 @@ public:
|
||||||
void createRtDescriptorSet();
|
void createRtDescriptorSet();
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,18 +23,15 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
|
#include "hello_vulkan.h"
|
||||||
#include "imgui/imgui_camera_widget.h"
|
#include "imgui/imgui_camera_widget.h"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +54,7 @@ static void onErrorCallback(int error, const char* description)
|
||||||
void renderUI(HelloVulkan& helloVk)
|
void renderUI(HelloVulkan& helloVk)
|
||||||
{
|
{
|
||||||
ImGuiH::CameraWidget();
|
ImGuiH::CameraWidget();
|
||||||
if(ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen))
|
if(ImGui::CollapsingHeader("Light"))
|
||||||
{
|
{
|
||||||
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
|
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
@ -104,8 +102,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -132,12 +129,13 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, false);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, false);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, false);
|
contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
||||||
#endif
|
#endif
|
||||||
contextInfo.addInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
|
@ -145,18 +143,16 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -171,11 +167,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -234,8 +229,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -245,27 +239,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -274,40 +269,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,10 @@ attributes, we will store the offsets information of that geometry.
|
||||||
// The following is used to find the primitive mesh information in the CHIT
|
// The following is used to find the primitive mesh information in the CHIT
|
||||||
std::vector<RtPrimitiveLookup> primLookup;
|
std::vector<RtPrimitiveLookup> primLookup;
|
||||||
for(auto& primMesh : m_gltfScene.m_primMeshes)
|
for(auto& primMesh : m_gltfScene.m_primMeshes)
|
||||||
|
{
|
||||||
primLookup.push_back({primMesh.firstIndex, primMesh.vertexOffset, primMesh.materialIndex});
|
primLookup.push_back({primMesh.firstIndex, primMesh.vertexOffset, primMesh.materialIndex});
|
||||||
m_rtPrimLookup =
|
}
|
||||||
m_alloc.createBuffer(cmdBuf, primLookup, vk::BufferUsageFlagBits::eStorageBuffer);
|
m_rtPrimLookup = m_alloc.createBuffer(cmdBuf, primLookup, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -145,35 +146,45 @@ The function is similar, only the input is different.
|
||||||
//
|
//
|
||||||
auto HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim)
|
auto HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim)
|
||||||
{
|
{
|
||||||
// Building part
|
// BLAS builder requires raw device addresses.
|
||||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer});
|
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer});
|
info.buffer = m_vertexBuffer.buffer;
|
||||||
|
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
info.buffer = m_indexBuffer.buffer;
|
||||||
|
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
|
||||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
uint32_t maxPrimitiveCount = prim.indexCount / 3;
|
||||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
|
||||||
triangles.setVertexData(vertexAddress);
|
|
||||||
triangles.setVertexStride(sizeof(nvmath::vec3f));
|
|
||||||
triangles.setIndexType(vk::IndexType::eUint32);
|
|
||||||
triangles.setIndexData(indexAddress);
|
|
||||||
triangles.setTransformData({});
|
|
||||||
triangles.setMaxVertex(prim.vertexCount);
|
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
// Describe buffer as array of VertexObj.
|
||||||
vk::AccelerationStructureGeometryKHR asGeom;
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
|
||||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit
|
triangles.vertexData.deviceAddress = vertexAddress;
|
||||||
asGeom.geometry.setTriangles(triangles);
|
triangles.vertexStride = sizeof(nvmath::vec3f);
|
||||||
|
// Describe index data (32-bit unsigned int)
|
||||||
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
|
triangles.indexData.deviceAddress = indexAddress;
|
||||||
|
// Indicate identity transform by setting transformData to null device pointer.
|
||||||
|
//triangles.transformData = {};
|
||||||
|
triangles.maxVertex = prim.vertexCount;
|
||||||
|
|
||||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
// Identify the above data as containing opaque triangles.
|
||||||
offset.setFirstVertex(prim.vertexOffset);
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
offset.setPrimitiveCount(prim.indexCount / 3);
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||||
offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t));
|
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
|
||||||
offset.setTransformOffset(0);
|
asGeom.geometry.triangles = triangles;
|
||||||
|
|
||||||
nvvk::RaytracingBuilderKHR::Blas blas;
|
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||||
blas.asGeometry.emplace_back(asGeom);
|
offset.firstVertex = prim.vertexOffset;
|
||||||
blas.asBuildOffsetInfo.emplace_back(offset);
|
offset.primitiveCount = prim.indexCount / 3;
|
||||||
return blas;
|
offset.primitiveOffset = prim.firstIndex * sizeof(uint32_t);
|
||||||
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
|
// Our blas is made from only one geometry, but could be made of many geometries
|
||||||
|
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||||
|
input.asGeometry.emplace_back(asGeom);
|
||||||
|
input.asBuildOffsetInfo.emplace_back(offset);
|
||||||
|
|
||||||
|
return input;
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -207,11 +218,9 @@ each node, we will be pushing the instance Id (retrieve the matrix) and the mate
|
||||||
don't have a scene graph, we could loop over all drawable nodes.
|
don't have a scene graph, we could loop over all drawable nodes.
|
||||||
|
|
||||||
~~~~C
|
~~~~C
|
||||||
std::vector<vk::Buffer> vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer,
|
std::vector<VkBuffer> vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer, m_uvBuffer.buffer};
|
||||||
m_uvBuffer.buffer};
|
vkCmdBindVertexBuffers(cmdBuf, 0, static_cast<uint32_t>(vertexBuffers.size()), vertexBuffers.data(), offsets.data());
|
||||||
cmdBuf.bindVertexBuffers(0, static_cast<uint32_t>(vertexBuffers.size()), vertexBuffers.data(),
|
vkCmdBindIndexBuffer(cmdBuf, m_indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
offsets.data());
|
|
||||||
cmdBuf.bindIndexBuffer(m_indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
|
||||||
|
|
||||||
uint32_t idxNode = 0;
|
uint32_t idxNode = 0;
|
||||||
for(auto& node : m_gltfScene.m_nodes)
|
for(auto& node : m_gltfScene.m_nodes)
|
||||||
|
|
@ -220,10 +229,9 @@ don't have a scene graph, we could loop over all drawable nodes.
|
||||||
|
|
||||||
m_pushConstant.instanceId = idxNode++;
|
m_pushConstant.instanceId = idxNode++;
|
||||||
m_pushConstant.materialId = primitive.materialIndex;
|
m_pushConstant.materialId = primitive.materialIndex;
|
||||||
cmdBuf.pushConstants<ObjPushConstant>(
|
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||||
m_pipelineLayout, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0,
|
sizeof(ObjPushConstant), &m_pushConstant);
|
||||||
m_pushConstant);
|
vkCmdDrawIndexed(cmdBuf, primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0);
|
||||||
cmdBuf.drawIndexed(primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0);
|
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -234,11 +242,11 @@ In `createRtDescriptorSet()`, the only change we will add is the primitive info
|
||||||
the data when hitting a triangle.
|
the data when hitting a triangle.
|
||||||
|
|
||||||
~~~~C
|
~~~~C
|
||||||
m_rtDescSetLayoutBind.addBinding(
|
m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||||
vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eClosestHitNV | vkSS::eAnyHitNV)); // Primitive info
|
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Primitive info
|
||||||
....
|
// ...
|
||||||
vk::DescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE};
|
||||||
....
|
// ...
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &primitiveInfoDesc));
|
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &primitiveInfoDesc));
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -18,13 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvh/gltfscene.hpp"
|
#include "nvh/gltfscene.hpp"
|
||||||
|
|
@ -38,23 +37,20 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadScene(const std::string& filename);
|
void loadScene(const std::string& filename);
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf, tinygltf::Model& gltfModel);
|
void createTextureImages(const VkCommandBuffer& cmdBuf, tinygltf::Model& gltfModel);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// Structure used for retrieving the primitive information in the closest hit
|
// Structure used for retrieving the primitive information in the closest hit
|
||||||
// The gl_InstanceCustomIndexNV
|
// The gl_InstanceCustomIndexNV
|
||||||
|
|
@ -87,12 +83,12 @@ public:
|
||||||
ObjPushConstant m_pushConstant;
|
ObjPushConstant m_pushConstant;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
@ -105,20 +101,20 @@ public:
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
auto primitiveToGeometry(const nvh::GltfPrimMesh& prim);
|
auto primitiveToGeometry(const nvh::GltfPrimMesh& prim);
|
||||||
|
|
@ -128,19 +124,19 @@ public:
|
||||||
void createRtDescriptorSet();
|
void createRtDescriptorSet();
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
void updateFrame();
|
void updateFrame();
|
||||||
void resetFrame();
|
void resetFrame();
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
nvvk::SBTWrapper m_sbtWrapper;
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -87,8 +86,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -115,9 +113,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -127,20 +125,20 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||||
vk::PhysicalDeviceShaderClockFeaturesKHR clockFeature;
|
VkPhysicalDeviceShaderClockFeaturesKHR clockFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR};
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_EXTENSION_NAME, false, &clockFeature);
|
contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_EXTENSION_NAME, false, &clockFeature);
|
||||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
|
||||||
&accelFeature);
|
|
||||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
|
||||||
&rtPipelineFeature);
|
|
||||||
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -151,16 +149,14 @@ int main(int argc, char** argv)
|
||||||
// Use a compatible device
|
// Use a compatible device
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||||
|
|
||||||
|
|
||||||
// Create example
|
// Create example
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -209,6 +205,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -217,8 +214,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -228,27 +224,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -257,40 +254,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -18,13 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -36,13 +35,10 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
|
|
@ -50,8 +46,7 @@ public:
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
|
||||||
|
|
||||||
nvmath::mat4 getViewMatrix() { return CameraManip.getMatrix(); }
|
nvmath::mat4 getViewMatrix() { return CameraManip.getMatrix(); }
|
||||||
|
|
||||||
|
|
@ -62,10 +57,10 @@ public:
|
||||||
return nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, nearZ, 1000.0f);
|
return nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, nearZ, 1000.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateUniformBuffer(const vk::CommandBuffer&);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -130,39 +125,41 @@ public:
|
||||||
std::vector<Lantern> m_lanterns;
|
std::vector<Lantern> m_lanterns;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -183,7 +180,7 @@ public:
|
||||||
void createRtShaderBindingTable();
|
void createRtShaderBindingTable();
|
||||||
void createLanternIndirectBuffer();
|
void createLanternIndirectBuffer();
|
||||||
|
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
// Used to store lantern model, generated at runtime.
|
// Used to store lantern model, generated at runtime.
|
||||||
const float m_lanternModelRadius = 0.125;
|
const float m_lanternModelRadius = 0.125;
|
||||||
|
|
@ -194,21 +191,21 @@ public:
|
||||||
// Index of lantern's BLAS in the BLAS array stored in m_rtBuilder.
|
// Index of lantern's BLAS in the BLAS array stored in m_rtBuilder.
|
||||||
size_t m_lanternBlasId;
|
size_t m_lanternBlasId;
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_lanternIndirectDescPool;
|
VkDescriptorPool m_lanternIndirectDescPool;
|
||||||
vk::DescriptorSetLayout m_lanternIndirectDescSetLayout;
|
VkDescriptorSetLayout m_lanternIndirectDescSetLayout;
|
||||||
vk::DescriptorSet m_lanternIndirectDescSet;
|
VkDescriptorSet m_lanternIndirectDescSet;
|
||||||
vk::PipelineLayout m_lanternIndirectCompPipelineLayout;
|
VkPipelineLayout m_lanternIndirectCompPipelineLayout;
|
||||||
vk::Pipeline m_lanternIndirectCompPipeline;
|
VkPipeline m_lanternIndirectCompPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
|
|
||||||
// Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color,
|
// Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color,
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -74,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -88,8 +87,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -118,7 +116,7 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -128,19 +126,19 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
&accelFeature);
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
|
||||||
&rtPipelineFeature);
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||||
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
vkctx.initInstance(contextInfo);
|
vkctx.initInstance(contextInfo);
|
||||||
|
|
@ -150,16 +148,14 @@ int main(int argc, char** argv)
|
||||||
// Use a compatible device
|
// Use a compatible device
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||||
|
|
||||||
|
|
||||||
// Create example
|
// Create example
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -223,6 +219,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -231,9 +228,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -243,27 +238,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -272,40 +268,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -22,9 +22,9 @@
|
||||||
// #VKRay
|
// #VKRay
|
||||||
//
|
//
|
||||||
// Choosing the allocator to use
|
// Choosing the allocator to use
|
||||||
//#define ALLOC_DMA
|
#define ALLOC_DMA
|
||||||
//#define ALLOC_DEDICATED
|
//#define ALLOC_DEDICATED
|
||||||
#define ALLOC_VMA
|
//#define ALLOC_VMA
|
||||||
#include <nvvk/resourceallocator_vk.hpp>
|
#include <nvvk/resourceallocator_vk.hpp>
|
||||||
|
|
||||||
#if defined(ALLOC_DMA)
|
#if defined(ALLOC_DMA)
|
||||||
|
|
@ -37,7 +37,7 @@ using Allocator = nvvk::ResourceAllocatorVma;
|
||||||
using Allocator = nvvk::ResourceAllocatorDedicated;
|
using Allocator = nvvk::ResourceAllocatorDedicated;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -52,25 +52,21 @@ using Allocator = nvvk::ResourceAllocatorDedicated;
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -107,12 +103,12 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
|
|
@ -123,25 +119,26 @@ public:
|
||||||
|
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -151,25 +148,25 @@ public:
|
||||||
void createRtDescriptorSet();
|
void createRtDescriptorSet();
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
nvvk::SBTWrapper m_sbtWrapper;
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
{
|
{
|
||||||
nvmath::vec4f clearColor;
|
nvmath::vec4f clearColor;
|
||||||
nvmath::vec3f lightPosition;
|
nvmath::vec3f lightPosition;
|
||||||
float lightIntensity;
|
float lightIntensity{100.0f};
|
||||||
int lightType;
|
int lightType{0};
|
||||||
} m_rtPushConstants;
|
} m_rtPushConstants;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -35,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -57,8 +54,7 @@ struct MilliTimer
|
||||||
double elapse()
|
double elapse()
|
||||||
{
|
{
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
auto t =
|
auto t = std::chrono::duration_cast<std::chrono::microseconds>(now - startTime).count() / 1000.0;
|
||||||
std::chrono::duration_cast<std::chrono::microseconds>(now - startTime).count() / 1000.0;
|
|
||||||
startTime = now;
|
startTime = now;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
@ -75,6 +71,7 @@ struct MilliTimer
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -102,6 +99,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -116,8 +114,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -144,9 +141,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -158,17 +155,16 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -183,11 +179,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -209,8 +204,7 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back();
|
HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back();
|
||||||
|
|
||||||
float scale = fabsf(disn(gen));
|
float scale = fabsf(disn(gen));
|
||||||
nvmath::mat4f mat =
|
nvmath::mat4f mat = nvmath::translation_mat4(nvmath::vec3f{dis(gen), 2.0f + dis(gen), dis(gen)});
|
||||||
nvmath::translation_mat4(nvmath::vec3f{dis(gen), 2.0f + dis(gen), dis(gen)});
|
|
||||||
mat = mat * nvmath::rotation_mat4_x(dis(gen));
|
mat = mat * nvmath::rotation_mat4_x(dis(gen));
|
||||||
mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale));
|
mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale));
|
||||||
inst.transform = mat;
|
inst.transform = mat;
|
||||||
|
|
@ -259,6 +253,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -267,8 +262,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -278,27 +272,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -307,40 +302,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
|
|
@ -71,25 +71,27 @@ The following implementation will create 2.000.000 spheres at random positions a
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating all spheres
|
// Creating all spheres
|
||||||
//
|
//
|
||||||
void HelloVulkan::createSpheres()
|
void HelloVulkan::createSpheres(uint32_t nbSpheres)
|
||||||
{
|
{
|
||||||
std::random_device rd{};
|
std::random_device rd{};
|
||||||
std::mt19937 gen{rd()};
|
std::mt19937 gen{rd()};
|
||||||
std::normal_distribution<float> xzd{0.f, 5.f};
|
std::normal_distribution<float> xzd{0.f, 5.f};
|
||||||
std::normal_distribution<float> yd{3.f, 1.f};
|
std::normal_distribution<float> yd{6.f, 3.f};
|
||||||
std::uniform_real_distribution<float> radd{.05f, .2f};
|
std::uniform_real_distribution<float> radd{.05f, .2f};
|
||||||
|
|
||||||
// All spheres
|
// All spheres
|
||||||
Sphere s;
|
m_spheres.resize(nbSpheres);
|
||||||
for(uint32_t i = 0; i < 2000000; i++)
|
for(uint32_t i = 0; i < nbSpheres; i++)
|
||||||
{
|
{
|
||||||
|
Sphere s;
|
||||||
s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen));
|
s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen));
|
||||||
s.radius = radd(gen);
|
s.radius = radd(gen);
|
||||||
m_spheres.emplace_back(s);
|
m_spheres[i] = std::move(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Axis aligned bounding box of each sphere
|
// Axis aligned bounding box of each sphere
|
||||||
std::vector<Aabb> aabbs;
|
std::vector<Aabb> aabbs;
|
||||||
|
aabbs.reserve(nbSpheres);
|
||||||
for(const auto& s : m_spheres)
|
for(const auto& s : m_spheres)
|
||||||
{
|
{
|
||||||
Aabb aabb;
|
Aabb aabb;
|
||||||
|
|
@ -99,28 +101,28 @@ void HelloVulkan::createSpheres()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating two materials
|
// Creating two materials
|
||||||
MatrialObj mat;
|
MaterialObj mat;
|
||||||
mat.diffuse = vec3f(0, 1, 1);
|
mat.diffuse = nvmath::vec3f(0, 1, 1);
|
||||||
std::vector<MatrialObj> materials;
|
std::vector<MaterialObj> materials;
|
||||||
std::vector<int> matIdx;
|
std::vector<int> matIdx(nbSpheres);
|
||||||
materials.emplace_back(mat);
|
materials.emplace_back(mat);
|
||||||
mat.diffuse = vec3f(1, 1, 0);
|
mat.diffuse = nvmath::vec3f(1, 1, 0);
|
||||||
materials.emplace_back(mat);
|
materials.emplace_back(mat);
|
||||||
|
|
||||||
// Assign a material to each sphere
|
// Assign a material to each sphere
|
||||||
for(size_t i = 0; i < m_spheres.size(); i++)
|
for(size_t i = 0; i < m_spheres.size(); i++)
|
||||||
{
|
{
|
||||||
matIdx.push_back(i % 2);
|
matIdx[i] = i % 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating all buffers
|
// Creating all buffers
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
using vkBU = VkBufferUsageFlagBits;
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||||
m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, vkBU::eStorageBuffer);
|
m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, vkBU::eShaderDeviceAddress);
|
m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
|
||||||
m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, vkBU::eStorageBuffer);
|
m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, vkBU::eStorageBuffer);
|
m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
genCmdBuf.submitAndWait(cmdBuf);
|
||||||
|
|
||||||
// Debug information
|
// Debug information
|
||||||
|
|
@ -148,39 +150,32 @@ What is changing compare to triangle primitive is the Aabb data (see Aabb struct
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Returning the ray tracing geometry used for the BLAS, containing all spheres
|
// 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;
|
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||||
asCreate.setGeometryType(vk::GeometryTypeKHR::eAabbs);
|
info.buffer = m_spheresAabbBuffer.buffer;
|
||||||
asCreate.setMaxPrimitiveCount((uint32_t)m_spheres.size()); // Nb triangles
|
VkDeviceAddress dataAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
asCreate.setIndexType(vk::IndexType::eNoneKHR);
|
|
||||||
asCreate.setVertexFormat(vk::Format::eUndefined);
|
|
||||||
asCreate.setMaxVertexCount(0);
|
|
||||||
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
|
|
||||||
|
|
||||||
|
VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR};
|
||||||
|
aabbs.data.deviceAddress = dataAddress;
|
||||||
|
aabbs.stride = sizeof(Aabb);
|
||||||
|
|
||||||
vk::DeviceAddress dataAddress = m_device.getBufferAddress({m_spheresAabbBuffer.buffer});
|
// Setting up the build info of the acceleration (C version, c++ gives wrong type)
|
||||||
vk::AccelerationStructureGeometryAabbsDataKHR aabbs;
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
aabbs.setData(dataAddress);
|
asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
|
||||||
aabbs.setStride(sizeof(Aabb));
|
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||||
|
asGeom.geometry.aabbs = aabbs;
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
VkAccelerationStructureBuildRangeInfoKHR offset{};
|
||||||
vk::AccelerationStructureGeometryKHR asGeom;
|
offset.firstVertex = 0;
|
||||||
asGeom.setGeometryType(asCreate.geometryType);
|
offset.primitiveCount = (uint32_t)m_spheres.size(); // Nb aabb
|
||||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
offset.primitiveOffset = 0;
|
||||||
asGeom.geometry.setAabbs(aabbs);
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
vk::AccelerationStructureBuildOffsetInfoKHR offset;
|
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||||
offset.setFirstVertex(0);
|
input.asGeometry.emplace_back(asGeom);
|
||||||
offset.setPrimitiveCount(asCreate.maxPrimitiveCount);
|
input.asBuildOffsetInfo.emplace_back(offset);
|
||||||
offset.setPrimitiveOffset(0);
|
return input;
|
||||||
offset.setTransformOffset(0);
|
|
||||||
|
|
||||||
nvvk::RaytracingBuilderKHR::Blas blas;
|
|
||||||
blas.asGeometry.emplace_back(asGeom);
|
|
||||||
blas.asCreateGeometryInfo.emplace_back(asCreate);
|
|
||||||
blas.asBuildOffsetInfo.emplace_back(offset);
|
|
||||||
return blas;
|
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -212,7 +207,7 @@ The function `createBottomLevelAS()` is creating a BLAS per OBJ, the following m
|
||||||
void HelloVulkan::createBottomLevelAS()
|
void HelloVulkan::createBottomLevelAS()
|
||||||
{
|
{
|
||||||
// BLAS - Storing each primitive in a geometry
|
// BLAS - Storing each primitive in a geometry
|
||||||
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas;
|
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
|
||||||
allBlas.reserve(m_objModel.size());
|
allBlas.reserve(m_objModel.size());
|
||||||
for(const auto& obj : m_objModel)
|
for(const auto& obj : m_objModel)
|
||||||
{
|
{
|
||||||
|
|
@ -228,7 +223,7 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
allBlas.emplace_back(blas);
|
allBlas.emplace_back(blas);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -261,19 +256,19 @@ In function `createDescriptorSetLayout()`, the addition of the material and mate
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Materials (binding = 1)
|
// Materials (binding = 1)
|
||||||
m_descSetLayoutBind.emplace_back(vkDS(1, vkDT::eStorageBuffer, nbObj + 1,
|
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj+1,
|
||||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
// Materials Index (binding = 4)
|
// Materials Index (binding = 4)
|
||||||
m_descSetLayoutBind.emplace_back(
|
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj +1,
|
||||||
vkDS(4, vkDT::eStorageBuffer, nbObj + 1, vkSS::eFragment | vkSS::eClosestHitKHR));
|
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
And the new buffer holding the spheres
|
And the new buffer holding the spheres
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Storing spheres (binding = 7)
|
// Storing spheres (binding = 7)
|
||||||
m_descSetLayoutBind.emplace_back( //
|
m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||||
vkDS(7, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR | vkSS::eIntersectionKHR));
|
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The function `updateDescriptorSet()` which is writing the values of the buffer need also to be modified.
|
The function `updateDescriptorSet()` which is writing the values of the buffer need also to be modified.
|
||||||
|
|
@ -281,22 +276,22 @@ The function `updateDescriptorSet()` which is writing the values of the buffer n
|
||||||
At the end of the loop on all models, lets add the new material and material index.
|
At the end of the loop on all models, lets add the new material and material index.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
for(auto& model : m_objModel)
|
for(auto& m : m_objModel)
|
||||||
{
|
{
|
||||||
dbiMat.emplace_back(model.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiMatIdx.emplace_back(model.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiVert.emplace_back(model.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiIdx.emplace_back(model.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
}
|
}
|
||||||
dbiMat.emplace_back(m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMat.push_back({m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiMatIdx.emplace_back(m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMatIdx.push_back({m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Then write the buffer for the spheres
|
Then write the buffer for the spheres
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
vk::DescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, dbiSpheres));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiSpheres));
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## Intersection Shader
|
## Intersection Shader
|
||||||
|
|
@ -306,44 +301,33 @@ The intersection shader is added to the Hit Group `VK_RAY_TRACING_SHADER_GROUP_T
|
||||||
Here is how the two hit group looks like:
|
Here is how the two hit group looks like:
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Hit Group0 - Closest Hit
|
enum StageIndices
|
||||||
vk::ShaderModule chitSM =
|
|
||||||
nvvk::createShaderModule(m_device, //
|
|
||||||
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
eRaygen,
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
eMiss,
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
eMiss2,
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
eClosestHit,
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
eClosestHit2,
|
||||||
m_rtShaderGroups.push_back(hg);
|
eIntersection,
|
||||||
}
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
|
||||||
// Hit Group1 - Closest Hit + Intersection (procedural)
|
// Closest hit
|
||||||
vk::ShaderModule chit2SM =
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
||||||
nvvk::createShaderModule(m_device, //
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths));
|
stages[eClosestHit2] = stage;
|
||||||
vk::ShaderModule rintSM =
|
// Intersection
|
||||||
nvvk::createShaderModule(m_device, //
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
|
||||||
nvh::loadFile("shaders/raytrace.rint.spv", true, paths));
|
stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
|
||||||
{
|
stages[eIntersection] = stage;
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
|
|
||||||
hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
|
|
||||||
m_rtShaderGroups.push_back(hg);
|
|
||||||
}
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
And destroy the two shaders at the end
|
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
m_device.destroy(chit2SM);
|
// closest hit shader + Intersection (Hit group 2)
|
||||||
m_device.destroy(rintSM);
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
|
||||||
|
group.closestHitShader = eClosestHit2;
|
||||||
|
group.intersectionShader = eIntersection;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### raycommon.glsl
|
### raycommon.glsl
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -35,25 +35,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -90,39 +86,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -133,26 +131,26 @@ public:
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void createRtShaderBindingTable();
|
void createRtShaderBindingTable();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
{
|
{
|
||||||
nvmath::vec4f clearColor;
|
nvmath::vec4f clearColor;
|
||||||
nvmath::vec3f lightPosition;
|
nvmath::vec3f lightPosition;
|
||||||
float lightIntensity;
|
float lightIntensity{100.0f};
|
||||||
int lightType;
|
int lightType{0};
|
||||||
} m_rtPushConstants;
|
} m_rtPushConstants;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -74,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -88,8 +87,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -116,9 +114,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -130,18 +128,16 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -156,11 +152,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -212,6 +207,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -220,8 +216,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -231,27 +226,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -260,40 +256,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -35,25 +35,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -90,39 +86,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -133,19 +131,19 @@ public:
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void createRtShaderBindingTable();
|
void createRtShaderBindingTable();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
void resetFrame();
|
void resetFrame();
|
||||||
void updateFrame();
|
void updateFrame();
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
int m_maxFrames{10};
|
int m_maxFrames{10};
|
||||||
|
|
||||||
|
|
@ -153,8 +151,8 @@ public:
|
||||||
{
|
{
|
||||||
nvmath::vec4f clearColor;
|
nvmath::vec4f clearColor;
|
||||||
nvmath::vec3f lightPosition;
|
nvmath::vec3f lightPosition;
|
||||||
float lightIntensity;
|
float lightIntensity{100.0f};
|
||||||
int lightType;
|
int lightType{0};
|
||||||
int frame{0};
|
int frame{0};
|
||||||
} m_rtPushConstants;
|
} m_rtPushConstants;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -55,9 +53,8 @@ static void onErrorCallback(int error, const char* description)
|
||||||
// Extra UI
|
// Extra UI
|
||||||
void renderUI(HelloVulkan& helloVk)
|
void renderUI(HelloVulkan& helloVk)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed{false};
|
||||||
|
ImGuiH::CameraWidget();
|
||||||
changed |= ImGuiH::CameraWidget();
|
|
||||||
if(ImGui::CollapsingHeader("Light"))
|
if(ImGui::CollapsingHeader("Light"))
|
||||||
{
|
{
|
||||||
auto& pc = helloVk.m_pushConstant;
|
auto& pc = helloVk.m_pushConstant;
|
||||||
|
|
@ -81,6 +78,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -95,8 +93,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -123,9 +120,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -138,17 +135,15 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -163,11 +158,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -219,6 +213,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -232,8 +227,7 @@ int main(int argc, char** argv)
|
||||||
helloVk.resetFrame();
|
helloVk.resetFrame();
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -243,27 +237,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -272,40 +267,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
|
|
@ -59,18 +59,31 @@ void main()
|
||||||
This new shader needs to be added to the raytracing pipeline. So, in `createRtPipeline` in `hello_vulkan.cpp`, load the new closest hit shader immediately after loading the first one.
|
This new shader needs to be added to the raytracing pipeline. So, in `createRtPipeline` in `hello_vulkan.cpp`, load the new closest hit shader immediately after loading the first one.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
vk::ShaderModule chit2SM =
|
enum StageIndices
|
||||||
nvvk::createShaderModule(m_device, //
|
{
|
||||||
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true));
|
eRaygen,
|
||||||
|
eMiss,
|
||||||
|
eMiss2,
|
||||||
|
eClosestHit,
|
||||||
|
eClosestHit2,
|
||||||
|
eShaderGroupCount
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHit2] = stage;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Then add a new hit group group immediately after adding the first hit group:
|
Then add a new hit group group immediately after adding the first hit group:
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// Second group
|
// Hit 2
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
m_rtShaderGroups.push_back(hg);
|
group.closestHitShader = eClosestHit2;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### `raytrace.rgen`
|
### `raytrace.rgen`
|
||||||
|
|
@ -200,6 +213,36 @@ In `main`, after we set which hit group an instance will use, we can add the dat
|
||||||
|
|
||||||
### `HelloVulkan::createRtShaderBindingTable`
|
### `HelloVulkan::createRtShaderBindingTable`
|
||||||
|
|
||||||
|
**NEW**
|
||||||
|
|
||||||
|
The creation of the shading binding table as it was done, was using hardcoded offsets and potentially could lead to errors.
|
||||||
|
Instead, the new code uses the `nvvk::SBTWraper` that uses the ray tracing pipeline and the `VkRayTracingPipelineCreateInfoKHR` to
|
||||||
|
create the SBT information.
|
||||||
|
|
||||||
|
The wrapper will find the handles for each group and will add the
|
||||||
|
data `m_hitShaderRecord` to the Hit group.
|
||||||
|
|
||||||
|
```` C
|
||||||
|
// Find handle indices and add data
|
||||||
|
m_sbtWrapper.addIndices(rayPipelineInfo);
|
||||||
|
m_sbtWrapper.addData(SBTWrapper::eHit, 1, m_hitShaderRecord[0]);
|
||||||
|
m_sbtWrapper.addData(SBTWrapper::eHit, 2, m_hitShaderRecord[1]);
|
||||||
|
m_sbtWrapper.create(m_rtPipeline);
|
||||||
|
````
|
||||||
|
|
||||||
|
The buffer for Hit will have the following layout
|
||||||
|
|
||||||
|
```
|
||||||
|
| handle | handle,data | handle,data |
|
||||||
|
```
|
||||||
|
|
||||||
|
The wrapper will make sure the stride covers the largest data and is aligned
|
||||||
|
based on the GPU properties.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**OLD - for reference**
|
||||||
|
|
||||||
Since we are no longer compacting all handles in a continuous buffer, we need to fill the SBT as described above.
|
Since we are no longer compacting all handles in a continuous buffer, we need to fill the SBT as described above.
|
||||||
|
|
||||||
After retrieving the handles of all 5 groups (raygen, miss, miss shadow, hit0, and hit1)
|
After retrieving the handles of all 5 groups (raygen, miss, miss shadow, hit0, and hit1)
|
||||||
|
|
@ -255,16 +298,27 @@ Then write the new SBT like this, where only Hit 1 has extra data.
|
||||||
Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sbtBuffer`:
|
Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sbtBuffer`:
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR);
|
m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
||||||
### `raytrace`
|
### `raytrace`
|
||||||
|
|
||||||
|
**NEW**
|
||||||
|
|
||||||
|
The mvvk::SBTWrapper gives use the information without having to compute the `VkStridedDeviceAddressRegionKHR`
|
||||||
|
|
||||||
|
``` C
|
||||||
|
auto& regions = m_sbtWrapper.getRegions();
|
||||||
|
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
**OLD**
|
||||||
|
|
||||||
Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`.
|
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++
|
~~~~ C++
|
||||||
vk::DeviceSize hitGroupSize =
|
VkDeviceSize hitGroupSize =
|
||||||
nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer),
|
nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer),
|
||||||
m_rtProperties.shaderGroupBaseAlignment);
|
m_rtProperties.shaderGroupBaseAlignment);
|
||||||
~~~~
|
~~~~
|
||||||
|
|
@ -272,7 +326,7 @@ Finally, since the size of the hit group is now larger than just the handle, we
|
||||||
The stride device address will be modified like this:
|
The stride device address will be modified like this:
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
using Stride = vk::StridedDeviceAddressRegionKHR;
|
using Stride = VkStridedDeviceAddressRegionKHR;
|
||||||
std::array<Stride, 4> strideAddresses{
|
std::array<Stride, 4> strideAddresses{
|
||||||
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
|
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
|
||||||
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
|
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
|
||||||
|
|
@ -280,7 +334,7 @@ The stride device address will be modified like this:
|
||||||
Stride{0u, 0u, 0u}}; // callable
|
Stride{0u, 0u, 0u}}; // callable
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
!!! Note:
|
**Note:**
|
||||||
The result should now show both `wuson` models with a yellow color.
|
The result should now show both `wuson` models with a yellow color.
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -37,25 +37,21 @@ using nvvk::SBTWrapper;
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -93,39 +89,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -136,20 +134,19 @@ public:
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void createRtShaderBindingTable();
|
void createRtShaderBindingTable();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
{
|
{
|
||||||
nvmath::vec4f clearColor;
|
nvmath::vec4f clearColor;
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,19 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
#include "hello_vulkan.h"
|
||||||
#include "imgui/imgui_camera_widget.h"
|
#include "imgui/imgui_camera_widget.h"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
#define UNUSED(x) (void)(x)
|
#define UNUSED(x) (void)(x)
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -43,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -70,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -84,8 +86,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -112,9 +113,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -126,18 +127,16 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -152,11 +151,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -169,10 +167,10 @@ int main(int argc, char** argv)
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
|
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
|
||||||
nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0)));
|
nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0)));
|
||||||
|
|
||||||
HelloVulkan::ObjInstance inst = helloVk.m_objInstance[0]; // Instance the wuson object
|
HelloVulkan::ObjInstance inst = helloVk.m_objInstance[0]; // Instance the Wuson object
|
||||||
inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0));
|
inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0));
|
||||||
inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform));
|
inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform));
|
||||||
helloVk.m_objInstance.push_back(inst); // Adding an instance of the wuson
|
helloVk.m_objInstance.push_back(inst); // Adding an instance of the Wuson
|
||||||
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||||
|
|
||||||
|
|
@ -180,8 +178,8 @@ int main(int argc, char** argv)
|
||||||
helloVk.m_hitShaderRecord.resize(2);
|
helloVk.m_hitShaderRecord.resize(2);
|
||||||
helloVk.m_hitShaderRecord[0].color = nvmath::vec4f(0, 1, 0, 0); // Green
|
helloVk.m_hitShaderRecord[0].color = nvmath::vec4f(0, 1, 0, 0); // Green
|
||||||
helloVk.m_hitShaderRecord[1].color = nvmath::vec4f(0, 1, 1, 0); // Cyan
|
helloVk.m_hitShaderRecord[1].color = nvmath::vec4f(0, 1, 1, 0); // Cyan
|
||||||
helloVk.m_objInstance[0].hitgroup = 1; // wuson 0
|
helloVk.m_objInstance[0].hitgroup = 1; // Wuson 0
|
||||||
helloVk.m_objInstance[1].hitgroup = 2; // wuson 1
|
helloVk.m_objInstance[1].hitgroup = 2; // Wuson 1
|
||||||
|
|
||||||
|
|
||||||
helloVk.createOffscreenRender();
|
helloVk.createOffscreenRender();
|
||||||
|
|
@ -197,7 +195,7 @@ int main(int argc, char** argv)
|
||||||
helloVk.createTopLevelAS();
|
helloVk.createTopLevelAS();
|
||||||
helloVk.createRtDescriptorSet();
|
helloVk.createRtDescriptorSet();
|
||||||
helloVk.createRtPipeline();
|
helloVk.createRtPipeline();
|
||||||
helloVk.createRtShaderBindingTable();
|
//helloVk.createRtShaderBindingTable();
|
||||||
|
|
||||||
helloVk.createPostDescriptor();
|
helloVk.createPostDescriptor();
|
||||||
helloVk.createPostPipeline();
|
helloVk.createPostPipeline();
|
||||||
|
|
@ -222,6 +220,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -230,8 +229,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -241,27 +239,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -270,40 +269,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,11 @@ Remove most functions and members to keep only what is need to create the accele
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model);
|
auto objectToVkGeometryKHR(const ObjModel& model);
|
||||||
void createBottomLevelAS();
|
void createBottomLevelAS();
|
||||||
void createTopLevelAS();
|
void createTopLevelAS();
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
@ -58,11 +58,11 @@ m_descSetLayoutBind.emplace_back( //
|
||||||
In `HelloVulkan::updateDescriptorSet`, write the value to the descriptor set.
|
In `HelloVulkan::updateDescriptorSet`, write the value to the descriptor set.
|
||||||
|
|
||||||
~~~~ C++
|
~~~~ C++
|
||||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo;
|
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||||
descASInfo.setAccelerationStructureCount(1);
|
descASInfo.accelerationStructureCount = 1;
|
||||||
descASInfo.setPAccelerationStructures(&tlas);
|
descASInfo.pAccelerationStructures = &tlas;
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, descASInfo));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo));
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,23 +19,24 @@
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "obj_loader.h"
|
#include "obj_loader.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
#include "hello_vulkan.h"
|
||||||
|
#include "nvh/alignment.hpp"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
|
#include "nvh/fileoperations.hpp"
|
||||||
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/images_vk.hpp"
|
#include "nvvk/images_vk.hpp"
|
||||||
#include "nvvk/pipeline_vk.hpp"
|
#include "nvvk/pipeline_vk.hpp"
|
||||||
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
#include "nvvk/renderpasses_vk.hpp"
|
||||||
|
#include "nvvk/shaders_vk.hpp"
|
||||||
|
|
||||||
|
extern std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// Holding the camera matrices
|
// Holding the camera matrices
|
||||||
|
|
@ -48,17 +49,15 @@ struct CameraMatrices
|
||||||
nvmath::mat4f projInverse;
|
nvmath::mat4f projInverse;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Keep the handle on the device
|
// Keep the handle on the device
|
||||||
// Initialize the tool to do all our allocations: buffers, images
|
// Initialize the tool to do all our allocations: buffers, images
|
||||||
//
|
//
|
||||||
void HelloVulkan::setup(const vk::Instance& instance,
|
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily)
|
|
||||||
{
|
{
|
||||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||||
m_alloc.init(device, physicalDevice);
|
m_alloc.init(instance, device, physicalDevice);
|
||||||
m_debug.setup(m_device);
|
m_debug.setup(m_device);
|
||||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +65,7 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Called at each frame to update the camera matrix
|
// Called at each frame to update the camera matrix
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
// Prepare new UBO contents on host.
|
// Prepare new UBO contents on host.
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||||
|
|
@ -79,33 +78,33 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
||||||
|
|
||||||
// UBO on the device, and what stages access it.
|
// UBO on the device, and what stages access it.
|
||||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||||
auto uboUsageStages =
|
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||||
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
|
|
||||||
|
|
||||||
// Ensure that the modified UBO is not visible to previous frames.
|
// Ensure that the modified UBO is not visible to previous frames.
|
||||||
vk::BufferMemoryBarrier beforeBarrier;
|
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
beforeBarrier.setBuffer(deviceUBO);
|
beforeBarrier.buffer = deviceUBO;
|
||||||
beforeBarrier.setOffset(0);
|
beforeBarrier.offset = 0;
|
||||||
beforeBarrier.setSize(sizeof hostUBO);
|
beforeBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||||
// buffer so it is okay to deallocate when the function returns).
|
// buffer so it is okay to deallocate when the function returns).
|
||||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||||
|
|
||||||
// Making sure the updated UBO will be visible.
|
// Making sure the updated UBO will be visible.
|
||||||
vk::BufferMemoryBarrier afterBarrier;
|
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
afterBarrier.setBuffer(deviceUBO);
|
afterBarrier.buffer = deviceUBO;
|
||||||
afterBarrier.setOffset(0);
|
afterBarrier.offset = 0;
|
||||||
afterBarrier.setSize(sizeof hostUBO);
|
afterBarrier.size = sizeof(hostUBO);
|
||||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -113,36 +112,25 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||||
//
|
//
|
||||||
void HelloVulkan::createDescriptorSetLayout()
|
void HelloVulkan::createDescriptorSetLayout()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||||
|
|
||||||
// Camera matrices (binding = 0)
|
// Camera matrices (binding = 0)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR));
|
|
||||||
// Materials (binding = 1)
|
// Materials (binding = 1)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
|
|
||||||
// Scene description (binding = 2)
|
// Scene description (binding = 2)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
|
|
||||||
// Textures (binding = 3)
|
// Textures (binding = 3)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR));
|
|
||||||
// Materials (binding = 4)
|
// Materials (binding = 4)
|
||||||
m_descSetLayoutBind.addBinding(
|
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR));
|
|
||||||
// Storing vertices (binding = 5)
|
// Storing vertices (binding = 5)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
|
|
||||||
// Storing indices (binding = 6)
|
// Storing indices (binding = 6)
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
|
|
||||||
// The top level acceleration structure
|
// The top level acceleration structure
|
||||||
m_descSetLayoutBind.addBinding( //
|
m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
vkDS(7, vkDT::eAccelerationStructureKHR, 1, vkSS::eFragment));
|
|
||||||
|
|
||||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||||
m_descPool = m_descSetLayoutBind.createPool(m_device, 1);
|
m_descPool = m_descSetLayoutBind.createPool(m_device, 1);
|
||||||
|
|
@ -154,25 +142,25 @@ void HelloVulkan::createDescriptorSetLayout()
|
||||||
//
|
//
|
||||||
void HelloVulkan::updateDescriptorSet()
|
void HelloVulkan::updateDescriptorSet()
|
||||||
{
|
{
|
||||||
std::vector<vk::WriteDescriptorSet> writes;
|
std::vector<VkWriteDescriptorSet> writes;
|
||||||
|
|
||||||
// Camera matrices and scene description
|
// Camera matrices and scene description
|
||||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||||
|
|
||||||
// All material buffers, 1 buffer per OBJ
|
// All material buffers, 1 buffer per OBJ
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiVert;
|
std::vector<VkDescriptorBufferInfo> dbiVert;
|
||||||
std::vector<vk::DescriptorBufferInfo> dbiIdx;
|
std::vector<VkDescriptorBufferInfo> dbiIdx;
|
||||||
for(auto& obj : m_objModel)
|
for(auto& m : m_objModel)
|
||||||
{
|
{
|
||||||
dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||||
}
|
}
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||||
|
|
@ -180,55 +168,53 @@ void HelloVulkan::updateDescriptorSet()
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
|
||||||
|
|
||||||
// All texture samplers
|
// All texture samplers
|
||||||
std::vector<vk::DescriptorImageInfo> diit;
|
std::vector<VkDescriptorImageInfo> diit;
|
||||||
for(auto& texture : m_textures)
|
for(auto& texture : m_textures)
|
||||||
{
|
{
|
||||||
diit.emplace_back(texture.descriptor);
|
diit.emplace_back(texture.descriptor);
|
||||||
}
|
}
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||||
|
|
||||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo;
|
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||||
descASInfo.setAccelerationStructureCount(1);
|
descASInfo.accelerationStructureCount = 1;
|
||||||
descASInfo.setPAccelerationStructures(&tlas);
|
descASInfo.pAccelerationStructures = &tlas;
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo));
|
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo));
|
||||||
|
|
||||||
|
|
||||||
// Writing the information
|
// Writing the information
|
||||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating the pipeline layout
|
// Creating the pipeline layout
|
||||||
//
|
//
|
||||||
void HelloVulkan::createGraphicsPipeline()
|
void HelloVulkan::createGraphicsPipeline()
|
||||||
{
|
{
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
|
||||||
|
|
||||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
sizeof(ObjPushConstant)};
|
|
||||||
|
|
||||||
// Creating the Pipeline Layout
|
// Creating the Pipeline Layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
createInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
createInfo.pSetLayouts = &m_descSetLayout;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
createInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
|
||||||
|
|
||||||
// Creating the Pipeline
|
// Creating the Pipeline
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
std::vector<std::string> paths = defaultSearchPaths;
|
||||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
||||||
gpb.depthStencilState.depthTestEnable = true;
|
gpb.depthStencilState.depthTestEnable = true;
|
||||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||||
gpb.addAttributeDescriptions({
|
gpb.addAttributeDescriptions({
|
||||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||||
});
|
});
|
||||||
|
|
||||||
m_graphicsPipeline = gpb.createPipeline();
|
m_graphicsPipeline = gpb.createPipeline();
|
||||||
|
|
@ -240,8 +226,6 @@ void HelloVulkan::createGraphicsPipeline()
|
||||||
//
|
//
|
||||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
|
|
||||||
LOGI("Loading File: %s \n", filename.c_str());
|
LOGI("Loading File: %s \n", filename.c_str());
|
||||||
ObjLoader loader;
|
ObjLoader loader;
|
||||||
loader.loadModel(filename);
|
loader.loadModel(filename);
|
||||||
|
|
@ -266,17 +250,13 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
|
|
||||||
// Create the buffers on Device and copy vertices, indices and materials
|
// Create the buffers on Device and copy vertices, indices and materials
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||||
model.vertexBuffer =
|
VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
|
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||||
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
|
||||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
|
||||||
model.indexBuffer =
|
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
m_alloc.createBuffer(cmdBuf, loader.m_indices,
|
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
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
|
// Creates all textures found
|
||||||
createTextureImages(cmdBuf, loader.m_textures);
|
createTextureImages(cmdBuf, loader.m_textures);
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
cmdBufGet.submitAndWait(cmdBuf);
|
||||||
|
|
@ -292,17 +272,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
m_objInstance.emplace_back(instance);
|
m_objInstance.emplace_back(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating the uniform buffer holding the camera matrices
|
// Creating the uniform buffer holding the camera matrices
|
||||||
// - Buffer is host visible
|
// - Buffer is host visible
|
||||||
//
|
//
|
||||||
void HelloVulkan::createUniformBuffer()
|
void HelloVulkan::createUniformBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
using vkMP = vk::MemoryPropertyFlagBits;
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
|
||||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
|
||||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
|
||||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,11 +292,10 @@ void HelloVulkan::createUniformBuffer()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createSceneDescriptionBuffer()
|
void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
{
|
{
|
||||||
using vkBU = vk::BufferUsageFlagBits;
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
cmdGen.submitAndWait(cmdBuf);
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
m_alloc.finalizeAndReleaseStaging();
|
||||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||||
|
|
@ -327,15 +304,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating all textures and samplers
|
// Creating all textures and samplers
|
||||||
//
|
//
|
||||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
||||||
const std::vector<std::string>& textures)
|
|
||||||
{
|
{
|
||||||
using vkIU = vk::ImageUsageFlagBits;
|
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
samplerCreateInfo.maxLod = FLT_MAX;
|
||||||
|
|
||||||
vk::SamplerCreateInfo samplerCreateInfo{
|
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
|
||||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
|
||||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
|
||||||
|
|
||||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||||
if(textures.empty() && m_textures.empty())
|
if(textures.empty() && m_textures.empty())
|
||||||
|
|
@ -343,18 +320,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
nvvk::Texture texture;
|
nvvk::Texture texture;
|
||||||
|
|
||||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||||
vk::DeviceSize bufferSize = sizeof(color);
|
VkDeviceSize bufferSize = sizeof(color);
|
||||||
auto imgSize = vk::Extent2D(1, 1);
|
auto imgSize = VkExtent2D{1, 1};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||||
|
|
||||||
// Creating the VKImage
|
// Creating the dummy texture
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -367,8 +343,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
o << "media/textures/" << texture;
|
o << "media/textures/" << texture;
|
||||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||||
|
|
||||||
stbi_uc* stbi_pixels =
|
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
||||||
|
|
||||||
|
|
@ -381,15 +356,14 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||||
vk::ImageViewCreateInfo ivInfo =
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||||
|
|
||||||
m_textures.push_back(texture);
|
m_textures.push_back(texture);
|
||||||
|
|
@ -405,10 +379,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||||
//
|
//
|
||||||
void HelloVulkan::destroyResources()
|
void HelloVulkan::destroyResources()
|
||||||
{
|
{
|
||||||
m_device.destroy(m_graphicsPipeline);
|
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||||
m_device.destroy(m_pipelineLayout);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
m_device.destroy(m_descPool);
|
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||||
m_device.destroy(m_descSetLayout);
|
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||||
|
|
||||||
m_alloc.destroy(m_cameraMat);
|
m_alloc.destroy(m_cameraMat);
|
||||||
m_alloc.destroy(m_sceneDesc);
|
m_alloc.destroy(m_sceneDesc);
|
||||||
|
|
||||||
|
|
@ -426,14 +401,15 @@ void HelloVulkan::destroyResources()
|
||||||
}
|
}
|
||||||
|
|
||||||
//#Post
|
//#Post
|
||||||
m_device.destroy(m_postPipeline);
|
|
||||||
m_device.destroy(m_postPipelineLayout);
|
|
||||||
m_device.destroy(m_postDescPool);
|
|
||||||
m_device.destroy(m_postDescSetLayout);
|
|
||||||
m_alloc.destroy(m_offscreenColor);
|
m_alloc.destroy(m_offscreenColor);
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
m_alloc.destroy(m_offscreenDepth);
|
||||||
m_device.destroy(m_offscreenRenderPass);
|
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
||||||
m_device.destroy(m_offscreenFramebuffer);
|
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
||||||
|
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
||||||
|
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
||||||
|
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||||
|
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
m_rtBuilder.destroy();
|
m_rtBuilder.destroy();
|
||||||
|
|
@ -443,32 +419,31 @@ void HelloVulkan::destroyResources()
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Drawing the scene in raster mode
|
// Drawing the scene in raster mode
|
||||||
//
|
//
|
||||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||||
{
|
{
|
||||||
using vkPBP = vk::PipelineBindPoint;
|
VkDeviceSize offset{0};
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
vk::DeviceSize offset{0};
|
|
||||||
|
|
||||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||||
|
|
||||||
// Dynamic Viewport
|
// Dynamic Viewport
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
setViewport(cmdBuf);
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
|
||||||
|
|
||||||
// Drawing all triangles
|
// Drawing all triangles
|
||||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& inst = m_objInstance[i];
|
auto& inst = m_objInstance[i];
|
||||||
auto& model = m_objModel[inst.objIndex];
|
auto& model = m_objModel[inst.objIndex];
|
||||||
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
||||||
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
|
||||||
m_pushConstant);
|
|
||||||
|
|
||||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
sizeof(ObjPushConstant), &m_pushConstant);
|
||||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||||
|
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -482,10 +457,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/)
|
||||||
updatePostDescriptorSet();
|
updatePostDescriptorSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Post-processing
|
// Post-processing
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Creating an offscreen frame buffer and the associated render pass
|
// Creating an offscreen frame buffer and the associated render pass
|
||||||
//
|
//
|
||||||
|
|
@ -497,29 +474,28 @@ void HelloVulkan::createOffscreenRender()
|
||||||
// Creating the color image
|
// Creating the color image
|
||||||
{
|
{
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
||||||
vk::ImageUsageFlagBits::eColorAttachment
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
| vk::ImageUsageFlagBits::eSampled
|
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||||
| 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);
|
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||||
|
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
||||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating the depth buffer
|
// Creating the depth buffer
|
||||||
auto depthCreateInfo =
|
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
|
|
||||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
|
||||||
{
|
{
|
||||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
||||||
|
|
||||||
vk::ImageViewCreateInfo depthStencilView;
|
|
||||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||||
depthStencilView.setFormat(m_offscreenDepthFormat);
|
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
depthStencilView.format = m_offscreenDepthFormat;
|
||||||
depthStencilView.setImage(image.image);
|
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||||
|
depthStencilView.image = image.image;
|
||||||
|
|
||||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
||||||
}
|
}
|
||||||
|
|
@ -528,11 +504,9 @@ void HelloVulkan::createOffscreenRender()
|
||||||
{
|
{
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined,
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
vk::ImageLayout::eGeneral);
|
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
|
||||||
vk::ImageAspectFlagBits::eDepth);
|
|
||||||
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
genCmdBuf.submitAndWait(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -540,24 +514,23 @@ void HelloVulkan::createOffscreenRender()
|
||||||
// Creating a renderpass for the offscreen
|
// Creating a renderpass for the offscreen
|
||||||
if(!m_offscreenRenderPass)
|
if(!m_offscreenRenderPass)
|
||||||
{
|
{
|
||||||
m_offscreenRenderPass =
|
m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
||||||
nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating the frame buffer for offscreen
|
|
||||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
|
||||||
m_offscreenDepth.descriptor.imageView};
|
|
||||||
|
|
||||||
m_device.destroy(m_offscreenFramebuffer);
|
// Creating the frame buffer for offscreen
|
||||||
vk::FramebufferCreateInfo info;
|
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
|
||||||
info.setRenderPass(m_offscreenRenderPass);
|
|
||||||
info.setAttachmentCount(2);
|
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||||
info.setPAttachments(attachments.data());
|
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||||
info.setWidth(m_size.width);
|
info.renderPass = m_offscreenRenderPass;
|
||||||
info.setHeight(m_size.height);
|
info.attachmentCount = 2;
|
||||||
info.setLayers(1);
|
info.pAttachments = attachments.data();
|
||||||
m_offscreenFramebuffer = m_device.createFramebuffer(info);
|
info.width = m_size.width;
|
||||||
|
info.height = m_size.height;
|
||||||
|
info.layers = 1;
|
||||||
|
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -566,25 +539,22 @@ void HelloVulkan::createOffscreenRender()
|
||||||
void HelloVulkan::createPostPipeline()
|
void HelloVulkan::createPostPipeline()
|
||||||
{
|
{
|
||||||
// Push constants in the fragment shader
|
// Push constants in the fragment shader
|
||||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||||
|
|
||||||
// Creating the pipeline layout
|
// Creating the pipeline layout
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
createInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout);
|
createInfo.pSetLayouts = &m_postDescSetLayout;
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
createInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||||
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
||||||
|
|
||||||
|
|
||||||
// Pipeline: completely generic, no vertices
|
// Pipeline: completely generic, no vertices
|
||||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
|
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
||||||
m_renderPass);
|
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
true),
|
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||||
vk::ShaderStageFlagBits::eVertex);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
|
||||||
vk::ShaderStageFlagBits::eFragment);
|
|
||||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
|
||||||
m_postPipeline = pipelineGenerator.createPipeline();
|
m_postPipeline = pipelineGenerator.createPipeline();
|
||||||
m_debug.setObjectName(m_postPipeline, "post");
|
m_debug.setObjectName(m_postPipeline, "post");
|
||||||
}
|
}
|
||||||
|
|
@ -595,43 +565,36 @@ void HelloVulkan::createPostPipeline()
|
||||||
//
|
//
|
||||||
void HelloVulkan::createPostDescriptor()
|
void HelloVulkan::createPostDescriptor()
|
||||||
{
|
{
|
||||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
using vkDT = vk::DescriptorType;
|
|
||||||
using vkSS = vk::ShaderStageFlagBits;
|
|
||||||
|
|
||||||
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
|
||||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
||||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
||||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Update the output
|
// Update the output
|
||||||
//
|
//
|
||||||
void HelloVulkan::updatePostDescriptorSet()
|
void HelloVulkan::updatePostDescriptorSet()
|
||||||
{
|
{
|
||||||
vk::WriteDescriptorSet writeDescriptorSets =
|
VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
||||||
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
||||||
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Draw a full screen quad with the attached image
|
// Draw a full screen quad with the attached image
|
||||||
//
|
//
|
||||||
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
||||||
{
|
{
|
||||||
m_debug.beginLabel(cmdBuf, "Post");
|
m_debug.beginLabel(cmdBuf, "Post");
|
||||||
|
|
||||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
setViewport(cmdBuf);
|
||||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
|
||||||
|
|
||||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
||||||
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0,
|
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||||
aspectRatio);
|
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
||||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline);
|
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
||||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0,
|
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||||
m_postDescSet, {});
|
|
||||||
cmdBuf.draw(3, 1, 0, 0);
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
m_debug.endLabel(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
@ -646,45 +609,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
||||||
void HelloVulkan::initRayTracing()
|
void HelloVulkan::initRayTracing()
|
||||||
{
|
{
|
||||||
// Requesting ray tracing properties
|
// Requesting ray tracing properties
|
||||||
auto properties =
|
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
prop2.pNext = &m_rtProperties;
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
|
||||||
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
|
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS
|
// Convert an OBJ model into the ray tracing geometry used to build the BLAS
|
||||||
//
|
//
|
||||||
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
||||||
{
|
{
|
||||||
// Building part
|
// BLAS builder requires raw device addresses.
|
||||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
info.buffer = model.vertexBuffer.buffer;
|
||||||
|
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
info.buffer = model.indexBuffer.buffer;
|
||||||
|
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||||
|
|
||||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
uint32_t maxPrimitiveCount = model.nbIndices / 3;
|
||||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
|
||||||
triangles.setVertexData(vertexAddress);
|
|
||||||
triangles.setVertexStride(sizeof(VertexObj));
|
|
||||||
triangles.setIndexType(vk::IndexType::eUint32);
|
|
||||||
triangles.setIndexData(indexAddress);
|
|
||||||
triangles.setTransformData({});
|
|
||||||
triangles.setMaxVertex(model.nbVertices);
|
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
// Describe buffer as array of VertexObj.
|
||||||
vk::AccelerationStructureGeometryKHR asGeom;
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
|
||||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
triangles.vertexData.deviceAddress = vertexAddress;
|
||||||
asGeom.geometry.setTriangles(triangles);
|
triangles.vertexStride = sizeof(VertexObj);
|
||||||
|
// Describe index data (32-bit unsigned int)
|
||||||
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
|
triangles.indexData.deviceAddress = indexAddress;
|
||||||
|
// Indicate identity transform by setting transformData to null device pointer.
|
||||||
|
//triangles.transformData = {};
|
||||||
|
triangles.maxVertex = model.nbVertices;
|
||||||
|
|
||||||
// The primitive itself
|
// Identify the above data as containing opaque triangles.
|
||||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||||
offset.setFirstVertex(0);
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||||
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
|
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||||
offset.setPrimitiveOffset(0);
|
asGeom.geometry.triangles = triangles;
|
||||||
offset.setTransformOffset(0);
|
|
||||||
|
|
||||||
// Our blas is only one geometry, but could be made of many geometries
|
// The entire array will be used to build the BLAS.
|
||||||
|
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||||
|
offset.firstVertex = 0;
|
||||||
|
offset.primitiveCount = maxPrimitiveCount;
|
||||||
|
offset.primitiveOffset = 0;
|
||||||
|
offset.transformOffset = 0;
|
||||||
|
|
||||||
|
// Our blas is made from only one geometry, but could be made of many geometries
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||||
input.asGeometry.emplace_back(asGeom);
|
input.asGeometry.emplace_back(asGeom);
|
||||||
input.asBuildOffsetInfo.emplace_back(offset);
|
input.asBuildOffsetInfo.emplace_back(offset);
|
||||||
|
|
@ -707,7 +678,7 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
// We could add more geometry in each BLAS, but we add only one for now
|
// We could add more geometry in each BLAS, but we add only one for now
|
||||||
allBlas.emplace_back(blas);
|
allBlas.emplace_back(blas);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HelloVulkan::createTopLevelAS()
|
void HelloVulkan::createTopLevelAS()
|
||||||
|
|
@ -724,5 +695,5 @@ void HelloVulkan::createTopLevelAS()
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||||
tlas.emplace_back(rayInst);
|
tlas.emplace_back(rayInst);
|
||||||
}
|
}
|
||||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -35,25 +35,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -90,39 +86,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -130,6 +128,6 @@ public:
|
||||||
void createBottomLevelAS();
|
void createBottomLevelAS();
|
||||||
void createTopLevelAS();
|
void createTopLevelAS();
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -36,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -48,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -75,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -89,8 +86,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -117,9 +113,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -129,18 +125,19 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR};
|
||||||
|
;
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -151,16 +148,14 @@ int main(int argc, char** argv)
|
||||||
// Use a compatible device
|
// Use a compatible device
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||||
|
|
||||||
|
|
||||||
// Create example
|
// Create example
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -173,6 +168,7 @@ int main(int argc, char** argv)
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
||||||
|
|
||||||
|
|
||||||
helloVk.createOffscreenRender();
|
helloVk.createOffscreenRender();
|
||||||
helloVk.createDescriptorSetLayout();
|
helloVk.createDescriptorSetLayout();
|
||||||
helloVk.createGraphicsPipeline();
|
helloVk.createGraphicsPipeline();
|
||||||
|
|
@ -193,13 +189,12 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
nvmath::vec4f clearColor = nvmath::vec4f(1, 1, 1, 1.00f);
|
nvmath::vec4f clearColor = nvmath::vec4f(1, 1, 1, 1.00f);
|
||||||
|
|
||||||
|
|
||||||
helloVk.setupGlfwCallbacks(window);
|
helloVk.setupGlfwCallbacks(window);
|
||||||
ImGui_ImplGlfw_InitForVulkan(window, true);
|
ImGui_ImplGlfw_InitForVulkan(window, true);
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while(!glfwWindowShouldClose(window))
|
while(!glfwWindowShouldClose(window))
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
if(helloVk.isMinimized())
|
if(helloVk.isMinimized())
|
||||||
|
|
@ -209,6 +204,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -216,8 +212,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -227,76 +222,65 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
catch(const std::system_error& e)
|
|
||||||
{
|
|
||||||
if(e.code() == vk::Result::eErrorDeviceLost)
|
|
||||||
{
|
|
||||||
#if _WIN32
|
|
||||||
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
std::cout << e.what() << std::endl;
|
|
||||||
return e.code().value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
@ -29,7 +29,6 @@ list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
||||||
include_directories(${TUTO_KHR_DIR}/common)
|
include_directories(${TUTO_KHR_DIR}/common)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# GLSL to SPIR-V custom build
|
# GLSL to SPIR-V custom build
|
||||||
compile_glsl_directory(
|
compile_glsl_directory(
|
||||||
|
|
@ -39,7 +38,6 @@ compile_glsl_directory(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Sources
|
# Sources
|
||||||
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ Vulkan ray tracing allows recursive calls to traceRayEXT, up to a limit defined
|
||||||
In `createRtPipeline()` in `hello_vulkan.cpp`, bring the maximum recursion depth up to 10, making sure not to exceed the physical device's maximum recursion limit:
|
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++
|
~~~~ C++
|
||||||
rayPipelineInfo.setMaxPipelineRayRecursionDepth(
|
rayPipelineInfo.maxPipelineRayRecursionDepth = std::max(10u, m_rtProperties.maxRecursionDepth); // Ray depth
|
||||||
std::max(10u, m_rtProperties.maxRecursionDepth)); // Ray depth
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### `raycommon.glsl`
|
### `raycommon.glsl`
|
||||||
|
|
@ -203,7 +202,7 @@ Since the ray generation shader now handles attenuation, we no longer need to at
|
||||||
Finally, we no longer need to have a deep recursion setting in `createRtPipeline` -- just a depth of 2, one for the initial ray generation segment and another for shadow rays.
|
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++
|
~~~~ C++
|
||||||
rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
|
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
In `raytrace.rgen`, we can now make the maximum ray depth significantly larger -- such as 100, for instance -- without causing a device lost error.
|
In `raytrace.rgen`, we can now make the maximum ray depth significantly larger -- such as 100, for instance -- without causing a device lost error.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -35,25 +35,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -90,39 +86,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -133,18 +131,18 @@ public:
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void createRtShaderBindingTable();
|
void createRtShaderBindingTable();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
nvvk::Buffer m_rtSBTBuffer;
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,15 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
#include "hello_vulkan.h"
|
||||||
#include "imgui/imgui_camera_widget.h"
|
#include "imgui/imgui_camera_widget.h"
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -44,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -71,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -85,8 +86,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -113,9 +113,9 @@ int main(int argc, char** argv)
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo(true);
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
#ifdef WIN32
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -127,18 +127,16 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_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
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
|
|
@ -153,11 +151,10 @@ int main(int argc, char** argv)
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -168,11 +165,9 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Creation of the example
|
// Creation of the example
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
|
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
|
||||||
nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0))
|
nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0)) * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
|
||||||
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
|
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
|
||||||
nvmath::translation_mat4(nvmath::vec3f(2, 0, 0))
|
nvmath::translation_mat4(nvmath::vec3f(2, 0, 0)) * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
|
||||||
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
|
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
|
||||||
nvmath::translation_mat4(nvmath::vec3f(0, -1, 0)));
|
nvmath::translation_mat4(nvmath::vec3f(0, -1, 0)));
|
||||||
|
|
@ -216,6 +211,7 @@ int main(int argc, char** argv)
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
// Show UI window.
|
||||||
if(helloVk.showGui())
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
|
|
@ -225,8 +221,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50);
|
ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -236,27 +231,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -265,40 +261,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Project setting
|
# Project setting
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
project(${PROJNAME} LANGUAGES C CXX)
|
||||||
message(STATUS "-------------------------------")
|
message(STATUS "-------------------------------")
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
message(STATUS "Processing Project ${PROJNAME}:")
|
||||||
|
|
@ -76,4 +76,3 @@ _finalize_target( ${PROJNAME} )
|
||||||
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,14 +95,15 @@ In our example, we will have only integers for constant data. There are various
|
||||||
|
|
||||||
~~~~ C
|
~~~~ C
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
/// Helper to generate specialization info
|
// Helper to generate specialization info
|
||||||
|
//
|
||||||
class Specialization
|
class Specialization
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void add(uint32_t constantID, int32_t value)
|
void add(uint32_t constantID, int32_t value)
|
||||||
{
|
{
|
||||||
spec_values.push_back(value);
|
spec_values.push_back(value);
|
||||||
vk::SpecializationMapEntry entry;
|
VkSpecializationMapEntry entry;
|
||||||
entry.constantID = constantID;
|
entry.constantID = constantID;
|
||||||
entry.size = sizeof(int32_t);
|
entry.size = sizeof(int32_t);
|
||||||
entry.offset = static_cast<uint32_t>(spec_entries.size() * sizeof(int32_t));
|
entry.offset = static_cast<uint32_t>(spec_entries.size() * sizeof(int32_t));
|
||||||
|
|
@ -115,40 +116,37 @@ public:
|
||||||
add(v.first, v.second);
|
add(v.first, v.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::SpecializationInfo* getSpecialization()
|
VkSpecializationInfo* getSpecialization()
|
||||||
{
|
{
|
||||||
spec_info.setData<int32_t>(spec_values);
|
spec_info.dataSize = static_cast<uint32_t>(spec_values.size() * sizeof(int32_t));
|
||||||
spec_info.setMapEntries(spec_entries);
|
spec_info.pData = spec_values.data();
|
||||||
|
spec_info.mapEntryCount = static_cast<uint32_t>(spec_entries.size());
|
||||||
|
spec_info.pMapEntries = spec_entries.data();
|
||||||
return &spec_info;
|
return &spec_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<int32_t> spec_values;
|
std::vector<int32_t> spec_values;
|
||||||
std::vector<vk::SpecializationMapEntry> spec_entries;
|
std::vector<VkSpecializationMapEntry> spec_entries;
|
||||||
vk::SpecializationInfo spec_info;
|
VkSpecializationInfo spec_info;
|
||||||
};
|
};
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
In `HelloVulkan::createRtPipeline()`,
|
In `HelloVulkan::createRtPipeline()`, we will create 8 specialization of the closest hit shader.
|
||||||
first move the Closest Hit shader module creation up in the function next to the other one, as follow ...
|
So the number of stages, will be 11 instead of 4.
|
||||||
|
|
||||||
~~~~ C
|
~~~~ C
|
||||||
vk::ShaderModule raygenSM = nvvk::createShaderModule(
|
enum StageIndices
|
||||||
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
{
|
||||||
vk::ShaderModule missSM = nvvk::createShaderModule(
|
eRaygen,
|
||||||
m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
eMiss,
|
||||||
|
eMiss2,
|
||||||
// The second miss shader is invoked when a shadow ray misses the geometry. It
|
eClosestHit, // <---- 8 specialization of this one
|
||||||
// simply indicates that no occlusion has been found
|
eShaderGroupCount = 11
|
||||||
vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
|
};
|
||||||
m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
|
||||||
|
|
||||||
vk::ShaderModule chitSM = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Thenjust after creating the shader modules, create a `Specialization` for each of the 8 on/off permutations of the 3 constants.
|
Then create a `Specialization` for each of the 8 on/off permutations of the 3 constants.
|
||||||
|
|
||||||
|
|
||||||
~~~~ C
|
~~~~ C
|
||||||
// Specialization
|
// Specialization
|
||||||
|
|
@ -162,23 +160,35 @@ Thenjust after creating the shader modules, create a `Specialization` for each o
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Then we will create as many HIT shader groups as we have specializations. This will give us the ability later to choose which 'specialization' we want to use.
|
Now the shader group will be created 8 times, each with a different specialization.
|
||||||
|
|
||||||
|
~~~~ C
|
||||||
|
// Hit Group - Closest Hit
|
||||||
|
// Create many variation of the closest hit
|
||||||
|
for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++)
|
||||||
|
{
|
||||||
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stage.pSpecializationInfo = specializations[s].getSpecialization();
|
||||||
|
stages[eClosestHit + s] = stage;
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
**Tip** : We can avoid to create 8 shader modules, but we would have to properly deal with the
|
||||||
|
deletion of them at the end of the function.
|
||||||
|
|
||||||
|
|
||||||
|
We will also modify the creation of the hit group to create as many HIT shader groups as we have specializations. This will give us the ability later to choose which 'specialization' we want to use.
|
||||||
|
|
||||||
~~~~ C
|
~~~~ C
|
||||||
// Hit Group - Closest Hit + AnyHit
|
// Hit Group - Closest Hit + AnyHit
|
||||||
for(size_t i = 0; i < specializations.size(); i++)
|
// Creating many Hit groups, one for each specialization
|
||||||
|
for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++)
|
||||||
{
|
{
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
group.closestHitShader = eClosestHit + s; // Using variation of the closest hit
|
||||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
m_rtShaderGroups.push_back(group);
|
||||||
vk::PipelineShaderStageCreateInfo stage;
|
|
||||||
stage.stage = vk::ShaderStageFlagBits::eClosestHitKHR;
|
|
||||||
stage.module = chitSM;
|
|
||||||
stage.pName = "main";
|
|
||||||
stage.pSpecializationInfo = specializations[i].getSpecialization();
|
|
||||||
stages.push_back(stage);
|
|
||||||
m_rtShaderGroups.push_back(hg);
|
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -18,13 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
|
#include "nvvk/appbase_vk.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
#include "nvvk/debug_util_vk.hpp"
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
#include "nvvk/descriptorsets_vk.hpp"
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
#include "nvvk/memallocator_dma_vk.hpp"
|
||||||
|
#include "nvvk/resourceallocator_vk.hpp"
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
#include "nvvk/raytraceKHR_vk.hpp"
|
||||||
|
|
@ -37,25 +36,21 @@
|
||||||
// - Rendering is done in an offscreen framebuffer
|
// - Rendering is done in an offscreen framebuffer
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||||
//
|
//
|
||||||
class HelloVulkan : public nvvk::AppBase
|
class HelloVulkan : public nvvk::AppBaseVk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void setup(const vk::Instance& instance,
|
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||||
const vk::Device& device,
|
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
|
||||||
uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createGraphicsPipeline();
|
void createGraphicsPipeline();
|
||||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||||
void updateDescriptorSet();
|
void updateDescriptorSet();
|
||||||
void createUniformBuffer();
|
void createUniformBuffer();
|
||||||
void createSceneDescriptionBuffer();
|
void createSceneDescriptionBuffer();
|
||||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||||
const std::vector<std::string>& textures);
|
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
void onResize(int /*w*/, int /*h*/) override;
|
||||||
void destroyResources();
|
void destroyResources();
|
||||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||||
|
|
||||||
// The OBJ model
|
// The OBJ model
|
||||||
struct ObjModel
|
struct ObjModel
|
||||||
|
|
@ -93,39 +88,41 @@ public:
|
||||||
std::vector<ObjInstance> m_objInstance;
|
std::vector<ObjInstance> m_objInstance;
|
||||||
|
|
||||||
// Graphic pipeline
|
// Graphic pipeline
|
||||||
vk::PipelineLayout m_pipelineLayout;
|
VkPipelineLayout m_pipelineLayout;
|
||||||
vk::Pipeline m_graphicsPipeline;
|
VkPipeline m_graphicsPipeline;
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||||
vk::DescriptorPool m_descPool;
|
VkDescriptorPool m_descPool;
|
||||||
vk::DescriptorSetLayout m_descSetLayout;
|
VkDescriptorSetLayout m_descSetLayout;
|
||||||
vk::DescriptorSet m_descSet;
|
VkDescriptorSet m_descSet;
|
||||||
|
|
||||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||||
|
|
||||||
|
|
||||||
// #Post
|
// #Post
|
||||||
void createOffscreenRender();
|
void createOffscreenRender();
|
||||||
void createPostPipeline();
|
void createPostPipeline();
|
||||||
void createPostDescriptor();
|
void createPostDescriptor();
|
||||||
void updatePostDescriptorSet();
|
void updatePostDescriptorSet();
|
||||||
void drawPost(vk::CommandBuffer cmdBuf);
|
void drawPost(VkCommandBuffer cmdBuf);
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_postDescPool;
|
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||||
vk::DescriptorSet m_postDescSet;
|
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||||
vk::Pipeline m_postPipeline;
|
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||||
vk::PipelineLayout m_postPipelineLayout;
|
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||||
vk::RenderPass m_offscreenRenderPass;
|
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||||
vk::Framebuffer m_offscreenFramebuffer;
|
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||||
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::eX8D24UnormPack32};
|
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||||
|
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||||
|
|
||||||
// #VKRay
|
// #VKRay
|
||||||
void initRayTracing();
|
void initRayTracing();
|
||||||
|
|
@ -135,18 +132,18 @@ public:
|
||||||
void createRtDescriptorSet();
|
void createRtDescriptorSet();
|
||||||
void updateRtDescriptorSet();
|
void updateRtDescriptorSet();
|
||||||
void createRtPipeline();
|
void createRtPipeline();
|
||||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||||
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||||
vk::DescriptorPool m_rtDescPool;
|
VkDescriptorPool m_rtDescPool;
|
||||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||||
vk::DescriptorSet m_rtDescSet;
|
VkDescriptorSet m_rtDescSet;
|
||||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||||
vk::PipelineLayout m_rtPipelineLayout;
|
VkPipelineLayout m_rtPipelineLayout;
|
||||||
vk::Pipeline m_rtPipeline;
|
VkPipeline m_rtPipeline;
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
nvvk::SBTWrapper m_sbtWrapper;
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
// at the top of imgui.cpp.
|
// at the top of imgui.cpp.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
#include "backends/imgui_impl_glfw.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
#include "nvh/cameramanipulator.hpp"
|
#include "nvh/cameramanipulator.hpp"
|
||||||
#include "nvh/fileoperations.hpp"
|
#include "nvh/fileoperations.hpp"
|
||||||
#include "nvpsystem.hpp"
|
#include "nvpsystem.hpp"
|
||||||
#include "nvvk/appbase_vkpp.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
#include "nvvk/commands_vk.hpp"
|
||||||
#include "nvvk/context_vk.hpp"
|
#include "nvvk/context_vk.hpp"
|
||||||
|
|
||||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
// Default search path for shaders
|
// Default search path for shaders
|
||||||
std::vector<std::string> defaultSearchPaths;
|
std::vector<std::string> defaultSearchPaths;
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
// GLFW Callback functions
|
||||||
static void onErrorCallback(int error, const char* description)
|
static void onErrorCallback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -84,6 +82,7 @@ void renderUI(HelloVulkan& helloVk)
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
static int const SAMPLE_WIDTH = 1280;
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
static int const SAMPLE_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
// Application Entry
|
// Application Entry
|
||||||
//
|
//
|
||||||
|
|
@ -98,8 +97,7 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
GLFWwindow* window =
|
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
// Setup camera
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
|
|
@ -123,12 +121,12 @@ int main(int argc, char** argv)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Requesting Vulkan extensions and layers
|
// Requesting Vulkan extensions and layers
|
||||||
nvvk::ContextCreateInfo contextInfo(true);
|
nvvk::ContextCreateInfo contextInfo;
|
||||||
contextInfo.setVersion(1, 2);
|
contextInfo.setVersion(1, 2);
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#else
|
#else
|
||||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
|
@ -138,19 +136,19 @@ int main(int argc, char** argv)
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
|
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
// #VKRay: Activate the ray tracing extension
|
||||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||||
&accelFeature);
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
|
||||||
&rtPipelineFeature);
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||||
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
// Creating Vulkan base application
|
||||||
nvvk::Context vkctx{};
|
nvvk::Context vkctx{};
|
||||||
vkctx.initInstance(contextInfo);
|
vkctx.initInstance(contextInfo);
|
||||||
|
|
@ -160,16 +158,14 @@ int main(int argc, char** argv)
|
||||||
// Use a compatible device
|
// Use a compatible device
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||||
|
|
||||||
|
|
||||||
// Create example
|
// Create example
|
||||||
HelloVulkan helloVk;
|
HelloVulkan helloVk;
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
// Window need to be opened to get the surface on which to draw
|
||||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
vkctx.setGCTQueueWithPresent(surface);
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||||
vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||||
helloVk.createDepthBuffer();
|
helloVk.createDepthBuffer();
|
||||||
helloVk.createRenderPass();
|
helloVk.createRenderPass();
|
||||||
|
|
@ -229,9 +225,7 @@ int main(int argc, char** argv)
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||||
|
|
||||||
renderUI(helloVk);
|
renderUI(helloVk);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
ImGuiH::Panel::End();
|
ImGuiH::Panel::End();
|
||||||
}
|
}
|
||||||
|
|
@ -241,27 +235,28 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
// Start command buffer of this frame
|
// Start command buffer of this frame
|
||||||
auto curFrame = helloVk.getCurFrame();
|
auto curFrame = helloVk.getCurFrame();
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
// Updating camera buffer
|
// Updating camera buffer
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
// Clearing screen
|
// Clearing screen
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].setColor(
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
// Rendering Scene
|
// Rendering Scene
|
||||||
if(useRaytracer)
|
if(useRaytracer)
|
||||||
|
|
@ -270,40 +265,40 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.rasterize(cmdBuf);
|
helloVk.rasterize(cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
// 2nd rendering pass: tone mapper, UI
|
||||||
{
|
{
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
helloVk.drawPost(cmdBuf);
|
helloVk.drawPost(cmdBuf);
|
||||||
// Rendering UI
|
// Rendering UI
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
cmdBuf.endRenderPass();
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit for display
|
// Submit for display
|
||||||
cmdBuf.end();
|
vkEndCommandBuffer(cmdBuf);
|
||||||
helloVk.submitFrame();
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
helloVk.getDevice().waitIdle();
|
vkDeviceWaitIdle(helloVk.getDevice());
|
||||||
|
|
||||||
helloVk.destroyResources();
|
helloVk.destroyResources();
|
||||||
helloVk.destroy();
|
helloVk.destroy();
|
||||||
|
|
||||||
vkctx.deinit();
|
vkctx.deinit();
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue