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
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,11 @@ void ObjLoader::loadModel(const std::string& filename)
|
||||||
for(const auto& material : reader.GetMaterials())
|
for(const auto& material : reader.GetMaterials())
|
||||||
{
|
{
|
||||||
MaterialObj m;
|
MaterialObj m;
|
||||||
m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]);
|
m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]);
|
||||||
m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]);
|
m.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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ struct MaterialObj
|
||||||
float shininess = 0.f;
|
float shininess = 0.f;
|
||||||
float ior = 1.0f; // index of refraction
|
float ior = 1.0f; // index of refraction
|
||||||
float dissolve = 1.f; // 1 == opaque; 0 == fully transparent
|
float dissolve = 1.f; // 1 == opaque; 0 == fully transparent
|
||||||
// illumination model (see http://www.fileformat.info/format/material/)
|
// illumination model (see http://www.fileformat.info/format/material/)
|
||||||
int illum = 0;
|
int illum = 0;
|
||||||
int textureID = -1;
|
int textureID = -1;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
@ -370,12 +370,12 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes.
|
||||||
`hello_vulkan.h`:
|
`hello_vulkan.h`:
|
||||||
|
|
||||||
```` 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,61 +462,72 @@ 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);
|
||||||
m_lanternIndirectPushConstants.viewRowZ = view.row(2);
|
m_lanternIndirectPushConstants.viewRowZ = view.row(2);
|
||||||
m_lanternIndirectPushConstants.proj = getProjMatrix();
|
m_lanternIndirectPushConstants.proj = getProjMatrix();
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -579,40 +588,40 @@ In order to focus on the ray tracing, I omit the code for generating those verte
|
||||||
buffers. The relevent code in `HelloVulkan::createLanternModel` for creating the `BlasInput` is
|
buffers. The relevent code in `HelloVulkan::createLanternModel` for creating the `BlasInput` is
|
||||||
|
|
||||||
```` 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);
|
||||||
m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset);
|
m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset);
|
||||||
````
|
````
|
||||||
|
|
||||||
The principle difference from before is that the vertex array is now a packed array of
|
The principle difference from before is that the vertex array is now a packed array of
|
||||||
|
|
@ -647,7 +656,7 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
m_lanternBlasId = allBlas.size();
|
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
|
||||||
|
};
|
||||||
|
// ...
|
||||||
|
|
||||||
// Lantern Primary Ray Hit Group
|
// OBJ Primary Ray Hit Group - Closest Hit
|
||||||
vk::ShaderModule lanternChitSM =
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.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[eClosestHit] = stage;
|
||||||
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR lanternHg{
|
// Lantern Primary Ray Hit Group
|
||||||
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
stages[eClosestHitLantern] = stage;
|
||||||
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
|
||||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"});
|
// ...
|
||||||
m_rtShaderGroups.push_back(lanternHg);
|
|
||||||
|
// closest hit shader
|
||||||
// ...
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
m_device.destroy(lanternChitSM);
|
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
|
||||||
|
|
@ -1102,41 +1109,53 @@ groups for primary rays. Add the following code to `HelloVulkan::createRtPipelin
|
||||||
after loading `raytraceShadow.rmiss.spv`.
|
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
|
||||||
// OBJ Lantern Shadow Ray Hit Group
|
// Lantern Primary Ray Hit Group
|
||||||
vk::ShaderModule lanternShadowObjChitSM =
|
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/lanternShadowObj.rchit.spv", true, paths, true));
|
stages[eClosestHitLantern] = stage;
|
||||||
|
|
||||||
|
// OBJ Lantern Shadow Ray Hit Group
|
||||||
|
stage.module =
|
||||||
|
nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true));
|
||||||
|
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||||
|
stages[eClosestHitLanternShdObj] = stage;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Lantern Shadow Miss
|
||||||
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||||
|
group.generalShader = eMissLantern;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
|
||||||
|
// closest hit shader
|
||||||
|
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||||
|
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||||
|
group.closestHitShader = eClosestHit;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
group.closestHitShader = eClosestHitLantern;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
group.closestHitShader = eClosestHitLanternShdObj;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
|
group.closestHitShader = eClosestHitLanternShd;
|
||||||
|
m_rtShaderGroups.push_back(group);
|
||||||
|
|
||||||
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{
|
|
||||||
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
|
||||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
|
||||||
lanternShadowObjHg.setClosestHitShader(static_cast<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,10 +1413,8 @@ 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], //
|
m_size.width, m_size.height, 1);
|
||||||
&strideAddresses[2], &strideAddresses[3], //
|
|
||||||
m_size.width, m_size.height, 1);
|
|
||||||
````
|
````
|
||||||
|
|
||||||
After that, we can open a loop for performing all lantern passes.
|
After that, we can open a loop for performing all lantern passes.
|
||||||
|
|
@ -1412,25 +1429,23 @@ Because the additive blending in the shader requires read-modify-write operation
|
||||||
we need a barrier between every pass.
|
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], //
|
indirectDeviceAddress);
|
||||||
m_device.getBufferAddress({m_lanternIndirectBuffer.buffer}) + i * sizeof(LanternIndirectEntry));
|
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
@ -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;*/
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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,11 +28,12 @@ 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(
|
||||||
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
||||||
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
||||||
VULKAN_TARGET "vulkan1.2"
|
VULKAN_TARGET "vulkan1.2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,46 +71,46 @@ 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);
|
||||||
CameraMatrices hostUBO = {};
|
CameraMatrices hostUBO = {};
|
||||||
hostUBO.view = CameraManip.getMatrix();
|
hostUBO.view = CameraManip.getMatrix();
|
||||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
// hostUBO.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
|
// #VKRay
|
||||||
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);
|
||||||
|
|
@ -271,18 +261,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
||||||
|
|
||||||
// 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,16 +368,15 @@ 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
|
||||||
|
|
@ -589,11 +569,11 @@ void HelloVulkan::createImplictBuffers()
|
||||||
if(m_implObjects.implMat.empty())
|
if(m_implObjects.implMat.empty())
|
||||||
m_implObjects.implMat.push_back({});
|
m_implObjects.implMat.push_back({});
|
||||||
|
|
||||||
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,14 +193,13 @@ 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()
|
||||||
std::normal_distribution<float> dis(2.0f, 2.0f);
|
std::normal_distribution<float> dis(2.0f, 2.0f);
|
||||||
std::normal_distribution<float> disn(0.5f, 0.2f);
|
std::normal_distribution<float> disn(0.5f, 0.2f);
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -305,28 +293,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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,
|
nvvk::Image image = m_alloc->createImage(depthCreateInfo);
|
||||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
|
||||||
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,50 +104,46 @@ 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),
|
m_pipeline = pipelineGenerator.createPipeline();
|
||||||
vk::ShaderStageFlagBits::eFragment);
|
|
||||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
|
||||||
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)
|
||||||
|
|
@ -176,46 +173,48 @@ void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst&
|
||||||
if(!implicitObj.objImpl.empty())
|
if(!implicitObj.objImpl.empty())
|
||||||
{
|
{
|
||||||
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,169 +222,188 @@ 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
|
0, sizeof(RtPushConstants)};
|
||||||
| vk::ShaderStageFlagBits::eCallableKHR,
|
|
||||||
0, sizeof(RtPushConstants)};
|
|
||||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant);
|
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");
|
||||||
// Initializing push constant values
|
// Initializing push constant values
|
||||||
|
|
@ -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,44 +27,40 @@
|
||||||
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,43 +62,44 @@ 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);
|
||||||
CameraMatrices hostUBO = {};
|
CameraMatrices hostUBO = {};
|
||||||
hostUBO.view = CameraManip.getMatrix();
|
hostUBO.view = CameraManip.getMatrix();
|
||||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||||
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,16 +331,15 @@ 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,26 +511,23 @@ 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);
|
m_postPipeline = pipelineGenerator.createPipeline();
|
||||||
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_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();
|
||||||
}
|
}
|
||||||
|
|
@ -206,62 +199,63 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
|
|
@ -230,28 +224,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
@ -450,15 +462,15 @@ void HelloVulkan::createBottomLevelAS()
|
||||||
{
|
{
|
||||||
// BLAS - Storing each primitive in a geometry
|
// BLAS - Storing each primitive in a geometry
|
||||||
m_blas.reserve(m_objModel.size());
|
m_blas.reserve(m_objModel.size());
|
||||||
for(const auto & obj : m_objModel)
|
for(const auto& obj : m_objModel)
|
||||||
{
|
{
|
||||||
auto blas = objectToVkGeometryKHR(obj);
|
auto blas = objectToVkGeometryKHR(obj);
|
||||||
|
|
||||||
// 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,19 +131,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);
|
||||||
|
|
||||||
|
|
||||||
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;
|
||||||
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas;
|
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas;
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -244,28 +237,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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,21 +131,21 @@ 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};
|
||||||
|
|
||||||
struct RtPushConstant
|
struct RtPushConstant
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -233,28 +226,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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,9 +74,9 @@ 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};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Renderpass
|
### Renderpass
|
||||||
|
|
@ -86,7 +84,7 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
||||||
This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth)
|
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,46 +63,44 @@ 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);
|
||||||
CameraMatrices hostUBO = {};
|
CameraMatrices hostUBO = {};
|
||||||
hostUBO.view = CameraManip.getMatrix();
|
hostUBO.view = CameraManip.getMatrix();
|
||||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
// hostUBO.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);
|
||||||
|
|
@ -250,18 +235,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
||||||
|
|
||||||
// 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,16 +342,15 @@ 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,26 +568,23 @@ 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);
|
m_postPipeline = pipelineGenerator.createPipeline();
|
||||||
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_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,22 +141,23 @@ public:
|
||||||
void createBottomLevelAS();
|
void createBottomLevelAS();
|
||||||
void createTopLevelAS();
|
void createTopLevelAS();
|
||||||
|
|
||||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||||
|
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||||
|
|
||||||
|
|
||||||
// #Tuto_animation
|
// #Tuto_animation
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
@ -251,66 +246,67 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
|
|
@ -244,28 +238,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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,12 +242,12 @@ 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,20 +124,20 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
@ -227,28 +223,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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,22 +191,22 @@ 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,
|
||||||
// position, etc. from when doing lantern lighting passes.
|
// position, etc. from when doing lantern lighting passes.
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -242,28 +237,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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"
|
||||||
|
|
||||||
|
|
@ -56,9 +53,8 @@ struct MilliTimer
|
||||||
void reset() { startTime = std::chrono::high_resolution_clock::now(); }
|
void reset() { startTime = std::chrono::high_resolution_clock::now(); }
|
||||||
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();
|
||||||
|
|
@ -199,7 +194,7 @@ int main(int argc, char** argv)
|
||||||
MilliTimer timer;
|
MilliTimer timer;
|
||||||
|
|
||||||
// Creation of the example
|
// Creation of the example
|
||||||
std::random_device rd; //Will be used to obtain a seed for the random number engine
|
std::random_device rd; //Will be used to obtain a seed for the random number engine
|
||||||
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
|
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
|
||||||
std::normal_distribution<float> dis(1.0f, 1.0f);
|
std::normal_distribution<float> dis(1.0f, 1.0f);
|
||||||
std::normal_distribution<float> disn(0.05f, 0.05f);
|
std::normal_distribution<float> disn(0.05f, 0.05f);
|
||||||
|
|
@ -209,12 +204,11 @@ 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;
|
inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform)));
|
||||||
inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -277,28 +271,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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++)
|
||||||
{
|
{
|
||||||
s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen));
|
Sphere s;
|
||||||
s.radius = radd(gen);
|
s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen));
|
||||||
m_spheres.emplace_back(s);
|
s.radius = radd(gen);
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
@ -230,28 +225,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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,28 +131,28 @@ 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};
|
||||||
|
|
||||||
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};
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
@ -242,28 +236,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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}:")
|
||||||
|
|
@ -33,7 +33,7 @@ include_directories(${TUTO_KHR_DIR}/common)
|
||||||
# GLSL to SPIR-V custom build
|
# GLSL to SPIR-V custom build
|
||||||
compile_glsl_directory(
|
compile_glsl_directory(
|
||||||
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
||||||
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
||||||
VULKAN_TARGET "vulkan1.2"
|
VULKAN_TARGET "vulkan1.2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -240,28 +238,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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}:")
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,14 @@ First, let's remove all extra code
|
||||||
Remove most functions and members to keep only what is need to create the acceleration structure:
|
Remove most functions and members to keep only what is need to create the acceleration structure:
|
||||||
|
|
||||||
~~~~ 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;
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### hello_vulkan (source)
|
### hello_vulkan (source)
|
||||||
|
|
@ -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,46 +65,46 @@ 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);
|
||||||
CameraMatrices hostUBO = {};
|
CameraMatrices hostUBO = {};
|
||||||
hostUBO.view = CameraManip.getMatrix();
|
hostUBO.view = CameraManip.getMatrix();
|
||||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
// hostUBO.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
|
// #VKRay
|
||||||
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);
|
||||||
|
|
@ -265,18 +249,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
||||||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
||||||
|
|
||||||
// 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,16 +356,15 @@ 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,26 +539,23 @@ 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);
|
m_postPipeline = pipelineGenerator.createPipeline();
|
||||||
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_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,110 +189,98 @@ 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();
|
||||||
|
if(helloVk.isMinimized())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Start the Dear ImGui frame
|
||||||
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
||||||
|
// Show UI window.
|
||||||
|
if(helloVk.showGui())
|
||||||
{
|
{
|
||||||
glfwPollEvents();
|
ImGuiH::Panel::Begin();
|
||||||
if(helloVk.isMinimized())
|
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
||||||
continue;
|
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
renderUI(helloVk);
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
ImGui::NewFrame();
|
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||||
|
ImGuiH::Panel::End();
|
||||||
// Show UI window.
|
|
||||||
if(helloVk.showGui())
|
|
||||||
{
|
|
||||||
ImGuiH::Panel::Begin();
|
|
||||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
|
||||||
|
|
||||||
renderUI(helloVk);
|
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
|
||||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
|
||||||
ImGuiH::Panel::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start rendering the scene
|
|
||||||
helloVk.prepareFrame();
|
|
||||||
|
|
||||||
// Start command buffer of this frame
|
|
||||||
auto curFrame = helloVk.getCurFrame();
|
|
||||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
|
||||||
|
|
||||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
|
||||||
|
|
||||||
// Updating camera buffer
|
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
|
||||||
|
|
||||||
// Clearing screen
|
|
||||||
std::array<vk::ClearValue, 2> clearValues;
|
|
||||||
clearValues[0].setColor(
|
|
||||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
|
||||||
clearValues[1].setDepthStencil({1.0f, 0});
|
|
||||||
|
|
||||||
// Offscreen render pass
|
|
||||||
{
|
|
||||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
|
||||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
|
||||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
|
||||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
|
||||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
|
||||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
|
||||||
|
|
||||||
// Rendering Scene
|
|
||||||
{
|
|
||||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
helloVk.rasterize(cmdBuf);
|
|
||||||
cmdBuf.endRenderPass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
|
||||||
{
|
|
||||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
|
||||||
postRenderPassBeginInfo.setClearValueCount(2);
|
|
||||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
|
||||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
|
||||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
|
||||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
|
||||||
|
|
||||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
|
||||||
// Rendering tonemapper
|
|
||||||
helloVk.drawPost(cmdBuf);
|
|
||||||
// Rendering UI
|
|
||||||
ImGui::Render();
|
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
|
||||||
cmdBuf.endRenderPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit for display
|
|
||||||
cmdBuf.end();
|
|
||||||
helloVk.submitFrame();
|
|
||||||
}
|
}
|
||||||
catch(const std::system_error& e)
|
|
||||||
|
// Start rendering the scene
|
||||||
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
|
// Start command buffer of this frame
|
||||||
|
auto curFrame = helloVk.getCurFrame();
|
||||||
|
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||||
|
|
||||||
|
// Updating camera buffer
|
||||||
|
helloVk.updateUniformBuffer(cmdBuf);
|
||||||
|
|
||||||
|
// Clearing screen
|
||||||
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
|
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||||
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
|
|
||||||
|
// Offscreen render pass
|
||||||
{
|
{
|
||||||
if(e.code() == vk::Result::eErrorDeviceLost)
|
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
|
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||||
|
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
|
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||||
|
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||||
|
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
|
// Rendering Scene
|
||||||
{
|
{
|
||||||
#if _WIN32
|
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
|
helloVk.rasterize(cmdBuf);
|
||||||
#endif
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
}
|
}
|
||||||
std::cout << e.what() << std::endl;
|
|
||||||
return e.code().value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2nd rendering pass: tone mapper, UI
|
||||||
|
{
|
||||||
|
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||||
|
postRenderPassBeginInfo.clearValueCount = 2;
|
||||||
|
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
|
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||||
|
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||||
|
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||||
|
|
||||||
|
// Rendering tonemapper
|
||||||
|
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
helloVk.drawPost(cmdBuf);
|
||||||
|
// Rendering UI
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||||
|
vkCmdEndRenderPass(cmdBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit for display
|
||||||
|
vkEndCommandBuffer(cmdBuf);
|
||||||
|
helloVk.submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// 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,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);
|
||||||
|
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
@ -235,28 +230,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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,19 +132,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);
|
||||||
|
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
@ -240,28 +234,29 @@ int main(int argc, char** argv)
|
||||||
helloVk.prepareFrame();
|
helloVk.prepareFrame();
|
||||||
|
|
||||||
// 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