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'
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
|
|
@ -21,7 +21,7 @@ BreakBeforeBinaryOperators: NonAssignment
|
|||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: 'false'
|
||||
BreakConstructorInitializersBeforeComma: 'true'
|
||||
ColumnLimit: '100'
|
||||
ColumnLimit: '120'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
|
||||
Cpp11BracedListStyle: 'true'
|
||||
IndentCaseLabels: 'true'
|
||||
|
|
@ -44,7 +44,7 @@ SpacesInSquareBrackets: 'false'
|
|||
Standard: Cpp11
|
||||
TabWidth: '2'
|
||||
UseTab: Never
|
||||
SortIncludes: 'true'
|
||||
SortIncludes: 'false'
|
||||
ReflowComments: 'false'
|
||||
BraceWrapping: {
|
||||
AfterClass: 'true'
|
||||
|
|
@ -58,7 +58,7 @@ BraceWrapping: {
|
|||
BeforeElse: 'true'
|
||||
IndentBraces: 'false'
|
||||
}
|
||||
PenaltyExcessCharacter: 9999
|
||||
PenaltyExcessCharacter: 1
|
||||
PenaltyBreakBeforeFirstCallParameter: 40
|
||||
PenaltyBreakFirstLessLess: 1
|
||||
PenaltyBreakComment: 30
|
||||
|
|
|
|||
|
|
@ -38,12 +38,11 @@ void ObjLoader::loadModel(const std::string& filename)
|
|||
for(const auto& material : reader.GetMaterials())
|
||||
{
|
||||
MaterialObj m;
|
||||
m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]);
|
||||
m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]);
|
||||
m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]);
|
||||
m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]);
|
||||
m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1],
|
||||
material.transmittance[2]);
|
||||
m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]);
|
||||
m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]);
|
||||
m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]);
|
||||
m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]);
|
||||
m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1], material.transmittance[2]);
|
||||
m.dissolve = material.dissolve;
|
||||
m.ior = material.ior;
|
||||
m.shininess = material.shininess;
|
||||
|
|
@ -67,8 +66,7 @@ void ObjLoader::loadModel(const std::string& filename)
|
|||
{
|
||||
m_vertices.reserve(shape.mesh.indices.size() + m_vertices.size());
|
||||
m_indices.reserve(shape.mesh.indices.size() + m_indices.size());
|
||||
m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(),
|
||||
shape.mesh.material_ids.end());
|
||||
m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(), shape.mesh.material_ids.end());
|
||||
|
||||
for(const auto& index : shape.mesh.indices)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct MaterialObj
|
|||
float shininess = 0.f;
|
||||
float ior = 1.0f; // index of refraction
|
||||
float dissolve = 1.f; // 1 == opaque; 0 == fully transparent
|
||||
// illumination model (see http://www.fileformat.info/format/material/)
|
||||
// illumination model (see http://www.fileformat.info/format/material/)
|
||||
int illum = 0;
|
||||
int textureID = -1;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ The directory structure should be looking like:
|
|||
**********************************************************
|
||||
|
||||
|
||||
!!! Warning
|
||||
!!! Warning CMake
|
||||
**Run CMake** in vk_raytracing_tutorial_KHR.
|
||||
|
||||
!!! Warning Beta Vulkan SDK
|
||||
|
|
|
|||
|
|
@ -202,18 +202,18 @@ void HelloVulkan::createLanternIndirectBuffer()
|
|||
|
||||
// m_alloc behind the scenes uses cmdBuf to transfer data to the buffer.
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
|
||||
using Usage = vk::BufferUsageFlagBits;
|
||||
m_lanternIndirectBuffer =
|
||||
m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount,
|
||||
Usage::eIndirectBuffer | Usage::eTransferDst
|
||||
| Usage::eShaderDeviceAddress | Usage::eStorageBuffer,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal);
|
||||
using Usage = VkBufferUsageFlagBits;
|
||||
m_lanternIndirectBuffer = m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount,
|
||||
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
std::vector<LanternIndirectEntry> entries(m_lanternCount);
|
||||
for (size_t i = 0; i < m_lanternCount; ++i) entries[i].lantern = m_lanterns[i];
|
||||
cmdBuf.updateBuffer(m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data());
|
||||
for(size_t i = 0; i < m_lanternCount; ++i)
|
||||
entries[i].lantern = m_lanterns[i];
|
||||
vkCmdUpdateBuffer(cmdBuf, m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data());
|
||||
|
||||
cmdBufGet.submitAndWait(cmdBuf);
|
||||
}
|
||||
|
|
@ -370,12 +370,12 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes.
|
|||
`hello_vulkan.h`:
|
||||
|
||||
```` C
|
||||
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
|
||||
vk::DescriptorPool m_lanternIndirectDescPool;
|
||||
vk::DescriptorSetLayout m_lanternIndirectDescSetLayout;
|
||||
vk::DescriptorSet m_lanternIndirectDescSet;
|
||||
vk::PipelineLayout m_lanternIndirectCompPipelineLayout;
|
||||
vk::Pipeline m_lanternIndirectCompPipeline;
|
||||
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
|
||||
VkDescriptorPool m_lanternIndirectDescPool;
|
||||
VkDescriptorSetLayout m_lanternIndirectDescSetLayout;
|
||||
VkDescriptorSet m_lanternIndirectDescSet;
|
||||
VkPipelineLayout m_lanternIndirectCompPipelineLayout;
|
||||
VkPipeline m_lanternIndirectCompPipeline;
|
||||
````
|
||||
|
||||
`hello_vulkan.cpp`:
|
||||
|
|
@ -385,26 +385,25 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes.
|
|||
// The compute shader just needs read/write access to the buffer of LanternIndirectEntry.
|
||||
void HelloVulkan::createLanternIndirectDescriptorSet()
|
||||
{
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
||||
|
||||
// Lantern buffer (binding = 0)
|
||||
m_lanternIndirectDescSetLayoutBind.addBinding( //
|
||||
vkDSLB(0, vkDT::eStorageBuffer, 1, vkSS::eCompute));
|
||||
m_lanternIndirectDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
|
||||
m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device);
|
||||
m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device);
|
||||
m_lanternIndirectDescSet =
|
||||
m_device.allocateDescriptorSets({m_lanternIndirectDescPool, 1, &m_lanternIndirectDescSetLayout})[0];
|
||||
|
||||
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||
allocateInfo.descriptorPool = m_lanternIndirectDescPool;
|
||||
allocateInfo.descriptorSetCount = 1;
|
||||
allocateInfo.pSetLayouts = &m_lanternIndirectDescSetLayout;
|
||||
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_lanternIndirectDescSet);
|
||||
|
||||
|
||||
assert(m_lanternIndirectBuffer.buffer);
|
||||
vk::DescriptorBufferInfo lanternBufferInfo{
|
||||
m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)};
|
||||
VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)};
|
||||
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
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
|
||||
|
|
@ -412,32 +411,31 @@ void HelloVulkan::createLanternIndirectDescriptorSet()
|
|||
void HelloVulkan::createLanternIndirectCompPipeline()
|
||||
{
|
||||
// Compile compute shader and package as stage.
|
||||
vk::ShaderModule computeShader =
|
||||
nvvk::createShaderModule(m_device, //
|
||||
nvh::loadFile("shaders/lanternIndirect.comp.spv", true, defaultSearchPaths, true));
|
||||
vk::PipelineShaderStageCreateInfo stageInfo;
|
||||
stageInfo.setStage(vk::ShaderStageFlagBits::eCompute);
|
||||
stageInfo.setModule(computeShader);
|
||||
stageInfo.setPName("main");
|
||||
VkShaderModule computeShader =
|
||||
nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true));
|
||||
VkPipelineShaderStageCreateInfo stageInfo{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
||||
stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
stageInfo.module = computeShader;
|
||||
stageInfo.pName = "main";
|
||||
|
||||
// Set up push constant and pipeline layout.
|
||||
constexpr auto pushSize = static_cast<uint32_t>(sizeof(m_lanternIndirectPushConstants));
|
||||
vk::PushConstantRange pushCRange = {vk::ShaderStageFlagBits::eCompute, 0, pushSize};
|
||||
constexpr auto pushSize = static_cast<uint32_t>(sizeof(m_lanternIndirectPushConstants));
|
||||
VkPushConstantRange pushCRange = {VK_SHADER_STAGE_COMPUTE_BIT, 0, pushSize};
|
||||
static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant");
|
||||
vk::PipelineLayoutCreateInfo layoutInfo;
|
||||
layoutInfo.setSetLayoutCount(1);
|
||||
layoutInfo.setPSetLayouts(&m_lanternIndirectDescSetLayout);
|
||||
layoutInfo.setPushConstantRangeCount(1);
|
||||
layoutInfo.setPPushConstantRanges(&pushCRange);
|
||||
m_lanternIndirectCompPipelineLayout = m_device.createPipelineLayout(layoutInfo);
|
||||
VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
layoutInfo.setLayoutCount = 1;
|
||||
layoutInfo.pSetLayouts = &m_lanternIndirectDescSetLayout;
|
||||
layoutInfo.pushConstantRangeCount = 1;
|
||||
layoutInfo.pPushConstantRanges = &pushCRange;
|
||||
vkCreatePipelineLayout(m_device, &layoutInfo, nullptr, &m_lanternIndirectCompPipelineLayout);
|
||||
|
||||
// Create compute pipeline.
|
||||
vk::ComputePipelineCreateInfo pipelineInfo;
|
||||
pipelineInfo.setStage(stageInfo);
|
||||
pipelineInfo.setLayout(m_lanternIndirectCompPipelineLayout);
|
||||
m_lanternIndirectCompPipeline = static_cast<const vk::Pipeline&>(m_device.createComputePipeline({}, pipelineInfo));
|
||||
VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
|
||||
pipelineInfo.stage = stageInfo;
|
||||
pipelineInfo.layout = m_lanternIndirectCompPipelineLayout;
|
||||
vkCreateComputePipelines(m_device, {}, 1, &pipelineInfo, nullptr, &m_lanternIndirectCompPipeline);
|
||||
|
||||
m_device.destroy(computeShader);
|
||||
vkDestroyShaderModule(m_device, computeShader, nullptr);
|
||||
}
|
||||
````
|
||||
|
||||
|
|
@ -464,61 +462,72 @@ pipeline barrier synchronizing access to the `LanternIndirectEntry` array
|
|||
between the compute shader and indirect draw stages.
|
||||
|
||||
```` C
|
||||
void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Ray Tracing the scene
|
||||
//
|
||||
// The raytracing is split into multiple passes:
|
||||
//
|
||||
// First pass fills in the initial values for every pixel in the output image.
|
||||
// Illumination and shadow rays come from the main light.
|
||||
//
|
||||
// Subsequently, one lantern pass is run for each lantern in the scene. We run
|
||||
// a compute shader to calculate a bounding scissor rectangle for each lantern's light
|
||||
// effect. This is stored in m_lanternIndirectBuffer. Then an indirect trace rays command
|
||||
// is run for every lantern within its scissor rectangle. The lanterns' light
|
||||
// contribution is additively blended into the output image.
|
||||
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
||||
{
|
||||
// Before tracing rays, we need to dispatch the compute shaders that
|
||||
// fill in the ray trace indirect parameters for each lantern pass.
|
||||
|
||||
// First, barrier before, ensure writes aren't visible to previous frame.
|
||||
vk::BufferMemoryBarrier bufferBarrier;
|
||||
bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eIndirectCommandRead);
|
||||
bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderWrite);
|
||||
bufferBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
||||
bufferBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
||||
bufferBarrier.setBuffer(m_lanternIndirectBuffer.buffer);
|
||||
bufferBarrier.offset = 0;
|
||||
bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0];
|
||||
cmdBuf.pipelineBarrier( //
|
||||
vk::PipelineStageFlagBits::eDrawIndirect, //
|
||||
vk::PipelineStageFlagBits::eComputeShader,//
|
||||
vk::DependencyFlags(0), //
|
||||
{}, {bufferBarrier}, {});
|
||||
VkBufferMemoryBarrier bufferBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
||||
bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
bufferBarrier.buffer = m_lanternIndirectBuffer.buffer;
|
||||
bufferBarrier.offset = 0;
|
||||
bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0];
|
||||
vkCmdPipelineBarrier(cmdBuf,
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, //
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
|
||||
VkDependencyFlags(0), //
|
||||
0, nullptr, 1, &bufferBarrier, 0, nullptr);
|
||||
|
||||
// Bind compute shader, update push constant and descriptors, dispatch compute.
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipeline);
|
||||
nvmath::mat4 view = getViewMatrix();
|
||||
m_lanternIndirectPushConstants.viewRowX = view.row(0);
|
||||
m_lanternIndirectPushConstants.viewRowY = view.row(1);
|
||||
m_lanternIndirectPushConstants.viewRowZ = view.row(2);
|
||||
m_lanternIndirectPushConstants.proj = getProjMatrix();
|
||||
m_lanternIndirectPushConstants.nearZ = nearZ;
|
||||
m_lanternIndirectPushConstants.screenX = m_size.width;
|
||||
m_lanternIndirectPushConstants.screenY = m_size.height;
|
||||
m_lanternIndirectPushConstants.lanternCount = m_lanternCount;
|
||||
cmdBuf.pushConstants<LanternIndirectPushConstants>(
|
||||
m_lanternIndirectCompPipelineLayout,
|
||||
vk::ShaderStageFlagBits::eCompute,
|
||||
0, m_lanternIndirectPushConstants);
|
||||
cmdBuf.bindDescriptorSets(
|
||||
vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipelineLayout, 0, {m_lanternIndirectDescSet}, {});
|
||||
cmdBuf.dispatch(1, 1, 1);
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipeline);
|
||||
nvmath::mat4 view = getViewMatrix();
|
||||
m_lanternIndirectPushConstants.viewRowX = view.row(0);
|
||||
m_lanternIndirectPushConstants.viewRowY = view.row(1);
|
||||
m_lanternIndirectPushConstants.viewRowZ = view.row(2);
|
||||
m_lanternIndirectPushConstants.proj = getProjMatrix();
|
||||
m_lanternIndirectPushConstants.nearZ = nearZ;
|
||||
m_lanternIndirectPushConstants.screenX = m_size.width;
|
||||
m_lanternIndirectPushConstants.screenY = m_size.height;
|
||||
m_lanternIndirectPushConstants.lanternCount = int32_t(m_lanternCount);
|
||||
vkCmdPushConstants(cmdBuf, m_lanternIndirectCompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0,
|
||||
sizeof(LanternIndirectPushConstants), &m_lanternIndirectPushConstants);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipelineLayout, 0, 1,
|
||||
&m_lanternIndirectDescSet, 0, nullptr);
|
||||
vkCmdDispatch(cmdBuf, 1, 1, 1);
|
||||
|
||||
// Ensure compute results are visible when doing indirect ray trace.
|
||||
bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
||||
bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eIndirectCommandRead);
|
||||
cmdBuf.pipelineBarrier( //
|
||||
vk::PipelineStageFlagBits::eComputeShader, //
|
||||
vk::PipelineStageFlagBits::eDrawIndirect, //
|
||||
vk::DependencyFlags(0), //
|
||||
{}, {bufferBarrier}, {});
|
||||
bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
||||
vkCmdPipelineBarrier(cmdBuf,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, //
|
||||
VkDependencyFlags(0), //
|
||||
0, nullptr, 1, &bufferBarrier, 0, nullptr);
|
||||
|
||||
|
||||
// Now move on to the actual ray tracing.
|
||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
||||
````
|
||||
|
||||
!!! TIP `eDrawIndirect`
|
||||
`vk::PipelineStageFlagBits::eDrawIndirect` (`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`)
|
||||
!!! TIP `VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`
|
||||
`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`
|
||||
covers the stage that sources indirect paramaters for compute and ray trace
|
||||
indirect commands, not just graphics draw indirect commands.
|
||||
|
||||
|
|
@ -542,7 +551,7 @@ they were factored out to common code in `hello_vulkan.h`.
|
|||
The function for updating the uniform buffer is tweaked to match.
|
||||
|
||||
```` C
|
||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
const float aspectRatio = m_size.width / static_cast<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
|
||||
|
||||
```` C
|
||||
// Package vertex and index buffers as BlasInput.
|
||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_lanternVertexBuffer.buffer});
|
||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_lanternIndexBuffer.buffer});
|
||||
// Package vertex and index buffers as BlasInput.
|
||||
VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternVertexBuffer.buffer);
|
||||
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternIndexBuffer.buffer);
|
||||
|
||||
uint32_t maxPrimitiveCount = uint32_t(indices.size() / 3);
|
||||
auto maxPrimitiveCount = uint32_t(indices.size() / 3);
|
||||
|
||||
// Describe buffer as packed array of float vec3.
|
||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data.
|
||||
triangles.setVertexData(vertexAddress);
|
||||
triangles.setVertexStride(sizeof(nvmath::vec3f));
|
||||
// Describe index data (32-bit unsigned int)
|
||||
triangles.setIndexType(vk::IndexType::eUint32);
|
||||
triangles.setIndexData(indexAddress);
|
||||
// Indicate identity transform by setting transformData to null device pointer.
|
||||
triangles.setTransformData({});
|
||||
triangles.setMaxVertex(vertices.size());
|
||||
// Describe buffer as packed array of float vec3.
|
||||
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||
triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
|
||||
triangles.vertexData.deviceAddress = vertexAddress;
|
||||
triangles.vertexStride = sizeof(nvmath::vec3f);
|
||||
// Describe index data (32-bit unsigned int)
|
||||
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
triangles.indexData.deviceAddress = indexAddress;
|
||||
// Indicate identity transform by setting transformData to null device pointer.
|
||||
//triangles.transformData = {};
|
||||
triangles.maxVertex = uint32_t(vertices.size());
|
||||
|
||||
// Identify the above data as containing opaque triangles.
|
||||
vk::AccelerationStructureGeometryKHR asGeom;
|
||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
||||
asGeom.geometry.setTriangles(triangles);
|
||||
// Identify the above data as containing opaque triangles.
|
||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||
asGeom.geometry.triangles = triangles;
|
||||
|
||||
// The entire array will be used to build the BLAS.
|
||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.setFirstVertex(0);
|
||||
offset.setPrimitiveCount(maxPrimitiveCount);
|
||||
offset.setPrimitiveOffset(0);
|
||||
offset.setTransformOffset(0);
|
||||
// The entire array will be used to build the BLAS.
|
||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.firstVertex = 0;
|
||||
offset.primitiveCount = maxPrimitiveCount;
|
||||
offset.primitiveOffset = 0;
|
||||
offset.transformOffset = 0;
|
||||
|
||||
// Our blas is made from only one geometry, but could be made of many geometries
|
||||
m_lanternBlasInput.asGeometry.emplace_back(asGeom);
|
||||
m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset);
|
||||
// Our blas is made from only one geometry, but could be made of many geometries
|
||||
m_lanternBlasInput.asGeometry.emplace_back(asGeom);
|
||||
m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset);
|
||||
````
|
||||
|
||||
The principle difference from before is that the vertex array is now a packed array of
|
||||
|
|
@ -647,7 +656,7 @@ void HelloVulkan::createBottomLevelAS()
|
|||
m_lanternBlasId = allBlas.size();
|
||||
allBlas.emplace_back(m_lanternBlasInput);
|
||||
|
||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||
}
|
||||
````
|
||||
|
||||
|
|
@ -696,7 +705,7 @@ void HelloVulkan::createTopLevelAS()
|
|||
tlas.emplace_back(lanternInstance);
|
||||
}
|
||||
|
||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||
}
|
||||
````
|
||||
|
||||
|
|
@ -749,25 +758,21 @@ The last task is done in `HelloVulkan::createRtDescriptorSet`
|
|||
//
|
||||
void HelloVulkan::createRtDescriptorSet()
|
||||
{
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
||||
|
||||
// ...
|
||||
|
||||
// Lantern buffer (binding = 2)
|
||||
m_rtDescSetLayoutBind.addBinding( //
|
||||
vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR));
|
||||
m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||
assert(m_lanternCount > 0);
|
||||
|
||||
// ...
|
||||
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
|
||||
// ...
|
||||
|
||||
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.
|
||||
|
||||
```` C
|
||||
// OBJ Primary Ray Hit Group - Closest Hit + AnyHit (not used)
|
||||
vk::ShaderModule chitSM =
|
||||
nvvk::createShaderModule(m_device, //
|
||||
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
|
||||
|
||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
||||
m_rtShaderGroups.push_back(hg);
|
||||
|
||||
// Lantern Primary Ray Hit Group
|
||||
vk::ShaderModule lanternChitSM =
|
||||
nvvk::createShaderModule(m_device, //
|
||||
nvh::loadFile("shaders/lantern.rchit.spv", true, paths, true));
|
||||
|
||||
vk::RayTracingShaderGroupCreateInfoKHR lanternHg{
|
||||
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"});
|
||||
m_rtShaderGroups.push_back(lanternHg);
|
||||
|
||||
enum StageIndices
|
||||
{
|
||||
// ...
|
||||
eClosestHit,
|
||||
eClosestHitLantern,
|
||||
eShaderGroupCount
|
||||
};
|
||||
// ...
|
||||
|
||||
m_device.destroy(lanternChitSM);
|
||||
// OBJ Primary Ray Hit Group - Closest Hit
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
stages[eClosestHit] = stage;
|
||||
|
||||
// Lantern Primary Ray Hit Group
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
stages[eClosestHitLantern] = stage;
|
||||
|
||||
// ...
|
||||
|
||||
// closest hit shader
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = eClosestHit;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
group.closestHitShader = eClosestHitLantern;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
````
|
||||
|
||||
We don't have to modify `HelloVulkan::createRtShaderBindingTable`. Changes to the number of
|
||||
|
|
@ -1102,41 +1109,53 @@ groups for primary rays. Add the following code to `HelloVulkan::createRtPipelin
|
|||
after loading `raytraceShadow.rmiss.spv`.
|
||||
|
||||
```` C
|
||||
// Miss shader 2 is invoked when a shadow ray for lantern lighting misses the
|
||||
// lantern. It shouldn't be invoked, but I include it just in case.
|
||||
vk::ShaderModule lanternmissSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("shaders/lanternShadow.rmiss.spv", true, paths, true));
|
||||
// Miss shader 2 is invoked when a shadow ray for lantern lighting misses the
|
||||
// lantern. It shouldn't be invoked, but I include it just in case.
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||
stages[eMissLantern] = stage;
|
||||
````
|
||||
|
||||
and add this code for loading the last 2 closest hit shaders after loading
|
||||
`lantern.rchit.spv`:
|
||||
|
||||
```` C
|
||||
// OBJ Lantern Shadow Ray Hit Group
|
||||
vk::ShaderModule lanternShadowObjChitSM =
|
||||
nvvk::createShaderModule(m_device, //
|
||||
nvh::loadFile("shaders/lanternShadowObj.rchit.spv", true, paths, true));
|
||||
// Lantern Primary Ray Hit Group
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
stages[eClosestHitLantern] = stage;
|
||||
|
||||
// OBJ Lantern Shadow Ray Hit Group
|
||||
stage.module =
|
||||
nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
stages[eClosestHitLanternShdObj] = stage;
|
||||
|
||||
// ...
|
||||
|
||||
// Lantern Shadow Miss
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.generalShader = eMissLantern;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
|
||||
// closest hit shader
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = eClosestHit;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
group.closestHitShader = eClosestHitLantern;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
group.closestHitShader = eClosestHitLanternShdObj;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
group.closestHitShader = eClosestHitLanternShd;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{
|
||||
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
lanternShadowObjHg.setClosestHitShader(static_cast<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.
|
||||
|
|
@ -1386,7 +1405,7 @@ pass. There are minimal changes from before, we just have to
|
|||
to account for the added shaders.
|
||||
|
||||
```` C
|
||||
using Stride = vk::StridedDeviceAddressRegionKHR;
|
||||
using Stride = VkStridedDeviceAddressRegionKHR;
|
||||
std::array<Stride, 4> strideAddresses{
|
||||
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
|
||||
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss
|
||||
|
|
@ -1394,10 +1413,8 @@ pass. There are minimal changes from before, we just have to
|
|||
Stride{0u, 0u, 0u}}; // callable
|
||||
|
||||
// First pass, illuminate scene with global light.
|
||||
cmdBuf.traceRaysKHR(
|
||||
&strideAddresses[0], &strideAddresses[1], //
|
||||
&strideAddresses[2], &strideAddresses[3], //
|
||||
m_size.width, m_size.height, 1);
|
||||
vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3],
|
||||
m_size.width, m_size.height, 1);
|
||||
````
|
||||
|
||||
After that, we can open a loop for performing all lantern passes.
|
||||
|
|
@ -1412,25 +1429,23 @@ Because the additive blending in the shader requires read-modify-write operation
|
|||
we need a barrier between every pass.
|
||||
|
||||
```` C
|
||||
// Barrier to ensure previous pass finished.
|
||||
vk::Image offscreenImage{m_offscreenColor.image};
|
||||
vk::ImageSubresourceRange colorRange(
|
||||
vk::ImageAspectFlagBits::eColor, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS
|
||||
);
|
||||
vk::ImageMemoryBarrier imageBarrier;
|
||||
imageBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imageBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imageBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
||||
imageBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
|
||||
imageBarrier.setImage(offscreenImage);
|
||||
imageBarrier.setSubresourceRange(colorRange);
|
||||
imageBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
||||
imageBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
cmdBuf.pipelineBarrier(
|
||||
vk::PipelineStageFlagBits::eRayTracingShaderKHR, //
|
||||
vk::PipelineStageFlagBits::eRayTracingShaderKHR, //
|
||||
vk::DependencyFlags(0), //
|
||||
{}, {}, {imageBarrier});
|
||||
// Barrier to ensure previous pass finished.
|
||||
VkImage offscreenImage{m_offscreenColor.image};
|
||||
VkImageSubresourceRange colorRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS};
|
||||
VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
imageBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imageBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageBarrier.image = offscreenImage;
|
||||
imageBarrier.subresourceRange = colorRange;
|
||||
imageBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
imageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
vkCmdPipelineBarrier(cmdBuf,
|
||||
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, //
|
||||
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, //
|
||||
VkDependencyFlags(0), //
|
||||
0, nullptr, 0, nullptr, 1, &imageBarrier);
|
||||
````
|
||||
|
||||
Then, we can pass the number of the lantern pass being performed (`i`), and look
|
||||
|
|
@ -1443,17 +1458,18 @@ is the first member of `LanternIndirectEntry`.
|
|||
```` C
|
||||
// Set lantern pass number.
|
||||
m_rtPushConstants.lanternPassNumber = i;
|
||||
cmdBuf.pushConstants<RtPushConstant>(m_rtPipelineLayout,
|
||||
vk::ShaderStageFlagBits::eRaygenKHR
|
||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
||||
| vk::ShaderStageFlagBits::eMissKHR,
|
||||
0, m_rtPushConstants);
|
||||
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
|
||||
0, sizeof(RtPushConstant), &m_rtPushConstants);
|
||||
|
||||
|
||||
VkDeviceAddress indirectDeviceAddress =
|
||||
nvvk::getBufferDeviceAddress(m_device, m_lanternIndirectBuffer.buffer) + i * sizeof(LanternIndirectEntry);
|
||||
|
||||
// Execute lantern pass.
|
||||
cmdBuf.traceRaysIndirectKHR(
|
||||
&strideAddresses[0], &strideAddresses[1], //
|
||||
&strideAddresses[2], &strideAddresses[3], //
|
||||
m_device.getBufferAddress({m_lanternIndirectBuffer.buffer}) + i * sizeof(LanternIndirectEntry));
|
||||
vkCmdTraceRaysIndirectKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], //
|
||||
&strideAddresses[2], &strideAddresses[3], //
|
||||
indirectDeviceAddress);
|
||||
}
|
||||
````
|
||||
|
||||
|
|
@ -1480,10 +1496,10 @@ void HelloVulkan::destroyResources()
|
|||
|
||||
// #VKRay
|
||||
// ...
|
||||
m_device.destroy(m_lanternIndirectDescPool);
|
||||
m_device.destroy(m_lanternIndirectDescSetLayout);
|
||||
m_device.destroy(m_lanternIndirectCompPipeline);
|
||||
m_device.destroy(m_lanternIndirectCompPipelineLayout);
|
||||
vkDestroyDescriptorPool(m_device, m_lanternIndirectDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_lanternIndirectDescSetLayout, nullptr);
|
||||
vkDestroyPipeline(m_device, m_lanternIndirectCompPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_lanternIndirectCompPipelineLayout, nullptr);
|
||||
m_alloc.destroy(m_lanternIndirectBuffer);
|
||||
m_alloc.destroy(m_lanternVertexBuffer);
|
||||
m_alloc.destroy(m_lanternIndexBuffer);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Licensed as public domain or BSD 2-clause, whichever is more convenient for you.
|
||||
Originally from https://github.com/aras-p/markdeep-docs-style */
|
||||
body {
|
||||
max-width: 50em;
|
||||
max-width: 80em;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
text-align: left;
|
||||
/*margin: 1.5em;*/
|
||||
|
|
|
|||
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
|
||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
||||
Project(${PROJNAME})
|
||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||
project(${PROJNAME} LANGUAGES C CXX)
|
||||
message(STATUS "-------------------------------")
|
||||
message(STATUS "Processing Project ${PROJNAME}:")
|
||||
|
||||
|
|
@ -28,6 +28,7 @@ file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
|||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
||||
include_directories(${TUTO_KHR_DIR}/common)
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# GLSL to SPIR-V custom build
|
||||
compile_glsl_directory(
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@
|
|||
|
||||
|
||||
#include <sstream>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
|
||||
|
|
@ -29,6 +27,7 @@ extern std::vector<std::string> defaultSearchPaths;
|
|||
#include "obj_loader.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
|
||||
#include "hello_vulkan.h"
|
||||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
|
|
@ -40,6 +39,9 @@ extern std::vector<std::string> defaultSearchPaths;
|
|||
#include "nvvk/renderpasses_vk.hpp"
|
||||
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// Holding the camera matrices
|
||||
struct CameraMatrices
|
||||
{
|
||||
|
|
@ -50,16 +52,14 @@ struct CameraMatrices
|
|||
nvmath::mat4f projInverse;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Keep the handle on the device
|
||||
// Initialize the tool to do all our allocations: buffers, images
|
||||
//
|
||||
void HelloVulkan::setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily)
|
||||
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||
{
|
||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
||||
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||
m_alloc.init(instance, device, physicalDevice);
|
||||
m_debug.setup(m_device);
|
||||
|
||||
|
|
@ -71,46 +71,46 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Called at each frame to update the camera matrix
|
||||
//
|
||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
// Prepare new UBO contents on host.
|
||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||
CameraMatrices hostUBO = {};
|
||||
hostUBO.view = CameraManip.getMatrix();
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
||||
// #VKRay
|
||||
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
||||
|
||||
// UBO on the device, and what stages access it.
|
||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages =
|
||||
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
|
||||
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||
|
||||
// Ensure that the modified UBO is not visible to previous frames.
|
||||
vk::BufferMemoryBarrier beforeBarrier;
|
||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
beforeBarrier.setBuffer(deviceUBO);
|
||||
beforeBarrier.setOffset(0);
|
||||
beforeBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
||||
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
beforeBarrier.buffer = deviceUBO;
|
||||
beforeBarrier.offset = 0;
|
||||
beforeBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||
|
||||
|
||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||
// buffer so it is okay to deallocate when the function returns).
|
||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
||||
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||
|
||||
// Making sure the updated UBO will be visible.
|
||||
vk::BufferMemoryBarrier afterBarrier;
|
||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
afterBarrier.setBuffer(deviceUBO);
|
||||
afterBarrier.setOffset(0);
|
||||
afterBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
afterBarrier.buffer = deviceUBO;
|
||||
afterBarrier.offset = 0;
|
||||
afterBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -118,39 +118,33 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
|||
//
|
||||
void HelloVulkan::createDescriptorSetLayout()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||
|
||||
// Camera matrices (binding = 0)
|
||||
m_descSetLayoutBind.addBinding(
|
||||
vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR));
|
||||
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
|
||||
// Materials (binding = 1)
|
||||
m_descSetLayoutBind.addBinding(
|
||||
vkDS(1, vkDT::eStorageBuffer, nbObj + 1, // Adding Implicit mat too
|
||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj + 1,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
// Scene description (binding = 2)
|
||||
m_descSetLayoutBind.addBinding( //
|
||||
vkDS(2, vkDT::eStorageBuffer, 1,
|
||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
// Textures (binding = 3)
|
||||
m_descSetLayoutBind.addBinding(
|
||||
vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR));
|
||||
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
// Materials (binding = 4)
|
||||
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj,
|
||||
vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
// Storing vertices (binding = 5)
|
||||
m_descSetLayoutBind.addBinding( //
|
||||
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||
// Storing indices (binding = 6)
|
||||
m_descSetLayoutBind.addBinding( //
|
||||
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
||||
// Storing implicit obj (binding = 7)
|
||||
m_descSetLayoutBind.addBinding( //
|
||||
vkDS(7, vkDT::eStorageBuffer, 1,
|
||||
vkSS::eClosestHitKHR | vkSS::eIntersectionKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR
|
||||
| VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
|
||||
|
||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||
|
|
@ -163,78 +157,76 @@ void HelloVulkan::createDescriptorSetLayout()
|
|||
//
|
||||
void HelloVulkan::updateDescriptorSet()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
|
||||
// Camera matrices and scene description
|
||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||
|
||||
// All material buffers, 1 buffer per OBJ
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiVert;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiIdx;
|
||||
for(auto& model : m_objModel)
|
||||
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||
std::vector<VkDescriptorBufferInfo> dbiVert;
|
||||
std::vector<VkDescriptorBufferInfo> dbiIdx;
|
||||
for(auto& m : m_objModel)
|
||||
{
|
||||
dbiMat.emplace_back(model.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMatIdx.emplace_back(model.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiVert.emplace_back(model.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiIdx.emplace_back(model.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
}
|
||||
dbiMat.emplace_back(m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE); // Adding implicit mat
|
||||
dbiMat.push_back({m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE}); // Adding implicit mat
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data()));
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
|
||||
|
||||
// All texture samplers
|
||||
std::vector<vk::DescriptorImageInfo> diit;
|
||||
std::vector<VkDescriptorImageInfo> diit;
|
||||
for(auto& texture : m_textures)
|
||||
{
|
||||
diit.emplace_back(texture.descriptor);
|
||||
}
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||
|
||||
vk::DescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiImplDesc));
|
||||
|
||||
// Writing the information
|
||||
m_device.updateDescriptorSets(static_cast<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
|
||||
//
|
||||
void HelloVulkan::createGraphicsPipeline()
|
||||
{
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
||||
sizeof(ObjPushConstants)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstants)};
|
||||
|
||||
// Creating the Pipeline Layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_descSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||
|
||||
|
||||
// Creating the Pipeline
|
||||
std::vector<std::string> paths = defaultSearchPaths;
|
||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass());
|
||||
gpb.depthStencilState.depthTestEnable = true;
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||
gpb.addAttributeDescriptions({
|
||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
});
|
||||
|
||||
m_graphicsPipeline = gpb.createPipeline();
|
||||
|
|
@ -246,8 +238,6 @@ void HelloVulkan::createGraphicsPipeline()
|
|||
//
|
||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
|
||||
LOGI("Loading File: %s \n", filename.c_str());
|
||||
ObjLoader loader;
|
||||
loader.loadModel(filename);
|
||||
|
|
@ -271,18 +261,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
||||
|
||||
// Create the buffers on Device and copy vertices, indices and materials
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
model.vertexBuffer =
|
||||
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
|
||||
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
||||
model.indexBuffer =
|
||||
m_alloc.createBuffer(cmdBuf, loader.m_indices,
|
||||
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
|
||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
// Creates all textures found
|
||||
createTextureImages(cmdBuf, loader.m_textures);
|
||||
cmdBufGet.submitAndWait(cmdBuf);
|
||||
|
|
@ -298,17 +284,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
m_objInstance.emplace_back(instance);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Creating the uniform buffer holding the camera matrices
|
||||
// - Buffer is host visible
|
||||
//
|
||||
void HelloVulkan::createUniformBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
using vkMP = vk::MemoryPropertyFlagBits;
|
||||
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||
}
|
||||
|
||||
|
|
@ -320,11 +304,10 @@ void HelloVulkan::createUniformBuffer()
|
|||
//
|
||||
void HelloVulkan::createSceneDescriptionBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||
|
||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
cmdGen.submitAndWait(cmdBuf);
|
||||
m_alloc.finalizeAndReleaseStaging();
|
||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||
|
|
@ -333,15 +316,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Creating all textures and samplers
|
||||
//
|
||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures)
|
||||
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, 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{
|
||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
|
||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||
if(textures.empty() && m_textures.empty())
|
||||
|
|
@ -349,18 +332,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
nvvk::Texture texture;
|
||||
|
||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||
vk::DeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = vk::Extent2D(1, 1);
|
||||
VkDeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = VkExtent2D{1, 1};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||
|
||||
// Creating the VKImage
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
// Creating the dummy texture
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
else
|
||||
|
|
@ -373,8 +355,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
o << "media/textures/" << texture;
|
||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||
|
||||
stbi_uc* stbi_pixels =
|
||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
|
||||
std::array<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());
|
||||
}
|
||||
|
||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
||||
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||
|
||||
{
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||
vk::ImageViewCreateInfo ivInfo =
|
||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
|
|
@ -411,10 +391,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
//
|
||||
void HelloVulkan::destroyResources()
|
||||
{
|
||||
m_device.destroy(m_graphicsPipeline);
|
||||
m_device.destroy(m_pipelineLayout);
|
||||
m_device.destroy(m_descPool);
|
||||
m_device.destroy(m_descSetLayout);
|
||||
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||
|
||||
m_alloc.destroy(m_cameraMat);
|
||||
m_alloc.destroy(m_sceneDesc);
|
||||
m_alloc.destroy(m_implObjects.implBuf);
|
||||
|
|
@ -445,32 +426,31 @@ void HelloVulkan::destroyResources()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Drawing the scene in raster mode
|
||||
//
|
||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
using vkPBP = vk::PipelineBindPoint;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
vk::DeviceSize offset{0};
|
||||
VkDeviceSize offset{0};
|
||||
|
||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||
|
||||
// Dynamic Viewport
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
||||
setViewport(cmdBuf);
|
||||
|
||||
// Drawing all triangles
|
||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||
|
||||
|
||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||
{
|
||||
auto& inst = m_objInstance[i];
|
||||
auto& model = m_objModel[inst.objIndex];
|
||||
m_pushConstants.instanceId = i; // Telling which instance is drawn
|
||||
cmdBuf.pushConstants<ObjPushConstants>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
||||
m_pushConstants);
|
||||
|
||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||
sizeof(ObjPushConstants), &m_pushConstants);
|
||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||
}
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
@ -511,7 +491,7 @@ void HelloVulkan::initRayTracing()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Ray trace the scene
|
||||
//
|
||||
void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
||||
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
|
||||
{
|
||||
updateFrame();
|
||||
if(m_pushConstants.frame >= m_maxFrames)
|
||||
|
|
@ -580,7 +560,7 @@ void HelloVulkan::addImplMaterial(const MaterialObj& mat)
|
|||
//
|
||||
void HelloVulkan::createImplictBuffers()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
using vkBU = VkBufferUsageFlagBits;
|
||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||
|
||||
// Not allowing empty buffers
|
||||
|
|
@ -589,11 +569,11 @@ void HelloVulkan::createImplictBuffers()
|
|||
if(m_implObjects.implMat.empty())
|
||||
m_implObjects.implMat.push_back({});
|
||||
|
||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||
m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl,
|
||||
vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress);
|
||||
m_implObjects.implMatBuf =
|
||||
m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, vkBU::eStorageBuffer);
|
||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||
m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl,
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
|
||||
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
|
||||
m_implObjects.implMatBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
cmdGen.submitAndWait(cmdBuf);
|
||||
m_alloc.finalizeAndReleaseStaging();
|
||||
m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj");
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/appbase_vk.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
|
||||
|
|
@ -56,25 +56,21 @@ using Allocator = nvvk::ResourceAllocatorDedicated;
|
|||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
class HelloVulkan : public nvvk::AppBaseVk
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||
|
||||
Offscreen& offscreen() { return m_offscreen; }
|
||||
Raytracer& raytracer() { return m_raytrace; }
|
||||
|
|
@ -87,12 +83,12 @@ public:
|
|||
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
VkDescriptorPool m_descPool;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
int m_maxFrames{10};
|
||||
void resetFrame();
|
||||
|
|
@ -115,7 +111,7 @@ public:
|
|||
Raytracer m_raytrace;
|
||||
|
||||
void initRayTracing();
|
||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
|
||||
// Implicit
|
||||
ImplInst m_implObjects;
|
||||
|
|
|
|||
|
|
@ -23,21 +23,18 @@
|
|||
// at the top of imgui.cpp.
|
||||
|
||||
#include <array>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
#include "backends/imgui_impl_glfw.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include "hello_vulkan.h"
|
||||
#include "imgui/imgui_camera_widget.h"
|
||||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvpsystem.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/context_vk.hpp"
|
||||
|
||||
#include "imgui/imgui_camera_widget.h"
|
||||
#include <random>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -47,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
// Default search path for shaders
|
||||
std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// GLFW Callback functions
|
||||
static void onErrorCallback(int error, const char* description)
|
||||
{
|
||||
|
|
@ -70,18 +68,15 @@ void renderUI(HelloVulkan& helloVk)
|
|||
|
||||
if(helloVk.m_pushConstants.lightType < 2)
|
||||
{
|
||||
changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x,
|
||||
-20.f, 20.f);
|
||||
changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, -20.f, 20.f);
|
||||
}
|
||||
if(helloVk.m_pushConstants.lightType > 0)
|
||||
{
|
||||
changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x,
|
||||
-1.f, 1.f);
|
||||
changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, -1.f, 1.f);
|
||||
}
|
||||
if(helloVk.m_pushConstants.lightType < 2)
|
||||
{
|
||||
changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f,
|
||||
500.f);
|
||||
changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f);
|
||||
}
|
||||
if(helloVk.m_pushConstants.lightType == 1)
|
||||
{
|
||||
|
|
@ -121,8 +116,7 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window =
|
||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
|
|
@ -151,7 +145,7 @@ int main(int argc, char** argv)
|
|||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#else
|
||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||
|
|
@ -163,18 +157,16 @@ int main(int argc, char** argv)
|
|||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
||||
&accelFeature);
|
||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
||||
&rtPipelineFeature);
|
||||
|
||||
// Creating Vulkan base application
|
||||
nvvk::Context vkctx{};
|
||||
|
|
@ -189,11 +181,10 @@ int main(int argc, char** argv)
|
|||
HelloVulkan helloVk;
|
||||
|
||||
// Window need to be opened to get the surface on which to draw
|
||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
vkctx.setGCTQueueWithPresent(surface);
|
||||
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
||||
vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
helloVk.createDepthBuffer();
|
||||
helloVk.createRenderPass();
|
||||
|
|
@ -202,14 +193,13 @@ int main(int argc, char** argv)
|
|||
// Setup Imgui
|
||||
helloVk.initGUI(0); // Using sub-pass 0
|
||||
|
||||
// Creating scene
|
||||
// Creation of the example
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
|
||||
nvmath::scale_mat4(nvmath::vec3f(0.5f))
|
||||
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f)));
|
||||
nvmath::scale_mat4(nvmath::vec3f(0.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f)));
|
||||
|
||||
std::random_device rd; // Will be used to obtain a seed for the random number engine
|
||||
std::random_device rd; // Will be used to obtain a seed for the random number engine
|
||||
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
|
||||
std::normal_distribution<float> dis(2.0f, 2.0f);
|
||||
std::normal_distribution<float> disn(0.5f, 0.2f);
|
||||
|
|
@ -278,11 +268,12 @@ int main(int argc, char** argv)
|
|||
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
|
||||
// Show UI window.
|
||||
if(helloVk.showGui())
|
||||
{
|
||||
ImGui::NewFrame();
|
||||
ImGuiH::Panel::Begin();
|
||||
bool changed = false;
|
||||
// Edit 3 floats representing a color
|
||||
|
|
@ -292,11 +283,8 @@ int main(int argc, char** argv)
|
|||
if(changed)
|
||||
helloVk.resetFrame();
|
||||
|
||||
|
||||
renderUI(helloVk);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||
ImGuiH::Panel::End();
|
||||
}
|
||||
|
|
@ -305,28 +293,29 @@ int main(int argc, char** argv)
|
|||
helloVk.prepareFrame();
|
||||
|
||||
// Start command buffer of this frame
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
|
||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||
|
||||
// Updating camera buffer
|
||||
helloVk.updateUniformBuffer(cmdBuf);
|
||||
|
||||
// Clearing screen
|
||||
std::array<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});
|
||||
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
|
||||
{
|
||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
offscreenRenderPassBeginInfo.setRenderPass(offscreen.renderPass());
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(offscreen.frameBuffer());
|
||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
offscreenRenderPassBeginInfo.renderPass = offscreen.renderPass();
|
||||
offscreenRenderPassBeginInfo.framebuffer = offscreen.frameBuffer();
|
||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
// Rendering Scene
|
||||
if(useRaytracer)
|
||||
|
|
@ -335,40 +324,41 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
}
|
||||
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
||||
postRenderPassBeginInfo.setClearValueCount(2);
|
||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
postRenderPassBeginInfo.clearValueCount = 2;
|
||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
offscreen.draw(cmdBuf, helloVk.getSize());
|
||||
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
vkEndCommandBuffer(cmdBuf);
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
vkDeviceWaitIdle(helloVk.getDevice());
|
||||
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
|
||||
vkctx.deinit();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
|
|
|||
|
|
@ -32,10 +32,7 @@ extern std::vector<std::string> defaultSearchPaths;
|
|||
// Post-processing
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Offscreen::setup(const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
nvvk::ResourceAllocator* allocator,
|
||||
uint32_t queueFamily)
|
||||
void Offscreen::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
|
||||
{
|
||||
m_device = device;
|
||||
m_alloc = allocator;
|
||||
|
|
@ -46,14 +43,14 @@ void Offscreen::setup(const vk::Device& device,
|
|||
|
||||
void Offscreen::destroy()
|
||||
{
|
||||
m_device.destroy(m_pipeline);
|
||||
m_device.destroy(m_pipelineLayout);
|
||||
m_device.destroy(m_descPool);
|
||||
m_device.destroy(m_dsetLayout);
|
||||
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_dsetLayout, nullptr);
|
||||
vkDestroyRenderPass(m_device, m_renderPass, nullptr);
|
||||
vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
|
||||
m_alloc->destroy(m_colorTexture);
|
||||
m_alloc->destroy(m_depthTexture);
|
||||
m_device.destroy(m_renderPass);
|
||||
m_device.destroy(m_framebuffer);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -66,30 +63,28 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
|
|||
|
||||
// Creating the color image
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(size, m_colorFormat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(
|
||||
size, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
nvvk::Image image = m_alloc->createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_colorTexture = m_alloc->createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc->createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
|
||||
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||
m_colorTexture = m_alloc->createTexture(image, ivInfo, sampler);
|
||||
m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
|
||||
|
||||
// Creating the depth buffer
|
||||
{
|
||||
auto depthCreateInfo =
|
||||
nvvk::makeImage2DCreateInfo(size, m_depthFormat,
|
||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
||||
nvvk::Image image = m_alloc->createImage(depthCreateInfo);
|
||||
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(size, m_depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
nvvk::Image image = m_alloc->createImage(depthCreateInfo);
|
||||
|
||||
vk::ImageViewCreateInfo depthStencilView;
|
||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
||||
depthStencilView.setFormat(m_depthFormat);
|
||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
||||
depthStencilView.setImage(image.image);
|
||||
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthStencilView.format = m_depthFormat;
|
||||
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||
depthStencilView.image = image.image;
|
||||
|
||||
m_depthTexture = m_alloc->createTexture(image, depthStencilView);
|
||||
}
|
||||
|
|
@ -98,11 +93,9 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
|
|||
{
|
||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
||||
vk::ImageAspectFlagBits::eDepth);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
|
||||
genCmdBuf.submitAndWait(cmdBuf);
|
||||
}
|
||||
|
|
@ -111,50 +104,46 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
|
|||
if(!m_renderPass)
|
||||
{
|
||||
m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true,
|
||||
vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
|
||||
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||
}
|
||||
|
||||
// Creating the frame buffer for offscreen
|
||||
std::vector<vk::ImageView> attachments = {m_colorTexture.descriptor.imageView,
|
||||
m_depthTexture.descriptor.imageView};
|
||||
std::vector<VkImageView> attachments = {m_colorTexture.descriptor.imageView, m_depthTexture.descriptor.imageView};
|
||||
|
||||
m_device.destroy(m_framebuffer);
|
||||
vk::FramebufferCreateInfo info;
|
||||
info.setRenderPass(m_renderPass);
|
||||
info.setAttachmentCount(2);
|
||||
info.setPAttachments(attachments.data());
|
||||
info.setWidth(size.width);
|
||||
info.setHeight(size.height);
|
||||
info.setLayers(1);
|
||||
m_framebuffer = m_device.createFramebuffer(info);
|
||||
vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
|
||||
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
info.renderPass = m_renderPass;
|
||||
info.attachmentCount = 2;
|
||||
info.pAttachments = attachments.data();
|
||||
info.width = size.width;
|
||||
info.height = size.height;
|
||||
info.layers = 1;
|
||||
vkCreateFramebuffer(m_device, &info, nullptr, &m_framebuffer);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
|
||||
// The incoming render pass, is in which rendering pass it will be displayed (framebuffer)
|
||||
//
|
||||
void Offscreen::createPipeline(vk::RenderPass& renderPass)
|
||||
void Offscreen::createPipeline(VkRenderPass& renderPass)
|
||||
{
|
||||
// Push constants in the fragment shader
|
||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||
|
||||
// Creating the pipeline layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_dsetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
pipelineLayoutCreateInfo.setLayoutCount = 1;
|
||||
pipelineLayoutCreateInfo.pSetLayouts = &m_dsetLayout;
|
||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_pipelineLayout);
|
||||
|
||||
// Pipeline: completely generic, no vertices
|
||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
||||
true),
|
||||
vk::ShaderStageFlagBits::eVertex);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
||||
vk::ShaderStageFlagBits::eFragment);
|
||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
||||
m_pipeline = pipelineGenerator.createPipeline();
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||
m_pipeline = pipelineGenerator.createPipeline();
|
||||
m_debug.setObjectName(m_pipeline, "post");
|
||||
}
|
||||
|
||||
|
|
@ -164,11 +153,7 @@ void Offscreen::createPipeline(vk::RenderPass& renderPass)
|
|||
//
|
||||
void Offscreen::createDescriptor()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
m_dsetLayoutBinding.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_dsetLayoutBinding.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device);
|
||||
m_descPool = m_dsetLayoutBinding.createPool(m_device);
|
||||
m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout);
|
||||
|
|
@ -179,26 +164,28 @@ void Offscreen::createDescriptor()
|
|||
//
|
||||
void Offscreen::updateDescriptorSet()
|
||||
{
|
||||
vk::WriteDescriptorSet writeDescriptorSets =
|
||||
m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor);
|
||||
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
VkWriteDescriptorSet writeDescriptorSets = m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor);
|
||||
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Draw a full screen quad with the attached image
|
||||
//
|
||||
void Offscreen::draw(vk::CommandBuffer cmdBuf, VkExtent2D& size)
|
||||
void Offscreen::draw(VkCommandBuffer cmdBuf, VkExtent2D& size)
|
||||
{
|
||||
m_debug.beginLabel(cmdBuf, "Post");
|
||||
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)size.width, (float)size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {size.width, size.height}}});
|
||||
VkViewport viewport{0, 0, (float)size.width, (float)size.height, 0, 1};
|
||||
vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
|
||||
VkRect2D scissor{{0, 0}, {size.width, size.height}};
|
||||
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
|
||||
|
||||
|
||||
auto aspectRatio = static_cast<float>(size.width) / static_cast<float>(size.height);
|
||||
cmdBuf.pushConstants<float>(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, aspectRatio);
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_pipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_pipelineLayout, 0, m_dset, {});
|
||||
cmdBuf.draw(3, 1, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_dset, 0, nullptr);
|
||||
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
|
|
@ -33,40 +31,36 @@
|
|||
class Offscreen
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
nvvk::ResourceAllocator* allocator,
|
||||
uint32_t queueFamily);
|
||||
void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
|
||||
void destroy();
|
||||
|
||||
void createFramebuffer(VkExtent2D& size);
|
||||
void createPipeline(vk::RenderPass& renderPass);
|
||||
void createPipeline(VkRenderPass& renderPass);
|
||||
void createDescriptor();
|
||||
void updateDescriptorSet();
|
||||
void draw(vk::CommandBuffer cmdBuf, VkExtent2D& size);
|
||||
void draw(VkCommandBuffer cmdBuf, VkExtent2D& size);
|
||||
|
||||
const vk::RenderPass& renderPass() { return m_renderPass; }
|
||||
const vk::Framebuffer& frameBuffer() { return m_framebuffer; }
|
||||
const nvvk::Texture& colorTexture() { return m_colorTexture; }
|
||||
const VkRenderPass& renderPass() { return m_renderPass; }
|
||||
const VkFramebuffer& frameBuffer() { return m_framebuffer; }
|
||||
const nvvk::Texture& colorTexture() { return m_colorTexture; }
|
||||
|
||||
private:
|
||||
nvvk::DescriptorSetBindings m_dsetLayoutBinding;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_dsetLayout;
|
||||
vk::DescriptorSet m_dset;
|
||||
vk::Pipeline m_pipeline;
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::RenderPass m_renderPass;
|
||||
vk::Framebuffer m_framebuffer;
|
||||
VkDescriptorPool m_descPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout m_dsetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet m_dset{VK_NULL_HANDLE};
|
||||
VkPipeline m_pipeline{VK_NULL_HANDLE};
|
||||
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
||||
VkRenderPass m_renderPass{VK_NULL_HANDLE};
|
||||
VkFramebuffer m_framebuffer{VK_NULL_HANDLE};
|
||||
|
||||
nvvk::Texture m_colorTexture;
|
||||
vk::Format m_colorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
VkFormat m_colorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||
nvvk::Texture m_depthTexture;
|
||||
vk::Format m_depthFormat{vk::Format::eX8D24UnormPack32};
|
||||
VkFormat m_depthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||
|
||||
nvvk::ResourceAllocator* m_alloc{
|
||||
nullptr}; // Allocator for buffer, images, acceleration structures
|
||||
vk::Device m_device;
|
||||
int m_graphicsQueueIndex{0};
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
|
||||
VkDevice m_device;
|
||||
int m_graphicsQueueIndex{0};
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,14 +25,12 @@
|
|||
#include "nvh/alignment.hpp"
|
||||
#include "nvvk/shaders_vk.hpp"
|
||||
#include "obj_loader.h"
|
||||
#include "nvvk/buffers_vk.hpp"
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
void Raytracer::setup(const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
nvvk::ResourceAllocator* allocator,
|
||||
uint32_t queueFamily)
|
||||
void Raytracer::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
|
||||
{
|
||||
m_device = device;
|
||||
m_physicalDevice = physicalDevice;
|
||||
|
|
@ -40,12 +38,11 @@ void Raytracer::setup(const vk::Device& device,
|
|||
m_graphicsQueueIndex = queueFamily;
|
||||
|
||||
// Requesting ray tracing properties
|
||||
auto properties =
|
||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
|
||||
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
prop2.pNext = &m_rtProperties;
|
||||
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||
|
||||
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
|
||||
m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties);
|
||||
m_debug.setup(device);
|
||||
}
|
||||
|
|
@ -55,10 +52,10 @@ void Raytracer::destroy()
|
|||
{
|
||||
m_sbtWrapper.destroy();
|
||||
m_rtBuilder.destroy();
|
||||
m_device.destroy(m_rtDescPool);
|
||||
m_device.destroy(m_rtDescSetLayout);
|
||||
m_device.destroy(m_rtPipeline);
|
||||
m_device.destroy(m_rtPipelineLayout);
|
||||
vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr);
|
||||
vkDestroyPipeline(m_device, m_rtPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr);
|
||||
m_alloc->destroy(m_rtSBTBuffer);
|
||||
}
|
||||
|
||||
|
|
@ -68,30 +65,30 @@ void Raytracer::destroy()
|
|||
auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
||||
{
|
||||
// Building part
|
||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
||||
VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
||||
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
||||
|
||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
||||
triangles.setVertexData(vertexAddress);
|
||||
triangles.setVertexStride(sizeof(VertexObj));
|
||||
triangles.setIndexType(vk::IndexType::eUint32);
|
||||
triangles.setIndexData(indexAddress);
|
||||
triangles.setTransformData({});
|
||||
triangles.setMaxVertex(model.nbVertices);
|
||||
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
triangles.vertexData.deviceAddress = vertexAddress;
|
||||
triangles.vertexStride = sizeof(VertexObj);
|
||||
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
triangles.indexData.deviceAddress = indexAddress;
|
||||
triangles.transformData = {};
|
||||
triangles.maxVertex = model.nbVertices;
|
||||
|
||||
// Setting up the build info of the acceleration
|
||||
vk::AccelerationStructureGeometryKHR asGeom;
|
||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit
|
||||
asGeom.geometry.setTriangles(triangles);
|
||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
|
||||
asGeom.geometry.triangles = triangles;
|
||||
|
||||
|
||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.setFirstVertex(0);
|
||||
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
|
||||
offset.setPrimitiveOffset(0);
|
||||
offset.setTransformOffset(0);
|
||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.firstVertex = 0;
|
||||
offset.primitiveCount = model.nbIndices / 3; // Nb triangles
|
||||
offset.primitiveOffset = 0;
|
||||
offset.transformOffset = 0;
|
||||
|
||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||
input.asGeometry.emplace_back(asGeom);
|
||||
|
|
@ -105,11 +102,11 @@ auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
|||
//
|
||||
auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
||||
{
|
||||
vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer});
|
||||
VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, implicitObj.implBuf.buffer);
|
||||
|
||||
vk::AccelerationStructureGeometryAabbsDataKHR aabbs;
|
||||
aabbs.setData(dataAddress);
|
||||
aabbs.setStride(sizeof(ObjImplicit));
|
||||
VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR};
|
||||
aabbs.data.deviceAddress = dataAddress;
|
||||
aabbs.stride = sizeof(ObjImplicit);
|
||||
|
||||
// Setting up the build info of the acceleration
|
||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||
|
|
@ -118,11 +115,11 @@ auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
|||
asGeom.geometry.aabbs = aabbs;
|
||||
|
||||
|
||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.setFirstVertex(0);
|
||||
offset.setPrimitiveCount(static_cast<uint32_t>(implicitObj.objImpl.size())); // Nb aabb
|
||||
offset.setPrimitiveOffset(0);
|
||||
offset.setTransformOffset(0);
|
||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.firstVertex = 0;
|
||||
offset.primitiveCount = static_cast<uint32_t>(implicitObj.objImpl.size()); // Nb aabb
|
||||
offset.primitiveOffset = 0;
|
||||
offset.transformOffset = 0;
|
||||
|
||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||
input.asGeometry.emplace_back(asGeom);
|
||||
|
|
@ -153,8 +150,8 @@ void Raytracer::createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& imp
|
|||
}
|
||||
|
||||
|
||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
|
||||
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowCompaction);
|
||||
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR
|
||||
| VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
|
||||
}
|
||||
|
||||
void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj)
|
||||
|
|
@ -176,46 +173,48 @@ void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst&
|
|||
if(!implicitObj.objImpl.empty())
|
||||
{
|
||||
nvvk::RaytracingBuilderKHR::Instance rayInst;
|
||||
rayInst.transform = implicitObj.transform; // Position of the instance
|
||||
rayInst.instanceCustomId =
|
||||
static_cast<uint32_t>(implicitObj.blasId); // Same for material index
|
||||
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.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
rayInst.transform = implicitObj.transform; // Position of the instance
|
||||
rayInst.instanceCustomId = static_cast<uint32_t>(implicitObj.blasId); // Same for material index
|
||||
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.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
tlas.emplace_back(rayInst);
|
||||
}
|
||||
|
||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// This descriptor set holds the Acceleration structure and the output image
|
||||
//
|
||||
void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage)
|
||||
void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
|
||||
{
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
||||
using vkDSLB = VkDescriptorSetLayoutBinding;
|
||||
|
||||
m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1,
|
||||
vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS
|
||||
m_rtDescSetLayoutBind.addBinding(
|
||||
vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image
|
||||
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
|
||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
|
||||
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
|
||||
|
||||
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
||||
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
||||
m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0];
|
||||
|
||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo;
|
||||
descASInfo.setAccelerationStructureCount(1);
|
||||
descASInfo.setPAccelerationStructures(&tlas);
|
||||
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral};
|
||||
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||
allocateInfo.descriptorPool = m_rtDescPool;
|
||||
allocateInfo.descriptorSetCount = 1;
|
||||
allocateInfo.pSetLayouts = &m_rtDescSetLayout;
|
||||
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
|
||||
|
||||
std::vector<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, 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
|
||||
// - Required when changing resolution
|
||||
//
|
||||
void Raytracer::updateRtDescriptorSet(const vk::ImageView& outputImage)
|
||||
void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage)
|
||||
{
|
||||
using vkDT = vk::DescriptorType;
|
||||
|
||||
// (1) Output buffer
|
||||
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral};
|
||||
vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo};
|
||||
m_device.updateDescriptorSets(wds, nullptr);
|
||||
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
|
||||
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo);
|
||||
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Pipeline for the ray tracer: all shaders, raygen, chit, miss
|
||||
//
|
||||
void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
|
||||
void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout)
|
||||
{
|
||||
vk::ShaderModule raygenSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule missSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
||||
|
||||
// The second miss shader is invoked when a shadow ray misses the geometry. It
|
||||
// simply indicates that no occlusion has been found
|
||||
vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||
enum StageIndices
|
||||
{
|
||||
eRaygen,
|
||||
eMiss,
|
||||
eMiss2,
|
||||
eClosestHit,
|
||||
eAnyHit,
|
||||
eClosestHit1,
|
||||
eAnyHit1,
|
||||
eIntersect,
|
||||
eCall0,
|
||||
eCall1,
|
||||
eCall2,
|
||||
eShaderGroupCount
|
||||
};
|
||||
|
||||
// All stages
|
||||
std::array<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
|
||||
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
|
||||
m_rtShaderGroups.push_back(rg); // 0
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.generalShader = eRaygen;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Miss
|
||||
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
|
||||
m_rtShaderGroups.push_back(mg); // 1
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.generalShader = eMiss;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Shadow Miss
|
||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
|
||||
m_rtShaderGroups.push_back(mg); // 2
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.generalShader = eMiss2;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Hit Group0 - Closest Hit + AnyHit
|
||||
vk::ShaderModule chitSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule ahitSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
||||
// closest hit shader
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = eClosestHit;
|
||||
group.anyHitShader = eAnyHit;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
|
||||
m_rtShaderGroups.push_back(hg); // 3
|
||||
|
||||
|
||||
// Hit Group1 - Closest Hit + Intersection (procedural)
|
||||
vk::ShaderModule chit2SM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule ahit2SM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule rintSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
|
||||
{
|
||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
hg.setClosestHitShader(static_cast<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
|
||||
}
|
||||
// closest hit shader
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = eClosestHit1;
|
||||
group.anyHitShader = eAnyHit1;
|
||||
group.intersectionShader = eIntersect;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Callable shaders
|
||||
vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||
group.generalShader = eCall0;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
group.generalShader = eCall1;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
group.generalShader = eCall2;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
vk::ShaderModule call0 = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule call1 = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule call2 = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
||||
|
||||
callGroup.setGeneralShader(static_cast<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
|
||||
vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR
|
||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
||||
| vk::ShaderStageFlagBits::eMissKHR
|
||||
| vk::ShaderStageFlagBits::eCallableKHR,
|
||||
0, sizeof(RtPushConstants)};
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant);
|
||||
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
|
||||
| VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
||||
0, sizeof(RtPushConstants)};
|
||||
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant;
|
||||
|
||||
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
||||
std::vector<vk::DescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(static_cast<uint32_t>(rtDescSetLayouts.size()));
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data());
|
||||
std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
|
||||
pipelineLayoutCreateInfo.setLayoutCount = static_cast<uint32_t>(rtDescSetLayouts.size());
|
||||
pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data();
|
||||
|
||||
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
|
||||
|
||||
m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
|
||||
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
||||
vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo;
|
||||
rayPipelineInfo.setStageCount(static_cast<uint32_t>(stages.size())); // Stages are shaders
|
||||
rayPipelineInfo.setPStages(stages.data());
|
||||
VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
|
||||
rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size()); // Stages are shaders
|
||||
rayPipelineInfo.pStages = stages.data();
|
||||
|
||||
rayPipelineInfo.setGroupCount(static_cast<uint32_t>(
|
||||
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
|
||||
rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
|
||||
rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
|
||||
rayPipelineInfo.pGroups = m_rtShaderGroups.data();
|
||||
|
||||
rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
|
||||
rayPipelineInfo.setLayout(m_rtPipelineLayout);
|
||||
// The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
|
||||
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
|
||||
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
|
||||
// in the ray generation to avoid deep recursion.
|
||||
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
|
||||
rayPipelineInfo.layout = m_rtPipelineLayout;
|
||||
|
||||
m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value;
|
||||
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
|
||||
|
||||
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
|
||||
|
||||
m_device.destroy(raygenSM);
|
||||
m_device.destroy(missSM);
|
||||
m_device.destroy(shadowmissSM);
|
||||
m_device.destroy(chitSM);
|
||||
m_device.destroy(ahitSM);
|
||||
m_device.destroy(chit2SM);
|
||||
m_device.destroy(ahit2SM);
|
||||
m_device.destroy(rintSM);
|
||||
m_device.destroy(call0);
|
||||
m_device.destroy(call1);
|
||||
m_device.destroy(call2);
|
||||
|
||||
for(auto& s : stages)
|
||||
vkDestroyShaderModule(m_device, s.module, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Ray Tracing the scene
|
||||
//
|
||||
void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
|
||||
const nvmath::vec4f& clearColor,
|
||||
vk::DescriptorSet& sceneDescSet,
|
||||
vk::Extent2D& size,
|
||||
ObjPushConstants& sceneConstants)
|
||||
void Raytracer::raytrace(const VkCommandBuffer& cmdBuf,
|
||||
const nvmath::vec4f& clearColor,
|
||||
VkDescriptorSet& sceneDescSet,
|
||||
VkExtent2D& size,
|
||||
ObjPushConstants& sceneConstants)
|
||||
{
|
||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
||||
// Initializing push constant values
|
||||
|
|
@ -398,19 +416,19 @@ void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
|
|||
m_rtPushConstants.lightType = sceneConstants.lightType;
|
||||
m_rtPushConstants.frame = sceneConstants.frame;
|
||||
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0,
|
||||
{m_rtDescSet, sceneDescSet}, {});
|
||||
cmdBuf.pushConstants<RtPushConstants>(m_rtPipelineLayout,
|
||||
vk::ShaderStageFlagBits::eRaygenKHR
|
||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
||||
| vk::ShaderStageFlagBits::eMissKHR
|
||||
| vk::ShaderStageFlagBits::eCallableKHR,
|
||||
0, m_rtPushConstants);
|
||||
|
||||
std::vector<VkDescriptorSet> descSets{m_rtDescSet, sceneDescSet};
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0,
|
||||
(uint32_t)descSets.size(), descSets.data(), 0, nullptr);
|
||||
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR
|
||||
| VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
||||
0, sizeof(RtPushConstants), &m_rtPushConstants);
|
||||
|
||||
|
||||
auto regions = m_sbtWrapper.getRegions();
|
||||
cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], size.width, size.height, 1);
|
||||
auto& regions = m_sbtWrapper.getRegions();
|
||||
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1);
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "nvmath/nvmath.h"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
|
@ -29,44 +27,40 @@
|
|||
class Raytracer
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
nvvk::ResourceAllocator* allocator,
|
||||
uint32_t queueFamily);
|
||||
void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
|
||||
void destroy();
|
||||
|
||||
auto objectToVkGeometryKHR(const ObjModel& model);
|
||||
auto implicitToVkGeometryKHR(const ImplInst& implicitObj);
|
||||
void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj);
|
||||
void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj);
|
||||
void createRtDescriptorSet(const vk::ImageView& outputImage);
|
||||
void updateRtDescriptorSet(const vk::ImageView& outputImage);
|
||||
void createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout);
|
||||
void raytrace(const vk::CommandBuffer& cmdBuf,
|
||||
const nvmath::vec4f& clearColor,
|
||||
vk::DescriptorSet& sceneDescSet,
|
||||
vk::Extent2D& size,
|
||||
ObjPushConstants& sceneConstants);
|
||||
void createRtDescriptorSet(const VkImageView& outputImage);
|
||||
void updateRtDescriptorSet(const VkImageView& outputImage);
|
||||
void createRtPipeline(VkDescriptorSetLayout& sceneDescLayout);
|
||||
void raytrace(const VkCommandBuffer& cmdBuf,
|
||||
const nvmath::vec4f& clearColor,
|
||||
VkDescriptorSet& sceneDescSet,
|
||||
VkExtent2D& size,
|
||||
ObjPushConstants& sceneConstants);
|
||||
|
||||
private:
|
||||
nvvk::ResourceAllocator* m_alloc{
|
||||
nullptr}; // Allocator for buffer, images, acceleration structures
|
||||
vk::PhysicalDevice m_physicalDevice;
|
||||
vk::Device m_device;
|
||||
int m_graphicsQueueIndex{0};
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
nvvk::SBTWrapper m_sbtWrapper;
|
||||
nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
|
||||
VkPhysicalDevice m_physicalDevice;
|
||||
VkDevice m_device;
|
||||
int m_graphicsQueueIndex{0};
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
nvvk::SBTWrapper m_sbtWrapper;
|
||||
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
vk::DescriptorPool m_rtDescPool;
|
||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
||||
vk::DescriptorSet m_rtDescSet;
|
||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
vk::PipelineLayout m_rtPipelineLayout;
|
||||
vk::Pipeline m_rtPipeline;
|
||||
nvvk::Buffer m_rtSBTBuffer;
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
VkDescriptorPool m_rtDescPool;
|
||||
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||
VkDescriptorSet m_rtDescSet;
|
||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
VkPipelineLayout m_rtPipelineLayout;
|
||||
VkPipeline m_rtPipeline;
|
||||
nvvk::Buffer m_rtSBTBuffer;
|
||||
|
||||
struct RtPushConstants
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,23 +19,24 @@
|
|||
|
||||
|
||||
#include <sstream>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "obj_loader.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
#include "hello_vulkan.h"
|
||||
#include "nvh/alignment.hpp"
|
||||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/images_vk.hpp"
|
||||
#include "nvvk/pipeline_vk.hpp"
|
||||
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/renderpasses_vk.hpp"
|
||||
#include "nvvk/shaders_vk.hpp"
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// Holding the camera matrices
|
||||
|
|
@ -50,13 +51,10 @@ struct CameraMatrices
|
|||
// Keep the handle on the device
|
||||
// Initialize the tool to do all our allocations: buffers, images
|
||||
//
|
||||
void HelloVulkan::setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily)
|
||||
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||
{
|
||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
||||
m_alloc.init(device, physicalDevice);
|
||||
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||
m_alloc.init(instance, device, physicalDevice);
|
||||
m_debug.setup(m_device);
|
||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
||||
}
|
||||
|
|
@ -64,43 +62,44 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Called at each frame to update the camera matrix
|
||||
//
|
||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
// Prepare new UBO contents on host.
|
||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||
CameraMatrices hostUBO = {};
|
||||
hostUBO.view = CameraManip.getMatrix();
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
||||
|
||||
// UBO on the device, and what stages access it.
|
||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader;
|
||||
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||
|
||||
// Ensure that the modified UBO is not visible to previous frames.
|
||||
vk::BufferMemoryBarrier beforeBarrier;
|
||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
beforeBarrier.setBuffer(deviceUBO);
|
||||
beforeBarrier.setOffset(0);
|
||||
beforeBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
||||
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
beforeBarrier.buffer = deviceUBO;
|
||||
beforeBarrier.offset = 0;
|
||||
beforeBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||
|
||||
|
||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||
// buffer so it is okay to deallocate when the function returns).
|
||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
||||
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||
|
||||
// Making sure the updated UBO will be visible.
|
||||
vk::BufferMemoryBarrier afterBarrier;
|
||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
afterBarrier.setBuffer(deviceUBO);
|
||||
afterBarrier.setOffset(0);
|
||||
afterBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
afterBarrier.buffer = deviceUBO;
|
||||
afterBarrier.offset = 0;
|
||||
afterBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -108,25 +107,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
|||
//
|
||||
void HelloVulkan::createDescriptorSetLayout()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||
|
||||
// Camera matrices (binding = 0)
|
||||
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex));
|
||||
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||
// Materials (binding = 1)
|
||||
m_descSetLayoutBind.addBinding(
|
||||
vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Scene description (binding = 2)
|
||||
m_descSetLayoutBind.addBinding( //
|
||||
vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Textures (binding = 3)
|
||||
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment));
|
||||
|
||||
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Materials (binding = 4)
|
||||
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
|
||||
|
||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||
|
|
@ -139,27 +132,27 @@ void HelloVulkan::createDescriptorSetLayout()
|
|||
//
|
||||
void HelloVulkan::updateDescriptorSet()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
|
||||
// Camera matrices and scene description
|
||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||
|
||||
// All material buffers, 1 buffer per OBJ
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
||||
for(auto &m : m_objModel)
|
||||
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||
for(auto& m : m_objModel)
|
||||
{
|
||||
dbiMat.emplace_back(m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMatIdx.emplace_back(m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
}
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||
|
||||
// All texture samplers
|
||||
std::vector<vk::DescriptorImageInfo> diit;
|
||||
std::vector<VkDescriptorImageInfo> diit;
|
||||
for(auto& texture : m_textures)
|
||||
{
|
||||
diit.emplace_back(texture.descriptor);
|
||||
|
|
@ -167,7 +160,7 @@ void HelloVulkan::updateDescriptorSet()
|
|||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||
|
||||
// Writing the information
|
||||
m_device.updateDescriptorSets(static_cast<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()
|
||||
{
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
||||
sizeof(ObjPushConstant)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
|
||||
|
||||
// Creating the Pipeline Layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_descSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||
|
||||
|
||||
// Creating the Pipeline
|
||||
std::vector<std::string> paths = defaultSearchPaths;
|
||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
||||
gpb.depthStencilState.depthTestEnable = true;
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||
gpb.addAttributeDescriptions({
|
||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
});
|
||||
|
||||
m_graphicsPipeline = gpb.createPipeline();
|
||||
|
|
@ -213,8 +203,6 @@ void HelloVulkan::createGraphicsPipeline()
|
|||
//
|
||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
|
||||
LOGI("Loading File: %s \n", filename.c_str());
|
||||
ObjLoader loader;
|
||||
loader.loadModel(filename);
|
||||
|
|
@ -239,11 +227,11 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
|
||||
// Create the buffers on Device and copy vertices, indices and materials
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, vkBU::eVertexBuffer);
|
||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, vkBU::eIndexBuffer);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
|
||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
// Creates all textures found
|
||||
createTextureImages(cmdBuf, loader.m_textures);
|
||||
cmdBufGet.submitAndWait(cmdBuf);
|
||||
|
|
@ -266,11 +254,8 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
//
|
||||
void HelloVulkan::createUniformBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
using vkMP = vk::MemoryPropertyFlagBits;
|
||||
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||
}
|
||||
|
||||
|
|
@ -282,11 +267,10 @@ void HelloVulkan::createUniformBuffer()
|
|||
//
|
||||
void HelloVulkan::createSceneDescriptionBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||
|
||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
cmdGen.submitAndWait(cmdBuf);
|
||||
m_alloc.finalizeAndReleaseStaging();
|
||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||
|
|
@ -295,15 +279,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Creating all textures and samplers
|
||||
//
|
||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures)
|
||||
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, 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{
|
||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
|
||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||
if(textures.empty() && m_textures.empty())
|
||||
|
|
@ -311,18 +295,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
nvvk::Texture texture;
|
||||
|
||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||
vk::DeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = vk::Extent2D(1, 1);
|
||||
VkDeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = VkExtent2D{1, 1};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||
|
||||
// Creating the dummy texture
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
else
|
||||
|
|
@ -335,8 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
o << "media/textures/" << texture;
|
||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||
|
||||
stbi_uc* stbi_pixels =
|
||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
|
||||
std::array<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());
|
||||
}
|
||||
|
||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
||||
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||
|
||||
{
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||
vk::ImageViewCreateInfo ivInfo =
|
||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
|
|
@ -373,10 +354,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
//
|
||||
void HelloVulkan::destroyResources()
|
||||
{
|
||||
m_device.destroy(m_graphicsPipeline);
|
||||
m_device.destroy(m_pipelineLayout);
|
||||
m_device.destroy(m_descPool);
|
||||
m_device.destroy(m_descSetLayout);
|
||||
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||
|
||||
m_alloc.destroy(m_cameraMat);
|
||||
m_alloc.destroy(m_sceneDesc);
|
||||
|
||||
|
|
@ -394,14 +376,14 @@ void HelloVulkan::destroyResources()
|
|||
}
|
||||
|
||||
//#Post
|
||||
m_device.destroy(m_postPipeline);
|
||||
m_device.destroy(m_postPipelineLayout);
|
||||
m_device.destroy(m_postDescPool);
|
||||
m_device.destroy(m_postDescSetLayout);
|
||||
m_alloc.destroy(m_offscreenColor);
|
||||
m_alloc.destroy(m_offscreenDepth);
|
||||
m_device.destroy(m_offscreenRenderPass);
|
||||
m_device.destroy(m_offscreenFramebuffer);
|
||||
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
||||
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||
|
||||
m_alloc.deinit();
|
||||
}
|
||||
|
|
@ -409,33 +391,31 @@ void HelloVulkan::destroyResources()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Drawing the scene in raster mode
|
||||
//
|
||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
using vkPBP = vk::PipelineBindPoint;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
vk::DeviceSize offset{0};
|
||||
VkDeviceSize offset{0};
|
||||
|
||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||
|
||||
// Dynamic Viewport
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
||||
|
||||
setViewport(cmdBuf);
|
||||
|
||||
// Drawing all triangles
|
||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||
|
||||
|
||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||
{
|
||||
auto& inst = m_objInstance[i];
|
||||
auto& model = m_objModel[inst.objIndex];
|
||||
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
||||
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
||||
m_pushConstant);
|
||||
|
||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||
sizeof(ObjPushConstant), &m_pushConstant);
|
||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||
}
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
@ -466,29 +446,28 @@ void HelloVulkan::createOffscreenRender()
|
|||
// Creating the color image
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
|
||||
// Creating the depth buffer
|
||||
auto depthCreateInfo =
|
||||
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
|
||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
||||
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
{
|
||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
||||
|
||||
vk::ImageViewCreateInfo depthStencilView;
|
||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
||||
depthStencilView.setFormat(m_offscreenDepthFormat);
|
||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
||||
depthStencilView.setImage(image.image);
|
||||
|
||||
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthStencilView.format = m_offscreenDepthFormat;
|
||||
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||
depthStencilView.image = image.image;
|
||||
|
||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
||||
}
|
||||
|
|
@ -497,11 +476,9 @@ void HelloVulkan::createOffscreenRender()
|
|||
{
|
||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
||||
vk::ImageAspectFlagBits::eDepth);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
|
||||
genCmdBuf.submitAndWait(cmdBuf);
|
||||
}
|
||||
|
|
@ -509,25 +486,23 @@ void HelloVulkan::createOffscreenRender()
|
|||
// Creating a renderpass for the offscreen
|
||||
if(!m_offscreenRenderPass)
|
||||
{
|
||||
m_offscreenRenderPass =
|
||||
nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
||||
true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
|
||||
m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
||||
true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||
}
|
||||
|
||||
|
||||
// Creating the frame buffer for offscreen
|
||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
|
||||
|
||||
m_device.destroy(m_offscreenFramebuffer);
|
||||
vk::FramebufferCreateInfo info;
|
||||
info.setRenderPass(m_offscreenRenderPass);
|
||||
info.setAttachmentCount(2);
|
||||
info.setPAttachments(attachments.data());
|
||||
info.setWidth(m_size.width);
|
||||
info.setHeight(m_size.height);
|
||||
info.setLayers(1);
|
||||
m_offscreenFramebuffer = m_device.createFramebuffer(info);
|
||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
info.renderPass = m_offscreenRenderPass;
|
||||
info.attachmentCount = 2;
|
||||
info.pAttachments = attachments.data();
|
||||
info.width = m_size.width;
|
||||
info.height = m_size.height;
|
||||
info.layers = 1;
|
||||
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -536,26 +511,23 @@ void HelloVulkan::createOffscreenRender()
|
|||
void HelloVulkan::createPostPipeline()
|
||||
{
|
||||
// Push constants in the fragment shader
|
||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||
|
||||
// Creating the pipeline layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_postDescSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
||||
|
||||
|
||||
// Pipeline: completely generic, no vertices
|
||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
|
||||
m_renderPass);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
||||
true),
|
||||
vk::ShaderStageFlagBits::eVertex);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
||||
vk::ShaderStageFlagBits::eFragment);
|
||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
||||
m_postPipeline = pipelineGenerator.createPipeline();
|
||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||
m_postPipeline = pipelineGenerator.createPipeline();
|
||||
m_debug.setObjectName(m_postPipeline, "post");
|
||||
}
|
||||
|
||||
|
|
@ -565,11 +537,7 @@ void HelloVulkan::createPostPipeline()
|
|||
//
|
||||
void HelloVulkan::createPostDescriptor()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
||||
|
|
@ -581,28 +549,25 @@ void HelloVulkan::createPostDescriptor()
|
|||
//
|
||||
void HelloVulkan::updatePostDescriptorSet()
|
||||
{
|
||||
vk::WriteDescriptorSet writeDescriptorSets =
|
||||
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
||||
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
||||
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Draw a full screen quad with the attached image
|
||||
//
|
||||
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
||||
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
||||
{
|
||||
m_debug.beginLabel(cmdBuf, "Post");
|
||||
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
||||
setViewport(cmdBuf);
|
||||
|
||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
||||
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0,
|
||||
aspectRatio);
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0,
|
||||
m_postDescSet, {});
|
||||
cmdBuf.draw(3, 1, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
||||
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@
|
|||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/appbase_vk.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/memallocator_dma_vk.hpp"
|
||||
|
|
@ -33,25 +32,21 @@
|
|||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
class HelloVulkan : public nvvk::AppBaseVk
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||
|
||||
// The OBJ model
|
||||
struct ObjModel
|
||||
|
|
@ -88,12 +83,12 @@ public:
|
|||
std::vector<ObjInstance> m_objInstance;
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
VkDescriptorPool m_descPool;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
|
|
@ -109,18 +104,18 @@ public:
|
|||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
void updatePostDescriptorSet();
|
||||
void drawPost(vk::CommandBuffer cmdBuf);
|
||||
void drawPost(VkCommandBuffer cmdBuf);
|
||||
|
||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||
vk::DescriptorPool m_postDescPool;
|
||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
||||
vk::DescriptorSet m_postDescSet;
|
||||
vk::Pipeline m_postPipeline;
|
||||
vk::PipelineLayout m_postPipelineLayout;
|
||||
vk::RenderPass m_offscreenRenderPass;
|
||||
vk::Framebuffer m_offscreenFramebuffer;
|
||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||
nvvk::Texture m_offscreenColor;
|
||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
|
||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
// at the top of imgui.cpp.
|
||||
|
||||
#include <array>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
#include "backends/imgui_impl_glfw.h"
|
||||
#include "imgui.h"
|
||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvpsystem.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/context_vk.hpp"
|
||||
|
||||
|
|
@ -89,14 +86,12 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window =
|
||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0),
|
||||
nvmath::vec3f(0, 1, 0));
|
||||
CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0), nvmath::vec3f(0, 1, 0));
|
||||
|
||||
// Setup Vulkan
|
||||
if(!glfwVulkanSupported())
|
||||
|
|
@ -147,11 +142,10 @@ int main(int argc, char** argv)
|
|||
HelloVulkan helloVk;
|
||||
|
||||
// Window need to be opened to get the surface on which to draw
|
||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
vkctx.setGCTQueueWithPresent(surface);
|
||||
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
||||
vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
helloVk.createDepthBuffer();
|
||||
helloVk.createRenderPass();
|
||||
|
|
@ -196,8 +190,7 @@ int main(int argc, char** argv)
|
|||
ImGuiH::Panel::Begin();
|
||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
||||
renderUI(helloVk);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||
ImGuiH::Panel::End();
|
||||
}
|
||||
|
|
@ -206,62 +199,63 @@ int main(int argc, char** argv)
|
|||
helloVk.prepareFrame();
|
||||
|
||||
// Start command buffer of this frame
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
|
||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||
|
||||
// Updating camera buffer
|
||||
helloVk.updateUniformBuffer(cmdBuf);
|
||||
|
||||
|
||||
// Clearing screen
|
||||
std::array<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});
|
||||
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
|
||||
{
|
||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
// Rendering Scene
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
||||
postRenderPassBeginInfo.setClearValueCount(2);
|
||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
postRenderPassBeginInfo.clearValueCount = 2;
|
||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.drawPost(cmdBuf);
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
vkEndCommandBuffer(cmdBuf);
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
vkDeviceWaitIdle(helloVk.getDevice());
|
||||
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
vkctx.deinit();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|||
#--------------------------------------------------------------------------------------------------
|
||||
# Project setting
|
||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||
project(${PROJNAME} LANGUAGES C CXX)
|
||||
message(STATUS "-------------------------------")
|
||||
message(STATUS "Processing Project ${PROJNAME}:")
|
||||
|
|
@ -76,4 +76,3 @@ _finalize_target( ${PROJNAME} )
|
|||
|
||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -18,12 +18,12 @@
|
|||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/appbase_vk.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/memallocator_dma_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
|
||||
// #VKRay
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
|
@ -35,25 +35,21 @@
|
|||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
class HelloVulkan : public nvvk::AppBaseVk
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||
|
||||
// The OBJ model
|
||||
struct ObjModel
|
||||
|
|
@ -90,39 +86,41 @@ public:
|
|||
std::vector<ObjInstance> m_objInstance;
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
VkDescriptorPool m_descPool;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||
|
||||
|
||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
|
||||
|
||||
// #Post
|
||||
void createOffscreenRender();
|
||||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
void updatePostDescriptorSet();
|
||||
void drawPost(vk::CommandBuffer cmdBuf);
|
||||
void drawPost(VkCommandBuffer cmdBuf);
|
||||
|
||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||
vk::DescriptorPool m_postDescPool;
|
||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
||||
vk::DescriptorSet m_postDescSet;
|
||||
vk::Pipeline m_postPipeline;
|
||||
vk::PipelineLayout m_postPipelineLayout;
|
||||
vk::RenderPass m_offscreenRenderPass;
|
||||
vk::Framebuffer m_offscreenFramebuffer;
|
||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||
nvvk::Texture m_offscreenColor;
|
||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
|
||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||
|
||||
// #VKRay
|
||||
void initRayTracing();
|
||||
|
|
@ -133,25 +131,25 @@ public:
|
|||
void updateRtDescriptorSet();
|
||||
void createRtPipeline();
|
||||
void createRtShaderBindingTable();
|
||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
|
||||
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
vk::DescriptorPool m_rtDescPool;
|
||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
||||
vk::DescriptorSet m_rtDescSet;
|
||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
vk::PipelineLayout m_rtPipelineLayout;
|
||||
vk::Pipeline m_rtPipeline;
|
||||
nvvk::Buffer m_rtSBTBuffer;
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
VkDescriptorPool m_rtDescPool;
|
||||
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||
VkDescriptorSet m_rtDescSet;
|
||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
VkPipelineLayout m_rtPipelineLayout;
|
||||
VkPipeline m_rtPipeline;
|
||||
nvvk::Buffer m_rtSBTBuffer;
|
||||
|
||||
struct RtPushConstant
|
||||
{
|
||||
nvmath::vec4f clearColor;
|
||||
nvmath::vec3f lightPosition;
|
||||
float lightIntensity;
|
||||
int lightType;
|
||||
float lightIntensity{100.0f};
|
||||
int lightType{0};
|
||||
} m_rtPushConstants;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
// at the top of imgui.cpp.
|
||||
|
||||
#include <array>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
#include "backends/imgui_impl_glfw.h"
|
||||
#include "imgui.h"
|
||||
|
|
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvpsystem.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/context_vk.hpp"
|
||||
|
||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
// Default search path for shaders
|
||||
std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// GLFW Callback functions
|
||||
static void onErrorCallback(int error, const char* description)
|
||||
{
|
||||
|
|
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
|||
static int const SAMPLE_WIDTH = 1280;
|
||||
static int const SAMPLE_HEIGHT = 720;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Application Entry
|
||||
//
|
||||
|
|
@ -87,8 +86,7 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window =
|
||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
|
|
@ -117,7 +115,7 @@ int main(int argc, char** argv)
|
|||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#else
|
||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||
|
|
@ -127,19 +125,19 @@ int main(int argc, char** argv)
|
|||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
||||
&accelFeature);
|
||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
||||
&rtPipelineFeature);
|
||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
|
||||
|
||||
// Creating Vulkan base application
|
||||
nvvk::Context vkctx{};
|
||||
vkctx.initInstance(contextInfo);
|
||||
|
|
@ -149,16 +147,14 @@ int main(int argc, char** argv)
|
|||
// Use a compatible device
|
||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||
|
||||
|
||||
// Create example
|
||||
HelloVulkan helloVk;
|
||||
|
||||
// Window need to be opened to get the surface on which to draw
|
||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
vkctx.setGCTQueueWithPresent(surface);
|
||||
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
||||
vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
helloVk.createDepthBuffer();
|
||||
helloVk.createRenderPass();
|
||||
|
|
@ -219,9 +215,7 @@ int main(int argc, char** argv)
|
|||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||
|
||||
renderUI(helloVk);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||
ImGuiH::Panel::End();
|
||||
}
|
||||
|
|
@ -230,28 +224,29 @@ int main(int argc, char** argv)
|
|||
helloVk.prepareFrame();
|
||||
|
||||
// Start command buffer of this frame
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
|
||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||
|
||||
// Updating camera buffer
|
||||
helloVk.updateUniformBuffer(cmdBuf);
|
||||
|
||||
// Clearing screen
|
||||
std::array<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});
|
||||
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
|
||||
{
|
||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
// Rendering Scene
|
||||
if(useRaytracer)
|
||||
|
|
@ -260,40 +255,40 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
}
|
||||
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
||||
postRenderPassBeginInfo.setClearValueCount(2);
|
||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
postRenderPassBeginInfo.clearValueCount = 2;
|
||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.drawPost(cmdBuf);
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
vkEndCommandBuffer(cmdBuf);
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
vkDeviceWaitIdle(helloVk.getDevice());
|
||||
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
|
||||
vkctx.deinit();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|||
#--------------------------------------------------------------------------------------------------
|
||||
# Project setting
|
||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||
project(${PROJNAME} LANGUAGES C CXX)
|
||||
message(STATUS "-------------------------------")
|
||||
message(STATUS "Processing Project ${PROJNAME}:")
|
||||
|
|
|
|||
|
|
@ -62,17 +62,20 @@ void HelloVulkan::animationInstances(float time)
|
|||
Next, we update the buffer that describes the scene, which is used by the rasterizer to set each object's position, and also by the ray tracer to compute shading normals.
|
||||
~~~~ C++
|
||||
// Update the buffer
|
||||
vk::DeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance);
|
||||
nvvkBuffer stagingBuffer = m_alloc.createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible);
|
||||
VkDeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance);
|
||||
nvvk::Buffer stagingBuffer =
|
||||
m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
// Copy data to staging buffer
|
||||
auto* gInst = m_alloc.map(stagingBuffer);
|
||||
memcpy(gInst, m_objInstance.data(), bufferSize);
|
||||
m_alloc.unmap(stagingBuffer);
|
||||
// Copy staging buffer to the Scene Description buffer
|
||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
cmdBuf.copyBuffer(stagingBuffer.buffer, m_sceneDesc.buffer, vk::BufferCopy(0, 0, bufferSize));
|
||||
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
|
||||
VkBufferCopy region{0, 0, bufferSize};
|
||||
vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_sceneDesc.buffer, 1, ®ion);
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
genCmdBuf.submitAndWait(cmdBuf);
|
||||
m_alloc.destroy(stagingBuffer);
|
||||
|
|
@ -115,7 +118,7 @@ std::vector<nvvk::RaytracingBuilder::Instance> m_tlas;
|
|||
|
||||
Make sure to rename it to `m_tlas`, instead of `tlas`.
|
||||
|
||||
One important point is that we need to set the TLAS build flags to allow updates, by adding the`vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate` flag.
|
||||
One important point is that we need to set the TLAS build flags to allow updates, by adding the`VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR` flag.
|
||||
This is absolutely needed, since otherwise the TLAS cannot be updated.
|
||||
|
||||
~~~~ C++
|
||||
|
|
@ -124,16 +127,17 @@ void HelloVulkan::createTopLevelAS()
|
|||
m_tlas.reserve(m_objInstance.size());
|
||||
for(uint32_t i = 0; i < static_cast<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.instanceCustomId = i; // gl_InstanceCustomIndexEXT
|
||||
rayInst.blasId = m_objInstance[i].objIndex;
|
||||
rayInst.hitGroupId = m_objInstance[i].hitgroup;
|
||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV;
|
||||
rayInst.hitGroupId = 0;
|
||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
m_tlas.emplace_back(rayInst);
|
||||
}
|
||||
m_rtBuilder.buildTlas(m_tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
|
||||
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate);
|
||||
|
||||
m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
|
||||
m_rtBuilder.buildTlas(m_tlas, m_rtFlags);
|
||||
}
|
||||
~~~~
|
||||
|
||||
|
|
@ -203,11 +207,11 @@ Add all of the following members to the `HelloVulkan` class:
|
|||
void createCompPipelines();
|
||||
|
||||
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
||||
vk::DescriptorPool m_compDescPool;
|
||||
vk::DescriptorSetLayout m_compDescSetLayout;
|
||||
vk::DescriptorSet m_compDescSet;
|
||||
vk::Pipeline m_compPipeline;
|
||||
vk::PipelineLayout m_compPipelineLayout;
|
||||
VkDescriptorPool m_compDescPool;
|
||||
VkDescriptorSetLayout m_compDescSetLayout;
|
||||
VkDescriptorSet m_compDescSet;
|
||||
VkPipeline m_compPipeline;
|
||||
VkPipelineLayout m_compPipelineLayout;
|
||||
~~~~
|
||||
|
||||
The compute shader will work on a single `VertexObj` buffer.
|
||||
|
|
@ -215,8 +219,7 @@ The compute shader will work on a single `VertexObj` buffer.
|
|||
~~~~ C++
|
||||
void HelloVulkan::createCompDescriptors()
|
||||
{
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding(
|
||||
0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
|
||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||
|
|
@ -227,12 +230,12 @@ void HelloVulkan::createCompDescriptors()
|
|||
`updateCompDescriptors` will set the set the descriptor to the buffer of `VertexObj` objects to which the animation will be applied.
|
||||
|
||||
~~~~ C++
|
||||
void HelloVulkan::updateCompDescriptors(nvvkBuffer& vertex)
|
||||
void HelloVulkan::updateCompDescriptors(nvvk::Buffer& vertex)
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
vk::DescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, dbiUnif));
|
||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
VkDescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &dbiUnif));
|
||||
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()
|
||||
{
|
||||
// pushing time
|
||||
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(float)};
|
||||
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants};
|
||||
m_compPipelineLayout = m_device.createPipelineLayout(layout_info);
|
||||
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
|
||||
VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float)};
|
||||
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_compDescSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &push_constants;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_compPipelineLayout);
|
||||
|
||||
|
||||
VkComputePipelineCreateInfo computePipelineCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
|
||||
computePipelineCreateInfo.layout = m_compPipelineLayout;
|
||||
|
||||
computePipelineCreateInfo.stage =
|
||||
nvvk::createShaderStageInfo(m_device,
|
||||
nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths),
|
||||
nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true),
|
||||
VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo, nullptr);
|
||||
m_device.destroy(computePipelineCreateInfo.stage.module);
|
||||
|
||||
vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_compPipeline);
|
||||
|
||||
vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr);
|
||||
}
|
||||
~~~~
|
||||
|
||||
Finally, destroy the resources in `HelloVulkan::destroyResources()`:
|
||||
|
||||
~~~~ C++
|
||||
m_device.destroy(m_compDescPool);
|
||||
m_device.destroy(m_compDescSetLayout);
|
||||
m_device.destroy(m_compPipeline);
|
||||
m_device.destroy(m_compPipelineLayout);
|
||||
// #VK_compute
|
||||
vkDestroyPipeline(m_device, m_compPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
|
||||
~~~~
|
||||
|
||||
### `anim.comp`
|
||||
|
|
@ -338,14 +351,13 @@ void HelloVulkan::animationObject(float time)
|
|||
updateCompDescriptors(model.vertexBuffer);
|
||||
|
||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time);
|
||||
vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1);
|
||||
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
||||
{m_compDescSet}, {});
|
||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(float),
|
||||
&time);
|
||||
cmdBuf.dispatch(model.nbVertices, 1, 1);
|
||||
genCmdBuf.submitAndWait(cmdBuf);
|
||||
}
|
||||
~~~~
|
||||
|
|
@ -450,15 +462,15 @@ void HelloVulkan::createBottomLevelAS()
|
|||
{
|
||||
// BLAS - Storing each primitive in a geometry
|
||||
m_blas.reserve(m_objModel.size());
|
||||
for(const auto & obj : m_objModel)
|
||||
for(const auto& obj : m_objModel)
|
||||
{
|
||||
auto blas = objectToVkGeometryKHR(obj);
|
||||
|
||||
// We could add more geometry in each BLAS, but we add only one for now
|
||||
m_blas.push_back(blas);
|
||||
}
|
||||
m_rtBuilder.buildBlas(m_blas, vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate
|
||||
| vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastBuild);
|
||||
m_rtBuilder.buildBlas(m_blas, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR
|
||||
| VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
||||
}
|
||||
~~~~
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/appbase_vk.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/memallocator_dma_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
|
||||
// #VKRay
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
|
@ -36,25 +36,21 @@
|
|||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
class HelloVulkan : public nvvk::AppBaseVk
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||
|
||||
// The OBJ model
|
||||
struct ObjModel
|
||||
|
|
@ -91,39 +87,41 @@ public:
|
|||
std::vector<ObjInstance> m_objInstance;
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
VkDescriptorPool m_descPool;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||
|
||||
|
||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
|
||||
|
||||
// #Post
|
||||
void createOffscreenRender();
|
||||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
void updatePostDescriptorSet();
|
||||
void drawPost(vk::CommandBuffer cmdBuf);
|
||||
void drawPost(VkCommandBuffer cmdBuf);
|
||||
|
||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||
vk::DescriptorPool m_postDescPool;
|
||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
||||
vk::DescriptorSet m_postDescSet;
|
||||
vk::Pipeline m_postPipeline;
|
||||
vk::PipelineLayout m_postPipelineLayout;
|
||||
vk::RenderPass m_offscreenRenderPass;
|
||||
vk::Framebuffer m_offscreenFramebuffer;
|
||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||
nvvk::Texture m_offscreenColor;
|
||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
|
||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||
|
||||
// #VKRay
|
||||
void initRayTracing();
|
||||
|
|
@ -133,19 +131,19 @@ public:
|
|||
void createRtDescriptorSet();
|
||||
void updateRtDescriptorSet();
|
||||
void createRtPipeline();
|
||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
|
||||
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
vk::DescriptorPool m_rtDescPool;
|
||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
||||
vk::DescriptorSet m_rtDescSet;
|
||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
vk::PipelineLayout m_rtPipelineLayout;
|
||||
vk::Pipeline m_rtPipeline;
|
||||
nvvk::SBTWrapper m_sbtWrapper;
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
VkDescriptorPool m_rtDescPool;
|
||||
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||
VkDescriptorSet m_rtDescSet;
|
||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
VkPipelineLayout m_rtPipelineLayout;
|
||||
VkPipeline m_rtPipeline;
|
||||
nvvk::SBTWrapper m_sbtWrapper;
|
||||
|
||||
std::vector<nvvk::RaytracingBuilderKHR::Instance> m_tlas;
|
||||
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas;
|
||||
|
|
@ -168,11 +166,11 @@ public:
|
|||
void createCompPipelines();
|
||||
|
||||
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
||||
vk::DescriptorPool m_compDescPool;
|
||||
vk::DescriptorSetLayout m_compDescSetLayout;
|
||||
vk::DescriptorSet m_compDescSet;
|
||||
vk::Pipeline m_compPipeline;
|
||||
vk::PipelineLayout m_compPipelineLayout;
|
||||
VkDescriptorPool m_compDescPool;
|
||||
VkDescriptorSetLayout m_compDescSetLayout;
|
||||
VkDescriptorSet m_compDescSet;
|
||||
VkPipeline m_compPipeline;
|
||||
VkPipelineLayout m_compPipelineLayout;
|
||||
|
||||
vk::BuildAccelerationStructureFlagsKHR m_rtFlags;
|
||||
VkBuildAccelerationStructureFlagsKHR m_rtFlags;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
// at the top of imgui.cpp.
|
||||
|
||||
#include <array>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "backends/imgui_impl_glfw.h"
|
||||
#include "imgui.h"
|
||||
|
|
@ -33,13 +32,10 @@
|
|||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvpsystem.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/context_vk.hpp"
|
||||
|
||||
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#define UNUSED(x) (void)(x)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -47,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
// Default search path for shaders
|
||||
std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// GLFW Callback functions
|
||||
static void onErrorCallback(int error, const char* description)
|
||||
{
|
||||
|
|
@ -74,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
|||
static int const SAMPLE_WIDTH = 1280;
|
||||
static int const SAMPLE_HEIGHT = 720;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Application Entry
|
||||
//
|
||||
|
|
@ -88,12 +86,11 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window =
|
||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
CameraManip.setLookat(nvmath::vec3f(4, 4, 4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
|
||||
CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
|
||||
|
||||
// Setup Vulkan
|
||||
if(!glfwVulkanSupported())
|
||||
|
|
@ -131,16 +128,14 @@ int main(int argc, char** argv)
|
|||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
||||
&accelFeature);
|
||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
||||
&rtPipelineFeature);
|
||||
|
||||
// Creating Vulkan base application
|
||||
nvvk::Context vkctx{};
|
||||
|
|
@ -155,11 +150,10 @@ int main(int argc, char** argv)
|
|||
HelloVulkan helloVk;
|
||||
|
||||
// Window need to be opened to get the surface on which to draw
|
||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
vkctx.setGCTQueueWithPresent(surface);
|
||||
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
||||
vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
helloVk.createDepthBuffer();
|
||||
helloVk.createRenderPass();
|
||||
|
|
@ -229,8 +223,7 @@ int main(int argc, char** argv)
|
|||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||
|
||||
renderUI(helloVk);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||
ImGuiH::Panel::End();
|
||||
}
|
||||
|
|
@ -244,28 +237,29 @@ int main(int argc, char** argv)
|
|||
helloVk.prepareFrame();
|
||||
|
||||
// Start command buffer of this frame
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
|
||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||
|
||||
// Updating camera buffer
|
||||
helloVk.updateUniformBuffer(cmdBuf);
|
||||
|
||||
// Clearing screen
|
||||
std::array<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});
|
||||
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
|
||||
{
|
||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
// Rendering Scene
|
||||
if(useRaytracer)
|
||||
|
|
@ -274,40 +268,40 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
}
|
||||
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
||||
postRenderPassBeginInfo.setClearValueCount(2);
|
||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
postRenderPassBeginInfo.clearValueCount = 2;
|
||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.drawPost(cmdBuf);
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
vkEndCommandBuffer(cmdBuf);
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
vkDeviceWaitIdle(helloVk.getDevice());
|
||||
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
|
||||
vkctx.deinit();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|||
#--------------------------------------------------------------------------------------------------
|
||||
# Project setting
|
||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||
project(${PROJNAME} LANGUAGES C CXX)
|
||||
message(STATUS "-------------------------------")
|
||||
message(STATUS "Processing Project ${PROJNAME}:")
|
||||
|
|
|
|||
|
|
@ -108,25 +108,30 @@ The any hit shader will be part of the hit shader group. Currently, the hit shad
|
|||
In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahit.spv`
|
||||
|
||||
~~~~ C++
|
||||
vk::ShaderModule ahitSM =
|
||||
nvvk::createShaderModule(m_device, //
|
||||
nvh::loadFile("shaders/raytrace.rahit.spv", true, paths));
|
||||
enum StageIndices
|
||||
{
|
||||
...
|
||||
eAnyHit,
|
||||
eShaderGroupCount
|
||||
};
|
||||
|
||||
// Hit Group - Any Hit
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||
stages[eAnyHit] = stage;
|
||||
~~~~
|
||||
|
||||
add the any hit shader to the hit group
|
||||
The Any Hit goes in the same Hit group as the Closest Hit, so we need to
|
||||
add the Any Hit stage index and push back the shader module to the stages.
|
||||
|
||||
~~~~ C++
|
||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
|
||||
m_rtShaderGroups.push_back(hg);
|
||||
~~~~
|
||||
|
||||
and at the end, delete it:
|
||||
|
||||
~~~~ C++
|
||||
m_device.destroy(ahitSM);
|
||||
// closest hit shader
|
||||
// Payload 0
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = eClosestHit;
|
||||
group.anyHitShader = eAnyHit;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
~~~~
|
||||
|
||||
## Give access of the buffers to the Any Hit shader
|
||||
|
|
@ -137,38 +142,37 @@ This is the case for the material and scene description buffers
|
|||
|
||||
~~~~ C++
|
||||
// Materials (binding = 1)
|
||||
m_descSetLayoutBind.emplace_back(
|
||||
vkDS(1, vkDT::eStorageBuffer, nbObj,
|
||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
// Scene description (binding = 2)
|
||||
m_descSetLayoutBind.emplace_back( //
|
||||
vkDS(2, vkDT::eStorageBuffer, 1,
|
||||
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
~~~~
|
||||
|
||||
and also for the vertex, index and material index buffers:
|
||||
|
||||
~~~~ C++
|
||||
// Materials (binding = 4)
|
||||
m_descSetLayoutBind.emplace_back( //
|
||||
vkDS(4, vkDT::eStorageBuffer, nbObj,
|
||||
vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
// Storing vertices (binding = 5)
|
||||
m_descSetLayoutBind.emplace_back( //
|
||||
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
// Storing indices (binding = 6)
|
||||
m_descSetLayoutBind.emplace_back( //
|
||||
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
|
||||
m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
|
||||
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
||||
~~~~
|
||||
|
||||
## Opaque Flag
|
||||
|
||||
In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `vk::GeometryFlagBitsKHR::eOpaque`. However, this avoided invoking the any hit shader.
|
||||
In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `VK_GEOMETRY_OPAQUE_BIT_KHR`. However, this avoided invoking the any hit shader.
|
||||
|
||||
We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `eNoDuplicateAnyHitInvocation` flag:
|
||||
We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR` flag:
|
||||
|
||||
~~~~ C++
|
||||
geometry.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation);
|
||||
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // Avoid double hits;
|
||||
~~~~
|
||||
|
||||
## Ray Generation Shader
|
||||
|
|
@ -364,8 +368,6 @@ traceRayEXT(topLevelAS, // acceleration structure
|
|||
~~~~
|
||||
|
||||
|
||||
|
||||
|
||||
### Ray tracing Pipeline
|
||||
|
||||
The final step is to add the new Hit Group. This is a change in `HelloVulkan::createRtPipeline()`.
|
||||
|
|
@ -373,22 +375,42 @@ We need to load the new any hit shader and create a new Hit Group.
|
|||
|
||||
Replace the `"shaders/raytrace.rahit.spv"` for `"shaders/raytrace_0.rahit.spv"`
|
||||
|
||||
Load the new shader module.
|
||||
|
||||
~~~~ C
|
||||
enum StageIndices
|
||||
{
|
||||
eRaygen,
|
||||
eMiss,
|
||||
eMiss2,
|
||||
eClosestHit,
|
||||
eAnyHit,
|
||||
eAnyHit2,
|
||||
eShaderGroupCount
|
||||
};
|
||||
|
||||
// Hit Group - Any Hit
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_0.rahit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||
stages[eAnyHit] = stage;
|
||||
//
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||
stages[eAnyHit2] = stage;
|
||||
~~~~
|
||||
|
||||
Then, after the creating of the first Hit Group, create a new one, where only the any hit using payload 1
|
||||
is added. We are skipping the closest hit shader in the trace call, so we can ignore it in the Hit Group.
|
||||
|
||||
~~~~ C
|
||||
// Payload 1
|
||||
vk::ShaderModule ahit1SM =
|
||||
nvvk::createShaderModule(m_device, //
|
||||
nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths));
|
||||
hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped)
|
||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"});
|
||||
m_rtShaderGroups.push_back(hg);
|
||||
// Payload 1
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.anyHitShader = eAnyHit2;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
~~~~
|
||||
|
||||
At the end of the function, delete the shader module `ahit1SM`.
|
||||
|
||||
|
||||
**Note:** Re-Run
|
||||
Everything should work as before, but now it does it right.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/appbase_vk.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/memallocator_dma_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
|
||||
// #VKRay
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
|
@ -35,25 +35,21 @@
|
|||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
class HelloVulkan : public nvvk::AppBaseVk
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||
|
||||
// The OBJ model
|
||||
struct ObjModel
|
||||
|
|
@ -90,39 +86,41 @@ public:
|
|||
std::vector<ObjInstance> m_objInstance;
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
VkDescriptorPool m_descPool;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||
|
||||
|
||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
|
||||
|
||||
// #Post
|
||||
void createOffscreenRender();
|
||||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
void updatePostDescriptorSet();
|
||||
void drawPost(vk::CommandBuffer cmdBuf);
|
||||
void drawPost(VkCommandBuffer cmdBuf);
|
||||
|
||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||
vk::DescriptorPool m_postDescPool;
|
||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
||||
vk::DescriptorSet m_postDescSet;
|
||||
vk::Pipeline m_postPipeline;
|
||||
vk::PipelineLayout m_postPipelineLayout;
|
||||
vk::RenderPass m_offscreenRenderPass;
|
||||
vk::Framebuffer m_offscreenFramebuffer;
|
||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||
nvvk::Texture m_offscreenColor;
|
||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
|
||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||
|
||||
// #VKRay
|
||||
void initRayTracing();
|
||||
|
|
@ -133,21 +131,21 @@ public:
|
|||
void updateRtDescriptorSet();
|
||||
void createRtPipeline();
|
||||
void createRtShaderBindingTable();
|
||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
void resetFrame();
|
||||
void updateFrame();
|
||||
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
vk::DescriptorPool m_rtDescPool;
|
||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
||||
vk::DescriptorSet m_rtDescSet;
|
||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
vk::PipelineLayout m_rtPipelineLayout;
|
||||
vk::Pipeline m_rtPipeline;
|
||||
nvvk::Buffer m_rtSBTBuffer;
|
||||
int m_maxFrames{10000};
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
VkDescriptorPool m_rtDescPool;
|
||||
VkDescriptorSetLayout m_rtDescSetLayout;
|
||||
VkDescriptorSet m_rtDescSet;
|
||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
VkPipelineLayout m_rtPipelineLayout;
|
||||
VkPipeline m_rtPipeline;
|
||||
nvvk::Buffer m_rtSBTBuffer;
|
||||
int m_maxFrames{10000};
|
||||
|
||||
struct RtPushConstant
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
// at the top of imgui.cpp.
|
||||
|
||||
#include <array>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "backends/imgui_impl_glfw.h"
|
||||
#include "imgui.h"
|
||||
|
|
@ -33,11 +32,9 @@
|
|||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvpsystem.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/context_vk.hpp"
|
||||
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
|
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
// Default search path for shaders
|
||||
std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// GLFW Callback functions
|
||||
static void onErrorCallback(int error, const char* description)
|
||||
{
|
||||
|
|
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
|
|||
static int const SAMPLE_WIDTH = 1280;
|
||||
static int const SAMPLE_HEIGHT = 720;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Application Entry
|
||||
//
|
||||
|
|
@ -87,8 +86,7 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window =
|
||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
|
|
@ -117,7 +115,7 @@ int main(int argc, char** argv)
|
|||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#else
|
||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||
|
|
@ -131,13 +129,10 @@ int main(int argc, char** argv)
|
|||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
||||
&accelFeature);
|
||||
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
|
||||
&rtPipelineFeature);
|
||||
|
||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
|
||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
|
||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
|
|
@ -156,11 +151,10 @@ int main(int argc, char** argv)
|
|||
HelloVulkan helloVk;
|
||||
|
||||
// Window need to be opened to get the surface on which to draw
|
||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
vkctx.setGCTQueueWithPresent(surface);
|
||||
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
||||
vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
helloVk.createDepthBuffer();
|
||||
helloVk.createRenderPass();
|
||||
|
|
@ -172,8 +166,7 @@ int main(int argc, char** argv)
|
|||
// Creation of the example
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true),
|
||||
nvmath::scale_mat4(nvmath::vec3f(1.5f))
|
||||
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
|
||||
nvmath::scale_mat4(nvmath::vec3f(1.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||
|
||||
|
||||
|
|
@ -215,6 +208,7 @@ int main(int argc, char** argv)
|
|||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
|
||||
// Show UI window.
|
||||
if(helloVk.showGui())
|
||||
{
|
||||
|
|
@ -223,8 +217,7 @@ int main(int argc, char** argv)
|
|||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||
|
||||
renderUI(helloVk);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||
ImGuiH::Panel::End();
|
||||
}
|
||||
|
|
@ -233,28 +226,29 @@ int main(int argc, char** argv)
|
|||
helloVk.prepareFrame();
|
||||
|
||||
// Start command buffer of this frame
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
|
||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||
|
||||
// Updating camera buffer
|
||||
helloVk.updateUniformBuffer(cmdBuf);
|
||||
|
||||
// Clearing screen
|
||||
std::array<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});
|
||||
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
|
||||
{
|
||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
||||
offscreenRenderPassBeginInfo.setClearValueCount(2);
|
||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
// Rendering Scene
|
||||
if(useRaytracer)
|
||||
|
|
@ -263,40 +257,40 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
}
|
||||
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
||||
postRenderPassBeginInfo.setClearValueCount(2);
|
||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
postRenderPassBeginInfo.clearValueCount = 2;
|
||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.drawPost(cmdBuf);
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
vkEndCommandBuffer(cmdBuf);
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
vkDeviceWaitIdle(helloVk.getDevice());
|
||||
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
|
||||
vkctx.deinit();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
|
|
|||
|
|
@ -36,35 +36,33 @@ The following are the buffers are they can be seen in [NSight Graphics](https://
|
|||
|
||||
## G-Buffer
|
||||
|
||||
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `vk::Format::eR32G32B32A32Sfloat` to store the position and normal and one `vk::Format::eR32Sfloat` for the ambient occlusion.
|
||||
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion.
|
||||
|
||||
~~~~ C++
|
||||
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
||||
}
|
||||
|
||||
// The ambient occlusion result (r32)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
||||
}
|
||||
|
|
@ -76,9 +74,9 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
|||
|
||||
```
|
||||
// Creating the frame buffer for offscreen
|
||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||
m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||
m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
```
|
||||
|
||||
### Renderpass
|
||||
|
|
@ -86,7 +84,7 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
|||
This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth)
|
||||
|
||||
```
|
||||
vk::ClearValue clearValues[3];
|
||||
std::array<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.
|
||||
|
|
@ -94,14 +92,14 @@ Since the clear value will be re-used by the offscreen (3 attachments) and the p
|
|||
```
|
||||
// Offscreen render pass
|
||||
{
|
||||
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
|
||||
clearValues[2].setDepthStencil({1.0f, 0});
|
||||
clearValues[1].color = {{0, 0, 0, 0}};
|
||||
clearValues[2].depthStencil = {1.0f, 0};
|
||||
```
|
||||
|
||||
```
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
clearValues[1].setDepthStencil({1.0f, 0});
|
||||
clearValues[1].depthStencil = {1.0f, 0};
|
||||
```
|
||||
|
||||
### Fragment shader
|
||||
|
|
@ -138,12 +136,9 @@ The shader takes two inputs, the G-Buffer and the TLAS, and has one output, the
|
|||
//
|
||||
void HelloVulkan::createCompDescriptors()
|
||||
{
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
|
||||
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
|
||||
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
|
||||
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
|
||||
m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
|
||||
m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
|
||||
|
||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||
|
|
@ -162,15 +157,17 @@ when resizing the window and the G-Buffer and AO buffer are resized.
|
|||
//
|
||||
void HelloVulkan::updateCompDescriptors()
|
||||
{
|
||||
std::vector<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, 1, &m_aoBuffer.descriptor));
|
||||
|
||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
|
||||
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||
descASInfo.accelerationStructureCount = 1;
|
||||
descASInfo.pAccelerationStructures = &tlas;
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
||||
|
||||
m_device.updateDescriptorSets(static_cast<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)).
|
||||
This sets the current frame index, which allows us to accumulate AO samples over time.
|
||||
|
||||
Next, we are adding a `vk::ImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
||||
Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
||||
|
||||
~~~~ C++
|
||||
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
||||
// before the compute shader is using the buffer
|
||||
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
|
||||
vk::ImageMemoryBarrier imgMemBarrier;
|
||||
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
||||
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
imgMemBarrier.setImage(m_gBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
imgMemBarrier.image = m_gBuffer.image;
|
||||
imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.subresourceRange = range;
|
||||
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
~~~~
|
||||
|
||||
Folowing is the call to dispatch the compute shader
|
||||
|
||||
~~~~ C++
|
||||
// Preparing for the compute shader
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
||||
{m_compDescSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||
|
||||
|
||||
// Sending the push constant information
|
||||
aoControl.frame = m_frame;
|
||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
|
||||
sizeof(AoControl), &aoControl);
|
||||
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
|
||||
|
||||
// Dispatching the shader
|
||||
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
|
||||
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
~~~~
|
||||
|
||||
Then we are adding a final barrier to make sure the compute shader is done
|
||||
|
|
@ -242,13 +237,9 @@ writing the AO so that the fragment shader (post) can use it.
|
|||
~~~~ C++
|
||||
// Adding a barrier to be sure the compute shader has finished
|
||||
// writing to the AO buffer before the post shader is using it
|
||||
imgMemBarrier.setImage(m_aoBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
imgMemBarrier.image = m_aoBuffer.image;
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
~~~~
|
||||
|
||||
## Update Frame
|
||||
|
|
@ -450,9 +441,9 @@ We have also have added `AoControl aoControl;` somwhere in main() and passing th
|
|||
~~~~
|
||||
// Rendering Scene
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
helloVk.runCompute(cmdBuf, aoControl);
|
||||
}
|
||||
~~~~
|
||||
|
|
@ -463,10 +454,10 @@ The post shader will combine the result of the fragment (color) and the result o
|
|||
In `createPostDescriptor` we will need to add the descriptor
|
||||
|
||||
~~~~
|
||||
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
~~~~
|
||||
|
||||
And the equivalent in `updatePostDescriptorSet`
|
||||
And the equivalent in `updatePostDescriptorSet()`
|
||||
|
||||
~~~~
|
||||
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
||||
|
|
|
|||
|
|
@ -19,25 +19,25 @@
|
|||
|
||||
|
||||
#include <sstream>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "obj_loader.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
#include "hello_vulkan.h"
|
||||
#include "nvh/alignment.hpp"
|
||||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/images_vk.hpp"
|
||||
#include "nvvk/pipeline_vk.hpp"
|
||||
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/renderpasses_vk.hpp"
|
||||
#include "nvvk/shaders_vk.hpp"
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// Holding the camera matrices
|
||||
struct CameraMatrices
|
||||
|
|
@ -45,21 +45,17 @@ struct CameraMatrices
|
|||
nvmath::mat4f view;
|
||||
nvmath::mat4f proj;
|
||||
nvmath::mat4f viewInverse;
|
||||
// #VKRay
|
||||
nvmath::mat4f projInverse;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Keep the handle on the device
|
||||
// Initialize the tool to do all our allocations: buffers, images
|
||||
//
|
||||
void HelloVulkan::setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily)
|
||||
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||
{
|
||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
||||
m_alloc.init(device, physicalDevice);
|
||||
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||
m_alloc.init(instance, device, physicalDevice);
|
||||
m_debug.setup(m_device);
|
||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
||||
}
|
||||
|
|
@ -67,46 +63,44 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Called at each frame to update the camera matrix
|
||||
//
|
||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
// Prepare new UBO contents on host.
|
||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||
CameraMatrices hostUBO = {};
|
||||
hostUBO.view = CameraManip.getMatrix();
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
||||
// #VKRay
|
||||
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
||||
|
||||
// UBO on the device, and what stages access it.
|
||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages =
|
||||
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
|
||||
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||
|
||||
// Ensure that the modified UBO is not visible to previous frames.
|
||||
vk::BufferMemoryBarrier beforeBarrier;
|
||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
beforeBarrier.setBuffer(deviceUBO);
|
||||
beforeBarrier.setOffset(0);
|
||||
beforeBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
||||
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
beforeBarrier.buffer = deviceUBO;
|
||||
beforeBarrier.offset = 0;
|
||||
beforeBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||
|
||||
|
||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||
// buffer so it is okay to deallocate when the function returns).
|
||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
||||
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||
|
||||
// Making sure the updated UBO will be visible.
|
||||
vk::BufferMemoryBarrier afterBarrier;
|
||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
afterBarrier.setBuffer(deviceUBO);
|
||||
afterBarrier.setOffset(0);
|
||||
afterBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
afterBarrier.buffer = deviceUBO;
|
||||
afterBarrier.offset = 0;
|
||||
afterBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -114,22 +108,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
|||
//
|
||||
void HelloVulkan::createDescriptorSetLayout()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||
|
||||
// Camera matrices (binding = 0)
|
||||
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex));
|
||||
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||
// Materials (binding = 1)
|
||||
m_descSetLayoutBind.addBinding(vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Scene description (binding = 2)
|
||||
m_descSetLayoutBind.addBinding(vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Textures (binding = 3)
|
||||
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Materials (binding = 4)
|
||||
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
|
||||
|
||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||
|
|
@ -142,40 +133,39 @@ void HelloVulkan::createDescriptorSetLayout()
|
|||
//
|
||||
void HelloVulkan::updateDescriptorSet()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
|
||||
// Camera matrices and scene description
|
||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||
|
||||
// All material buffers, 1 buffer per OBJ
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiVert;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiIdx;
|
||||
for(auto& obj : m_objModel)
|
||||
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||
std::vector<VkDescriptorBufferInfo> dbiVert;
|
||||
std::vector<VkDescriptorBufferInfo> dbiIdx;
|
||||
for(auto& m : m_objModel)
|
||||
{
|
||||
dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
}
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||
|
||||
// All texture samplers
|
||||
std::vector<vk::DescriptorImageInfo> diit;
|
||||
std::vector<VkDescriptorImageInfo> diit;
|
||||
for(auto& texture : m_textures)
|
||||
{
|
||||
diit.emplace_back(texture.descriptor);
|
||||
}
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||
|
||||
|
||||
// Writing the information
|
||||
m_device.updateDescriptorSets(static_cast<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()
|
||||
{
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
||||
sizeof(ObjPushConstant)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
|
||||
|
||||
// Creating the Pipeline Layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_descSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||
|
||||
|
||||
// Creating the Pipeline
|
||||
std::vector<std::string> paths = defaultSearchPaths;
|
||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
||||
gpb.depthStencilState.depthTestEnable = true;
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||
gpb.addAttributeDescriptions({
|
||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
});
|
||||
|
||||
vk::PipelineColorBlendAttachmentState res;
|
||||
res.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
|
||||
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
|
||||
VkPipelineColorBlendAttachmentState res{};
|
||||
res.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
res.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
gpb.addBlendAttachmentState(res);
|
||||
|
||||
m_graphicsPipeline = gpb.createPipeline();
|
||||
|
|
@ -225,8 +212,6 @@ void HelloVulkan::createGraphicsPipeline()
|
|||
//
|
||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
|
||||
LOGI("Loading File: %s \n", filename.c_str());
|
||||
ObjLoader loader;
|
||||
loader.loadModel(filename);
|
||||
|
|
@ -250,18 +235,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
||||
|
||||
// Create the buffers on Device and copy vertices, indices and materials
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
model.vertexBuffer =
|
||||
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
|
||||
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
||||
model.indexBuffer =
|
||||
m_alloc.createBuffer(cmdBuf, loader.m_indices,
|
||||
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
|
||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
// Creates all textures found
|
||||
createTextureImages(cmdBuf, loader.m_textures);
|
||||
cmdBufGet.submitAndWait(cmdBuf);
|
||||
|
|
@ -277,17 +258,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
m_objInstance.emplace_back(instance);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Creating the uniform buffer holding the camera matrices
|
||||
// - Buffer is host visible
|
||||
//
|
||||
void HelloVulkan::createUniformBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
using vkMP = vk::MemoryPropertyFlagBits;
|
||||
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||
}
|
||||
|
||||
|
|
@ -299,11 +278,10 @@ void HelloVulkan::createUniformBuffer()
|
|||
//
|
||||
void HelloVulkan::createSceneDescriptionBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||
|
||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
cmdGen.submitAndWait(cmdBuf);
|
||||
m_alloc.finalizeAndReleaseStaging();
|
||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||
|
|
@ -312,15 +290,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Creating all textures and samplers
|
||||
//
|
||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures)
|
||||
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, 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{
|
||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
|
||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||
if(textures.empty() && m_textures.empty())
|
||||
|
|
@ -328,18 +306,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
nvvk::Texture texture;
|
||||
|
||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||
vk::DeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = vk::Extent2D(1, 1);
|
||||
VkDeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = VkExtent2D{1, 1};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||
|
||||
// Creating the VKImage
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
// Creating the dummy texture
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
else
|
||||
|
|
@ -352,8 +329,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
o << "media/textures/" << texture;
|
||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||
|
||||
stbi_uc* stbi_pixels =
|
||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
|
||||
std::array<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());
|
||||
}
|
||||
|
||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
||||
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||
|
||||
{
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||
vk::ImageViewCreateInfo ivInfo =
|
||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
|
|
@ -390,10 +365,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
//
|
||||
void HelloVulkan::destroyResources()
|
||||
{
|
||||
m_device.destroy(m_graphicsPipeline);
|
||||
m_device.destroy(m_pipelineLayout);
|
||||
m_device.destroy(m_descPool);
|
||||
m_device.destroy(m_descSetLayout);
|
||||
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||
|
||||
m_alloc.destroy(m_cameraMat);
|
||||
m_alloc.destroy(m_sceneDesc);
|
||||
|
||||
|
|
@ -411,22 +387,22 @@ void HelloVulkan::destroyResources()
|
|||
}
|
||||
|
||||
//#Post
|
||||
m_device.destroy(m_postPipeline);
|
||||
m_device.destroy(m_postPipelineLayout);
|
||||
m_device.destroy(m_postDescPool);
|
||||
m_device.destroy(m_postDescSetLayout);
|
||||
m_alloc.destroy(m_offscreenColor);
|
||||
m_alloc.destroy(m_gBuffer);
|
||||
m_alloc.destroy(m_aoBuffer);
|
||||
m_alloc.destroy(m_offscreenDepth);
|
||||
m_device.destroy(m_offscreenRenderPass);
|
||||
m_device.destroy(m_offscreenFramebuffer);
|
||||
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
||||
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||
|
||||
// Compute
|
||||
m_device.destroy(m_compDescPool);
|
||||
m_device.destroy(m_compDescSetLayout);
|
||||
m_device.destroy(m_compPipeline);
|
||||
m_device.destroy(m_compPipelineLayout);
|
||||
vkDestroyPipeline(m_device, m_compPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
|
||||
|
||||
// #VKRay
|
||||
m_rtBuilder.destroy();
|
||||
|
|
@ -436,32 +412,31 @@ void HelloVulkan::destroyResources()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Drawing the scene in raster mode
|
||||
//
|
||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
using vkPBP = vk::PipelineBindPoint;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
vk::DeviceSize offset{0};
|
||||
VkDeviceSize offset{0};
|
||||
|
||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||
|
||||
// Dynamic Viewport
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
||||
setViewport(cmdBuf);
|
||||
|
||||
// Drawing all triangles
|
||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||
|
||||
|
||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||
{
|
||||
auto& inst = m_objInstance[i];
|
||||
auto& model = m_objModel[inst.objIndex];
|
||||
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
||||
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
||||
m_pushConstant);
|
||||
|
||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||
sizeof(ObjPushConstant), &m_pushConstant);
|
||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||
}
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
@ -491,64 +466,62 @@ void HelloVulkan::createOffscreenRender()
|
|||
m_alloc.destroy(m_aoBuffer);
|
||||
m_alloc.destroy(m_offscreenDepth);
|
||||
|
||||
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||
|
||||
// Creating the color image
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_offscreenColor.image, "offscreen");
|
||||
}
|
||||
|
||||
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
||||
}
|
||||
|
||||
// The ambient occlusion result (r32)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
||||
}
|
||||
|
||||
|
||||
// Creating the depth buffer
|
||||
auto depthCreateInfo =
|
||||
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
|
||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
||||
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
{
|
||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
||||
|
||||
vk::ImageViewCreateInfo depthStencilView;
|
||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
||||
depthStencilView.setFormat(m_offscreenDepthFormat);
|
||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
||||
depthStencilView.setImage(image.image);
|
||||
|
||||
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthStencilView.format = m_offscreenDepthFormat;
|
||||
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||
depthStencilView.image = image.image;
|
||||
|
||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
||||
}
|
||||
|
|
@ -557,15 +530,11 @@ void HelloVulkan::createOffscreenRender()
|
|||
{
|
||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
||||
vk::ImageAspectFlagBits::eDepth);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
|
||||
genCmdBuf.submitAndWait(cmdBuf);
|
||||
}
|
||||
|
|
@ -574,26 +543,23 @@ void HelloVulkan::createOffscreenRender()
|
|||
if(!m_offscreenRenderPass)
|
||||
{
|
||||
m_offscreenRenderPass =
|
||||
nvvk::createRenderPass(m_device,
|
||||
{m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
|
||||
m_offscreenDepthFormat, 1, true, true, vk::ImageLayout::eGeneral,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::createRenderPass(m_device, {m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
|
||||
m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||
}
|
||||
|
||||
// Creating the frame buffer for offscreen
|
||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||
m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
|
||||
m_device.destroy(m_offscreenFramebuffer);
|
||||
vk::FramebufferCreateInfo info;
|
||||
info.setRenderPass(m_offscreenRenderPass);
|
||||
info.setAttachmentCount(static_cast<int>(attachments.size()));
|
||||
info.setPAttachments(attachments.data());
|
||||
info.setWidth(m_size.width);
|
||||
info.setHeight(m_size.height);
|
||||
info.setLayers(1);
|
||||
m_offscreenFramebuffer = m_device.createFramebuffer(info);
|
||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
info.renderPass = m_offscreenRenderPass;
|
||||
info.attachmentCount = static_cast<int>(attachments.size());
|
||||
info.pAttachments = attachments.data();
|
||||
info.width = m_size.width;
|
||||
info.height = m_size.height;
|
||||
info.layers = 1;
|
||||
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -602,26 +568,23 @@ void HelloVulkan::createOffscreenRender()
|
|||
void HelloVulkan::createPostPipeline()
|
||||
{
|
||||
// Push constants in the fragment shader
|
||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||
|
||||
// Creating the pipeline layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_postDescSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
||||
|
||||
|
||||
// Pipeline: completely generic, no vertices
|
||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
|
||||
m_renderPass);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
||||
true),
|
||||
vk::ShaderStageFlagBits::eVertex);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
||||
vk::ShaderStageFlagBits::eFragment);
|
||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
||||
m_postPipeline = pipelineGenerator.createPipeline();
|
||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||
m_postPipeline = pipelineGenerator.createPipeline();
|
||||
m_debug.setObjectName(m_postPipeline, "post");
|
||||
}
|
||||
|
||||
|
|
@ -631,12 +594,8 @@ void HelloVulkan::createPostPipeline()
|
|||
//
|
||||
void HelloVulkan::createPostDescriptor()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
||||
|
|
@ -647,36 +606,32 @@ void HelloVulkan::createPostDescriptor()
|
|||
//
|
||||
void HelloVulkan::updatePostDescriptorSet()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
writes.emplace_back(
|
||||
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
|
||||
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
||||
m_device.updateDescriptorSets(static_cast<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
|
||||
//
|
||||
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
||||
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
||||
{
|
||||
m_debug.beginLabel(cmdBuf, "Post");
|
||||
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
||||
setViewport(cmdBuf);
|
||||
|
||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
||||
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0,
|
||||
aspectRatio);
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0,
|
||||
m_postDescSet, {});
|
||||
cmdBuf.draw(3, 1, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
||||
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Raytracing, creation of BLAS and TLAS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -685,45 +640,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
|||
void HelloVulkan::initRayTracing()
|
||||
{
|
||||
// Requesting ray tracing properties
|
||||
auto properties =
|
||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
prop2.pNext = &m_rtProperties;
|
||||
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||
|
||||
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS
|
||||
// Convert an OBJ model into the ray tracing geometry used to build the BLAS
|
||||
//
|
||||
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
||||
{
|
||||
// Building part
|
||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
||||
// BLAS builder requires raw device addresses.
|
||||
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||
info.buffer = model.vertexBuffer.buffer;
|
||||
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||
info.buffer = model.indexBuffer.buffer;
|
||||
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||
|
||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
||||
triangles.setVertexData(vertexAddress);
|
||||
triangles.setVertexStride(sizeof(VertexObj));
|
||||
triangles.setIndexType(vk::IndexType::eUint32);
|
||||
triangles.setIndexData(indexAddress);
|
||||
triangles.setTransformData({});
|
||||
triangles.setMaxVertex(model.nbVertices);
|
||||
uint32_t maxPrimitiveCount = model.nbIndices / 3;
|
||||
|
||||
// Setting up the build info of the acceleration
|
||||
vk::AccelerationStructureGeometryKHR asGeom;
|
||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
||||
asGeom.geometry.setTriangles(triangles);
|
||||
// Describe buffer as array of VertexObj.
|
||||
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
|
||||
triangles.vertexData.deviceAddress = vertexAddress;
|
||||
triangles.vertexStride = sizeof(VertexObj);
|
||||
// Describe index data (32-bit unsigned int)
|
||||
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
triangles.indexData.deviceAddress = indexAddress;
|
||||
// Indicate identity transform by setting transformData to null device pointer.
|
||||
//triangles.transformData = {};
|
||||
triangles.maxVertex = model.nbVertices;
|
||||
|
||||
// The primitive itself
|
||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.setFirstVertex(0);
|
||||
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
|
||||
offset.setPrimitiveOffset(0);
|
||||
offset.setTransformOffset(0);
|
||||
// Identify the above data as containing opaque triangles.
|
||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||
asGeom.geometry.triangles = triangles;
|
||||
|
||||
// Our blas is only one geometry, but could be made of many geometries
|
||||
// The entire array will be used to build the BLAS.
|
||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.firstVertex = 0;
|
||||
offset.primitiveCount = maxPrimitiveCount;
|
||||
offset.primitiveOffset = 0;
|
||||
offset.transformOffset = 0;
|
||||
|
||||
// Our blas is made from only one geometry, but could be made of many geometries
|
||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||
input.asGeometry.emplace_back(asGeom);
|
||||
input.asBuildOffsetInfo.emplace_back(offset);
|
||||
|
|
@ -746,7 +709,7 @@ void HelloVulkan::createBottomLevelAS()
|
|||
// We could add more geometry in each BLAS, but we add only one for now
|
||||
allBlas.emplace_back(blas);
|
||||
}
|
||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||
}
|
||||
|
||||
void HelloVulkan::createTopLevelAS()
|
||||
|
|
@ -763,7 +726,7 @@ void HelloVulkan::createTopLevelAS()
|
|||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
tlas.emplace_back(rayInst);
|
||||
}
|
||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -776,12 +739,9 @@ void HelloVulkan::createTopLevelAS()
|
|||
//
|
||||
void HelloVulkan::createCompDescriptors()
|
||||
{
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
|
||||
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
|
||||
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
|
||||
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
|
||||
m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
|
||||
m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
|
||||
|
||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||
|
|
@ -793,15 +753,17 @@ void HelloVulkan::createCompDescriptors()
|
|||
//
|
||||
void HelloVulkan::updateCompDescriptors()
|
||||
{
|
||||
std::vector<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, 1, &m_aoBuffer.descriptor));
|
||||
|
||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
|
||||
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||
descASInfo.accelerationStructureCount = 1;
|
||||
descASInfo.pAccelerationStructures = &tlas;
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
||||
|
||||
m_device.updateDescriptorSets(static_cast<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()
|
||||
{
|
||||
// pushing time
|
||||
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(AoControl)};
|
||||
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants};
|
||||
m_compPipelineLayout = m_device.createPipelineLayout(layout_info);
|
||||
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
|
||||
VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl)};
|
||||
VkPipelineLayoutCreateInfo plCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
plCreateInfo.setLayoutCount = 1;
|
||||
plCreateInfo.pSetLayouts = &m_compDescSetLayout;
|
||||
plCreateInfo.pushConstantRangeCount = 1;
|
||||
plCreateInfo.pPushConstantRanges = &push_constants;
|
||||
vkCreatePipelineLayout(m_device, &plCreateInfo, nullptr, &m_compPipelineLayout);
|
||||
|
||||
computePipelineCreateInfo.stage =
|
||||
nvvk::createShaderStageInfo(m_device,
|
||||
nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
|
||||
VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo).value;
|
||||
m_device.destroy(computePipelineCreateInfo.stage.module);
|
||||
VkComputePipelineCreateInfo cpCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
|
||||
cpCreateInfo.layout = m_compPipelineLayout;
|
||||
cpCreateInfo.stage = nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
|
||||
VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
|
||||
vkCreateComputePipelines(m_device, {}, 1, &cpCreateInfo, nullptr, &m_compPipeline);
|
||||
|
||||
vkDestroyShaderModule(m_device, cpCreateInfo.stage.module, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Running compute shader
|
||||
//
|
||||
#define GROUP_SIZE 16 // Same group size as in compute shader
|
||||
void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
|
||||
void HelloVulkan::runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl)
|
||||
{
|
||||
updateFrame();
|
||||
|
||||
|
|
@ -839,43 +806,38 @@ void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
|
|||
|
||||
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
||||
// before the compute shader is using the buffer
|
||||
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
|
||||
vk::ImageMemoryBarrier imgMemBarrier;
|
||||
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
||||
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
imgMemBarrier.setImage(m_gBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
imgMemBarrier.image = m_gBuffer.image;
|
||||
imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.subresourceRange = range;
|
||||
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
|
||||
|
||||
// Preparing for the compute shader
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
||||
{m_compDescSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||
|
||||
|
||||
// Sending the push constant information
|
||||
aoControl.frame = m_frame;
|
||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
|
||||
sizeof(AoControl), &aoControl);
|
||||
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
|
||||
|
||||
// Dispatching the shader
|
||||
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
|
||||
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
|
||||
|
||||
// Adding a barrier to be sure the compute shader has finished
|
||||
// writing to the AO buffer before the post shader is using it
|
||||
imgMemBarrier.setImage(m_aoBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
imgMemBarrier.image = m_aoBuffer.image;
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/appbase_vk.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/memallocator_dma_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
|
||||
// #VKRay
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
|
@ -46,25 +46,21 @@ struct AoControl
|
|||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
class HelloVulkan : public nvvk::AppBaseVk
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||
|
||||
// The OBJ model
|
||||
struct ObjModel
|
||||
|
|
@ -89,7 +85,7 @@ public:
|
|||
// Information pushed at each draw call
|
||||
struct ObjPushConstant
|
||||
{
|
||||
nvmath::vec3f lightPosition{3.5f, 8.f, 5.f};
|
||||
nvmath::vec3f lightPosition{10.f, 15.f, 8.f};
|
||||
int instanceId{0}; // To retrieve the transformation matrix
|
||||
float lightIntensity{100.f};
|
||||
int lightType{0}; // 0: point, 1: infinite
|
||||
|
|
@ -101,41 +97,43 @@ public:
|
|||
std::vector<ObjInstance> m_objInstance;
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
VkDescriptorPool m_descPool;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||
|
||||
|
||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
|
||||
|
||||
// #Post
|
||||
void createOffscreenRender();
|
||||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
void updatePostDescriptorSet();
|
||||
void drawPost(vk::CommandBuffer cmdBuf);
|
||||
void drawPost(VkCommandBuffer cmdBuf);
|
||||
|
||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||
vk::DescriptorPool m_postDescPool;
|
||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
||||
vk::DescriptorSet m_postDescSet;
|
||||
vk::Pipeline m_postPipeline;
|
||||
vk::PipelineLayout m_postPipelineLayout;
|
||||
vk::RenderPass m_offscreenRenderPass;
|
||||
vk::Framebuffer m_offscreenFramebuffer;
|
||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||
nvvk::Texture m_offscreenColor;
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||
nvvk::Texture m_gBuffer;
|
||||
nvvk::Texture m_aoBuffer;
|
||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
|
||||
|
||||
// #Tuto_rayquery
|
||||
void initRayTracing();
|
||||
|
|
@ -143,22 +141,23 @@ public:
|
|||
void createBottomLevelAS();
|
||||
void createTopLevelAS();
|
||||
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
|
||||
|
||||
// #Tuto_animation
|
||||
void createCompDescriptors();
|
||||
void updateCompDescriptors();
|
||||
void createCompPipelines();
|
||||
void runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl);
|
||||
void runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl);
|
||||
|
||||
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
||||
vk::DescriptorPool m_compDescPool;
|
||||
vk::DescriptorSetLayout m_compDescSetLayout;
|
||||
vk::DescriptorSet m_compDescSet;
|
||||
vk::Pipeline m_compPipeline;
|
||||
vk::PipelineLayout m_compPipelineLayout;
|
||||
VkDescriptorPool m_compDescPool;
|
||||
VkDescriptorSetLayout m_compDescSetLayout;
|
||||
VkDescriptorSet m_compDescSet;
|
||||
VkPipeline m_compPipeline;
|
||||
VkPipelineLayout m_compPipelineLayout;
|
||||
|
||||
// #Tuto_jitter_cam
|
||||
void updateFrame();
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@
|
|||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
#include "backends/imgui_impl_glfw.h"
|
||||
#include "imgui.h"
|
||||
|
||||
|
|
@ -36,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvpsystem.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/context_vk.hpp"
|
||||
|
||||
|
|
@ -48,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
// Default search path for shaders
|
||||
std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// GLFW Callback functions
|
||||
static void onErrorCallback(int error, const char* description)
|
||||
{
|
||||
|
|
@ -75,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
|
|||
static int const SAMPLE_WIDTH = 1280;
|
||||
static int const SAMPLE_HEIGHT = 720;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Application Entry
|
||||
//
|
||||
|
|
@ -89,8 +87,7 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window =
|
||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
|
|
@ -117,9 +114,9 @@ int main(int argc, char** argv)
|
|||
nvvk::ContextCreateInfo contextInfo(true);
|
||||
contextInfo.setVersion(1, 2);
|
||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||
#ifdef WIN32
|
||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#ifdef _WIN32
|
||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#else
|
||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||
|
|
@ -129,19 +126,20 @@ int main(int argc, char** argv)
|
|||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures;
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
||||
&accelFeatures);
|
||||
vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures;
|
||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeatures);
|
||||
VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
|
||||
|
||||
|
||||
// Creating Vulkan base application
|
||||
nvvk::Context vkctx{};
|
||||
vkctx.initInstance(contextInfo);
|
||||
|
|
@ -151,16 +149,14 @@ int main(int argc, char** argv)
|
|||
// Use a compatible device
|
||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||
|
||||
|
||||
// Create example
|
||||
HelloVulkan helloVk;
|
||||
|
||||
// Window need to be opened to get the surface on which to draw
|
||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
vkctx.setGCTQueueWithPresent(surface);
|
||||
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
||||
vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
helloVk.createDepthBuffer();
|
||||
helloVk.createRenderPass();
|
||||
|
|
@ -241,8 +237,7 @@ int main(int argc, char** argv)
|
|||
helloVk.resetFrame();
|
||||
}
|
||||
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||
ImGuiH::Panel::End();
|
||||
}
|
||||
|
|
@ -251,66 +246,67 @@ int main(int argc, char** argv)
|
|||
helloVk.prepareFrame();
|
||||
|
||||
// Start command buffer of this frame
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
|
||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||
|
||||
// Updating camera buffer
|
||||
helloVk.updateUniformBuffer(cmdBuf);
|
||||
|
||||
// Clearing screen
|
||||
std::array<vk::ClearValue, 3> clearValues;
|
||||
clearValues[0].setColor(
|
||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
||||
std::array<VkClearValue, 3> clearValues{};
|
||||
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||
|
||||
|
||||
// Offscreen render pass
|
||||
{
|
||||
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
|
||||
clearValues[2].setDepthStencil({1.0f, 0});
|
||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
||||
offscreenRenderPassBeginInfo.setClearValueCount(3);
|
||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
clearValues[1].color = {{0, 0, 0, 0}};
|
||||
clearValues[2].depthStencil = {1.0f, 0};
|
||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
offscreenRenderPassBeginInfo.clearValueCount = (uint32_t)clearValues.size();
|
||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
// Rendering Scene
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
helloVk.runCompute(cmdBuf, aoControl);
|
||||
}
|
||||
}
|
||||
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
clearValues[1].setDepthStencil({1.0f, 0});
|
||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
||||
postRenderPassBeginInfo.setClearValueCount(2);
|
||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
clearValues[1].depthStencil = {1.0f, 0};
|
||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
postRenderPassBeginInfo.clearValueCount = 2;
|
||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.drawPost(cmdBuf);
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
vkEndCommandBuffer(cmdBuf);
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
catch(const std::system_error& e)
|
||||
{
|
||||
if(e.code() == vk::Result::eErrorDeviceLost)
|
||||
if(e.code().value() == VK_ERROR_DEVICE_LOST)
|
||||
{
|
||||
#if _WIN32
|
||||
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
|
||||
|
|
@ -322,10 +318,10 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
vkDeviceWaitIdle(helloVk.getDevice());
|
||||
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
|
||||
vkctx.deinit();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|||
#--------------------------------------------------------------------------------------------------
|
||||
# Project setting
|
||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
||||
project(${PROJNAME} LANGUAGES C CXX)
|
||||
message(STATUS "-------------------------------")
|
||||
message(STATUS "Processing Project ${PROJNAME}:")
|
||||
|
|
|
|||
|
|
@ -63,39 +63,50 @@ executeCallableEXT(pushC.lightType, 0);
|
|||
In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit shader, we will add
|
||||
3 callable shaders, for each type of light.
|
||||
|
||||
First create the shader modules
|
||||
~~~~ C++
|
||||
enum StageIndices
|
||||
{
|
||||
eRaygen,
|
||||
eMiss,
|
||||
eMiss2,
|
||||
eClosestHit,
|
||||
eCall0,
|
||||
eCall1,
|
||||
eCall2,
|
||||
eShaderGroupCount
|
||||
};
|
||||
|
||||
...
|
||||
// Call0
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||
stages[eCall0] = stage;
|
||||
// Call1
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||
stages[eCall1] = stage;
|
||||
// Call2
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||
stages[eCall2] = stage;
|
||||
~~~~
|
||||
|
||||
Then 3 groups of callable shaders and the stages that goes with it.
|
||||
|
||||
~~~~ C++
|
||||
// Callable shaders
|
||||
vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
|
||||
vk::ShaderModule call0 =
|
||||
nvvk::createShaderModule(m_device,
|
||||
nvh::loadFile("shaders/light_point.rcall.spv", true, paths));
|
||||
vk::ShaderModule call1 =
|
||||
nvvk::createShaderModule(m_device,
|
||||
nvh::loadFile("shaders/light_spot.rcall.spv", true, paths));
|
||||
vk::ShaderModule call2 =
|
||||
nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths));
|
||||
|
||||
callGroup.setGeneralShader(static_cast<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);
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.generalShader = eCall0;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
group.generalShader = eCall1;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
group.generalShader = eCall2;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
~~~~
|
||||
|
||||
And at the end of the function, delete the shaders.
|
||||
|
||||
~~~~ C++
|
||||
m_device.destroy(call0);
|
||||
m_device.destroy(call1);
|
||||
m_device.destroy(call2);
|
||||
~~~~
|
||||
|
||||
#### Shaders
|
||||
|
||||
|
|
@ -106,29 +117,44 @@ Here are the source of all shaders
|
|||
* [light_inf.rcall](shaders/light_inf.rcall)
|
||||
|
||||
|
||||
### Passing Callable to traceRaysKHR
|
||||
### Shading Binding Table
|
||||
|
||||
In this example, we will use the `nvvk::SBTWrapper`. It is using the information to create the ray tracing pipeline, to
|
||||
create the buffers for the shading binding table.
|
||||
|
||||
In the `hello_vulkan.h` header, include the wrapper and add a new member.
|
||||
|
||||
~~~~C
|
||||
#include "nvvk/sbtwrapper_vk.hpp"
|
||||
...
|
||||
nvvk::SBTWrapper m_sbtWrapper;
|
||||
~~~~
|
||||
|
||||
In `HelloVulkan::initRayTracing()`, initialize it the following way.
|
||||
|
||||
~~~~C
|
||||
m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties);
|
||||
~~~~
|
||||
|
||||
In `HelloVulkan::createRtPipeline()`, immediately after creating the pipeline call to `vkCreateRayTracingPipelinesKHR()`,
|
||||
create the SBT with the following command.
|
||||
|
||||
~~~~C
|
||||
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
|
||||
~~~~
|
||||
|
||||
|
||||
|
||||
In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Since they were added after the hit shader, we have in the SBT the following.
|
||||
|
||||

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

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