Using Vulkan C API

This commit is contained in:
mklefrancois 2021-06-07 14:02:45 +02:00
parent b3e6d84807
commit e642e9dc3a
83 changed files with 8015 additions and 8163 deletions

View file

@ -1,4 +1,4 @@
BasedOnStyle: LLVM BasedOnStyle: LLVM
AccessModifierOffset: '-2' AccessModifierOffset: '-2'
AlignAfterOpenBracket: Align AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: 'true' AlignConsecutiveAssignments: 'true'
@ -21,7 +21,7 @@ BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: 'false' BreakBeforeTernaryOperators: 'false'
BreakConstructorInitializersBeforeComma: 'true' BreakConstructorInitializersBeforeComma: 'true'
ColumnLimit: '100' ColumnLimit: '120'
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
Cpp11BracedListStyle: 'true' Cpp11BracedListStyle: 'true'
IndentCaseLabels: 'true' IndentCaseLabels: 'true'
@ -44,7 +44,7 @@ SpacesInSquareBrackets: 'false'
Standard: Cpp11 Standard: Cpp11
TabWidth: '2' TabWidth: '2'
UseTab: Never UseTab: Never
SortIncludes: 'true' SortIncludes: 'false'
ReflowComments: 'false' ReflowComments: 'false'
BraceWrapping: { BraceWrapping: {
AfterClass: 'true' AfterClass: 'true'
@ -58,7 +58,7 @@ BraceWrapping: {
BeforeElse: 'true' BeforeElse: 'true'
IndentBraces: 'false' IndentBraces: 'false'
} }
PenaltyExcessCharacter: 9999 PenaltyExcessCharacter: 1
PenaltyBreakBeforeFirstCallParameter: 40 PenaltyBreakBeforeFirstCallParameter: 40
PenaltyBreakFirstLessLess: 1 PenaltyBreakFirstLessLess: 1
PenaltyBreakComment: 30 PenaltyBreakComment: 30

View file

@ -38,12 +38,11 @@ void ObjLoader::loadModel(const std::string& filename)
for(const auto& material : reader.GetMaterials()) for(const auto& material : reader.GetMaterials())
{ {
MaterialObj m; MaterialObj m;
m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]); m.ambient = nvmath::vec3f(material.ambient[0], material.ambient[1], material.ambient[2]);
m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]); m.diffuse = nvmath::vec3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]);
m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]); m.specular = nvmath::vec3f(material.specular[0], material.specular[1], material.specular[2]);
m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]); m.emission = nvmath::vec3f(material.emission[0], material.emission[1], material.emission[2]);
m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1], m.transmittance = nvmath::vec3f(material.transmittance[0], material.transmittance[1], material.transmittance[2]);
material.transmittance[2]);
m.dissolve = material.dissolve; m.dissolve = material.dissolve;
m.ior = material.ior; m.ior = material.ior;
m.shininess = material.shininess; m.shininess = material.shininess;
@ -67,8 +66,7 @@ void ObjLoader::loadModel(const std::string& filename)
{ {
m_vertices.reserve(shape.mesh.indices.size() + m_vertices.size()); m_vertices.reserve(shape.mesh.indices.size() + m_vertices.size());
m_indices.reserve(shape.mesh.indices.size() + m_indices.size()); m_indices.reserve(shape.mesh.indices.size() + m_indices.size());
m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(), m_matIndx.insert(m_matIndx.end(), shape.mesh.material_ids.begin(), shape.mesh.material_ids.end());
shape.mesh.material_ids.end());
for(const auto& index : shape.mesh.indices) for(const auto& index : shape.mesh.indices)
{ {

View file

@ -36,7 +36,7 @@ struct MaterialObj
float shininess = 0.f; float shininess = 0.f;
float ior = 1.0f; // index of refraction float ior = 1.0f; // index of refraction
float dissolve = 1.f; // 1 == opaque; 0 == fully transparent float dissolve = 1.f; // 1 == opaque; 0 == fully transparent
// illumination model (see http://www.fileformat.info/format/material/) // illumination model (see http://www.fileformat.info/format/material/)
int illum = 0; int illum = 0;
int textureID = -1; int textureID = -1;
}; };

View file

@ -43,7 +43,7 @@ The directory structure should be looking like:
********************************************************** **********************************************************
!!! Warning !!! Warning CMake
**Run CMake** in vk_raytracing_tutorial_KHR. **Run CMake** in vk_raytracing_tutorial_KHR.
!!! Warning Beta Vulkan SDK !!! Warning Beta Vulkan SDK

View file

@ -202,18 +202,18 @@ void HelloVulkan::createLanternIndirectBuffer()
// m_alloc behind the scenes uses cmdBuf to transfer data to the buffer. // m_alloc behind the scenes uses cmdBuf to transfer data to the buffer.
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
using Usage = vk::BufferUsageFlagBits; using Usage = VkBufferUsageFlagBits;
m_lanternIndirectBuffer = m_lanternIndirectBuffer = m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount,
m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
Usage::eIndirectBuffer | Usage::eTransferDst | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
| Usage::eShaderDeviceAddress | Usage::eStorageBuffer, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vk::MemoryPropertyFlagBits::eDeviceLocal);
std::vector<LanternIndirectEntry> entries(m_lanternCount); std::vector<LanternIndirectEntry> entries(m_lanternCount);
for (size_t i = 0; i < m_lanternCount; ++i) entries[i].lantern = m_lanterns[i]; for(size_t i = 0; i < m_lanternCount; ++i)
cmdBuf.updateBuffer(m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data()); entries[i].lantern = m_lanterns[i];
vkCmdUpdateBuffer(cmdBuf, m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data());
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
} }
@ -370,12 +370,12 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes.
`hello_vulkan.h`: `hello_vulkan.h`:
```` C ```` C
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind; nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
vk::DescriptorPool m_lanternIndirectDescPool; VkDescriptorPool m_lanternIndirectDescPool;
vk::DescriptorSetLayout m_lanternIndirectDescSetLayout; VkDescriptorSetLayout m_lanternIndirectDescSetLayout;
vk::DescriptorSet m_lanternIndirectDescSet; VkDescriptorSet m_lanternIndirectDescSet;
vk::PipelineLayout m_lanternIndirectCompPipelineLayout; VkPipelineLayout m_lanternIndirectCompPipelineLayout;
vk::Pipeline m_lanternIndirectCompPipeline; VkPipeline m_lanternIndirectCompPipeline;
```` ````
`hello_vulkan.cpp`: `hello_vulkan.cpp`:
@ -385,26 +385,25 @@ to allocate one descriptor as the `LanternIndirectEntry` array never changes.
// The compute shader just needs read/write access to the buffer of LanternIndirectEntry. // The compute shader just needs read/write access to the buffer of LanternIndirectEntry.
void HelloVulkan::createLanternIndirectDescriptorSet() void HelloVulkan::createLanternIndirectDescriptorSet()
{ {
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
using vkDSLB = vk::DescriptorSetLayoutBinding;
// Lantern buffer (binding = 0) // Lantern buffer (binding = 0)
m_lanternIndirectDescSetLayoutBind.addBinding( // m_lanternIndirectDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT);
vkDSLB(0, vkDT::eStorageBuffer, 1, vkSS::eCompute));
m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device); m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device);
m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device); m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device);
m_lanternIndirectDescSet =
m_device.allocateDescriptorSets({m_lanternIndirectDescPool, 1, &m_lanternIndirectDescSetLayout})[0]; VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
allocateInfo.descriptorPool = m_lanternIndirectDescPool;
allocateInfo.descriptorSetCount = 1;
allocateInfo.pSetLayouts = &m_lanternIndirectDescSetLayout;
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_lanternIndirectDescSet);
assert(m_lanternIndirectBuffer.buffer); assert(m_lanternIndirectBuffer.buffer);
vk::DescriptorBufferInfo lanternBufferInfo{ VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)};
m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)};
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, &lanternBufferInfo)); writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, &lanternBufferInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
// Create compute pipeline used to fill m_lanternIndirectBuffer with parameters // Create compute pipeline used to fill m_lanternIndirectBuffer with parameters
@ -412,32 +411,31 @@ void HelloVulkan::createLanternIndirectDescriptorSet()
void HelloVulkan::createLanternIndirectCompPipeline() void HelloVulkan::createLanternIndirectCompPipeline()
{ {
// Compile compute shader and package as stage. // Compile compute shader and package as stage.
vk::ShaderModule computeShader = VkShaderModule computeShader =
nvvk::createShaderModule(m_device, // nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/lanternIndirect.comp.spv", true, defaultSearchPaths, true)); VkPipelineShaderStageCreateInfo stageInfo{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
vk::PipelineShaderStageCreateInfo stageInfo; stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
stageInfo.setStage(vk::ShaderStageFlagBits::eCompute); stageInfo.module = computeShader;
stageInfo.setModule(computeShader); stageInfo.pName = "main";
stageInfo.setPName("main");
// Set up push constant and pipeline layout. // Set up push constant and pipeline layout.
constexpr auto pushSize = static_cast<uint32_t>(sizeof(m_lanternIndirectPushConstants)); constexpr auto pushSize = static_cast<uint32_t>(sizeof(m_lanternIndirectPushConstants));
vk::PushConstantRange pushCRange = {vk::ShaderStageFlagBits::eCompute, 0, pushSize}; VkPushConstantRange pushCRange = {VK_SHADER_STAGE_COMPUTE_BIT, 0, pushSize};
static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant"); static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant");
vk::PipelineLayoutCreateInfo layoutInfo; VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
layoutInfo.setSetLayoutCount(1); layoutInfo.setLayoutCount = 1;
layoutInfo.setPSetLayouts(&m_lanternIndirectDescSetLayout); layoutInfo.pSetLayouts = &m_lanternIndirectDescSetLayout;
layoutInfo.setPushConstantRangeCount(1); layoutInfo.pushConstantRangeCount = 1;
layoutInfo.setPPushConstantRanges(&pushCRange); layoutInfo.pPushConstantRanges = &pushCRange;
m_lanternIndirectCompPipelineLayout = m_device.createPipelineLayout(layoutInfo); vkCreatePipelineLayout(m_device, &layoutInfo, nullptr, &m_lanternIndirectCompPipelineLayout);
// Create compute pipeline. // Create compute pipeline.
vk::ComputePipelineCreateInfo pipelineInfo; VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
pipelineInfo.setStage(stageInfo); pipelineInfo.stage = stageInfo;
pipelineInfo.setLayout(m_lanternIndirectCompPipelineLayout); pipelineInfo.layout = m_lanternIndirectCompPipelineLayout;
m_lanternIndirectCompPipeline = static_cast<const vk::Pipeline&>(m_device.createComputePipeline({}, pipelineInfo)); vkCreateComputePipelines(m_device, {}, 1, &pipelineInfo, nullptr, &m_lanternIndirectCompPipeline);
m_device.destroy(computeShader); vkDestroyShaderModule(m_device, computeShader, nullptr);
} }
```` ````
@ -464,61 +462,72 @@ pipeline barrier synchronizing access to the `LanternIndirectEntry` array
between the compute shader and indirect draw stages. between the compute shader and indirect draw stages.
```` C ```` C
void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) //--------------------------------------------------------------------------------------------------
// Ray Tracing the scene
//
// The raytracing is split into multiple passes:
//
// First pass fills in the initial values for every pixel in the output image.
// Illumination and shadow rays come from the main light.
//
// Subsequently, one lantern pass is run for each lantern in the scene. We run
// a compute shader to calculate a bounding scissor rectangle for each lantern's light
// effect. This is stored in m_lanternIndirectBuffer. Then an indirect trace rays command
// is run for every lantern within its scissor rectangle. The lanterns' light
// contribution is additively blended into the output image.
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
{ {
// Before tracing rays, we need to dispatch the compute shaders that // Before tracing rays, we need to dispatch the compute shaders that
// fill in the ray trace indirect parameters for each lantern pass. // fill in the ray trace indirect parameters for each lantern pass.
// First, barrier before, ensure writes aren't visible to previous frame. // First, barrier before, ensure writes aren't visible to previous frame.
vk::BufferMemoryBarrier bufferBarrier; VkBufferMemoryBarrier bufferBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eIndirectCommandRead); bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderWrite); bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
bufferBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.setBuffer(m_lanternIndirectBuffer.buffer); bufferBarrier.buffer = m_lanternIndirectBuffer.buffer;
bufferBarrier.offset = 0; bufferBarrier.offset = 0;
bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0]; bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0];
cmdBuf.pipelineBarrier( // vkCmdPipelineBarrier(cmdBuf,
vk::PipelineStageFlagBits::eDrawIndirect, // VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, //
vk::PipelineStageFlagBits::eComputeShader,// VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
vk::DependencyFlags(0), // VkDependencyFlags(0), //
{}, {bufferBarrier}, {}); 0, nullptr, 1, &bufferBarrier, 0, nullptr);
// Bind compute shader, update push constant and descriptors, dispatch compute. // Bind compute shader, update push constant and descriptors, dispatch compute.
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipeline);
nvmath::mat4 view = getViewMatrix(); nvmath::mat4 view = getViewMatrix();
m_lanternIndirectPushConstants.viewRowX = view.row(0); m_lanternIndirectPushConstants.viewRowX = view.row(0);
m_lanternIndirectPushConstants.viewRowY = view.row(1); m_lanternIndirectPushConstants.viewRowY = view.row(1);
m_lanternIndirectPushConstants.viewRowZ = view.row(2); m_lanternIndirectPushConstants.viewRowZ = view.row(2);
m_lanternIndirectPushConstants.proj = getProjMatrix(); m_lanternIndirectPushConstants.proj = getProjMatrix();
m_lanternIndirectPushConstants.nearZ = nearZ; m_lanternIndirectPushConstants.nearZ = nearZ;
m_lanternIndirectPushConstants.screenX = m_size.width; m_lanternIndirectPushConstants.screenX = m_size.width;
m_lanternIndirectPushConstants.screenY = m_size.height; m_lanternIndirectPushConstants.screenY = m_size.height;
m_lanternIndirectPushConstants.lanternCount = m_lanternCount; m_lanternIndirectPushConstants.lanternCount = int32_t(m_lanternCount);
cmdBuf.pushConstants<LanternIndirectPushConstants>( vkCmdPushConstants(cmdBuf, m_lanternIndirectCompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0,
m_lanternIndirectCompPipelineLayout, sizeof(LanternIndirectPushConstants), &m_lanternIndirectPushConstants);
vk::ShaderStageFlagBits::eCompute, vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipelineLayout, 0, 1,
0, m_lanternIndirectPushConstants); &m_lanternIndirectDescSet, 0, nullptr);
cmdBuf.bindDescriptorSets( vkCmdDispatch(cmdBuf, 1, 1, 1);
vk::PipelineBindPoint::eCompute, m_lanternIndirectCompPipelineLayout, 0, {m_lanternIndirectDescSet}, {});
cmdBuf.dispatch(1, 1, 1);
// Ensure compute results are visible when doing indirect ray trace. // Ensure compute results are visible when doing indirect ray trace.
bufferBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
bufferBarrier.setDstAccessMask(vk::AccessFlagBits::eIndirectCommandRead); bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
cmdBuf.pipelineBarrier( // vkCmdPipelineBarrier(cmdBuf,
vk::PipelineStageFlagBits::eComputeShader, // VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
vk::PipelineStageFlagBits::eDrawIndirect, // VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, //
vk::DependencyFlags(0), // VkDependencyFlags(0), //
{}, {bufferBarrier}, {}); 0, nullptr, 1, &bufferBarrier, 0, nullptr);
// Now move on to the actual ray tracing. // Now move on to the actual ray tracing.
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
```` ````
!!! TIP `eDrawIndirect` !!! TIP `VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`
`vk::PipelineStageFlagBits::eDrawIndirect` (`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`) `VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`
covers the stage that sources indirect paramaters for compute and ray trace covers the stage that sources indirect paramaters for compute and ray trace
indirect commands, not just graphics draw indirect commands. indirect commands, not just graphics draw indirect commands.
@ -542,7 +551,7 @@ they were factored out to common code in `hello_vulkan.h`.
The function for updating the uniform buffer is tweaked to match. The function for updating the uniform buffer is tweaked to match.
```` C ```` C
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
@ -579,40 +588,40 @@ In order to focus on the ray tracing, I omit the code for generating those verte
buffers. The relevent code in `HelloVulkan::createLanternModel` for creating the `BlasInput` is buffers. The relevent code in `HelloVulkan::createLanternModel` for creating the `BlasInput` is
```` C ```` C
// Package vertex and index buffers as BlasInput. // Package vertex and index buffers as BlasInput.
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_lanternVertexBuffer.buffer}); VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternVertexBuffer.buffer);
vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_lanternIndexBuffer.buffer}); VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternIndexBuffer.buffer);
uint32_t maxPrimitiveCount = uint32_t(indices.size() / 3); auto maxPrimitiveCount = uint32_t(indices.size() / 3);
// Describe buffer as packed array of float vec3. // Describe buffer as packed array of float vec3.
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); // vec3 vertex position data. triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.setVertexData(vertexAddress); triangles.vertexData.deviceAddress = vertexAddress;
triangles.setVertexStride(sizeof(nvmath::vec3f)); triangles.vertexStride = sizeof(nvmath::vec3f);
// Describe index data (32-bit unsigned int) // Describe index data (32-bit unsigned int)
triangles.setIndexType(vk::IndexType::eUint32); triangles.indexType = VK_INDEX_TYPE_UINT32;
triangles.setIndexData(indexAddress); triangles.indexData.deviceAddress = indexAddress;
// Indicate identity transform by setting transformData to null device pointer. // Indicate identity transform by setting transformData to null device pointer.
triangles.setTransformData({}); //triangles.transformData = {};
triangles.setMaxVertex(vertices.size()); triangles.maxVertex = uint32_t(vertices.size());
// Identify the above data as containing opaque triangles. // Identify the above data as containing opaque triangles.
vk::AccelerationStructureGeometryKHR asGeom; VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
asGeom.geometry.setTriangles(triangles); asGeom.geometry.triangles = triangles;
// The entire array will be used to build the BLAS. // The entire array will be used to build the BLAS.
vk::AccelerationStructureBuildRangeInfoKHR offset; VkAccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.firstVertex = 0;
offset.setPrimitiveCount(maxPrimitiveCount); offset.primitiveCount = maxPrimitiveCount;
offset.setPrimitiveOffset(0); offset.primitiveOffset = 0;
offset.setTransformOffset(0); offset.transformOffset = 0;
// Our blas is made from only one geometry, but could be made of many geometries // Our blas is made from only one geometry, but could be made of many geometries
m_lanternBlasInput.asGeometry.emplace_back(asGeom); m_lanternBlasInput.asGeometry.emplace_back(asGeom);
m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset); m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset);
```` ````
The principle difference from before is that the vertex array is now a packed array of The principle difference from before is that the vertex array is now a packed array of
@ -647,7 +656,7 @@ void HelloVulkan::createBottomLevelAS()
m_lanternBlasId = allBlas.size(); m_lanternBlasId = allBlas.size();
allBlas.emplace_back(m_lanternBlasInput); allBlas.emplace_back(m_lanternBlasInput);
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
```` ````
@ -696,7 +705,7 @@ void HelloVulkan::createTopLevelAS()
tlas.emplace_back(lanternInstance); tlas.emplace_back(lanternInstance);
} }
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
```` ````
@ -749,25 +758,21 @@ The last task is done in `HelloVulkan::createRtDescriptorSet`
// //
void HelloVulkan::createRtDescriptorSet() void HelloVulkan::createRtDescriptorSet()
{ {
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
using vkDSLB = vk::DescriptorSetLayoutBinding;
// ... // ...
// Lantern buffer (binding = 2) // Lantern buffer (binding = 2)
m_rtDescSetLayoutBind.addBinding( // m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
assert(m_lanternCount > 0); assert(m_lanternCount > 0);
// ... // ...
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// ... // ...
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &lanternBufferInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &lanternBufferInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
```` ````
@ -809,34 +814,36 @@ group after the OBJ hit group, to match the `hitGroupId`s assigned earlier in th
TLAS build. TLAS build.
```` C ```` C
// OBJ Primary Ray Hit Group - Closest Hit + AnyHit (not used)
vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, enum StageIndices
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, {
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; // ...
hg.setClosestHitShader(static_cast<uint32_t>(stages.size())); eClosestHit,
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); eClosestHitLantern,
m_rtShaderGroups.push_back(hg); eShaderGroupCount
};
// ...
// Lantern Primary Ray Hit Group // OBJ Primary Ray Hit Group - Closest Hit
vk::ShaderModule lanternChitSM = stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, // stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
nvh::loadFile("shaders/lantern.rchit.spv", true, paths, true)); stages[eClosestHit] = stage;
vk::RayTracingShaderGroupCreateInfoKHR lanternHg{ // Lantern Primary Ray Hit Group
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; stages[eClosestHitLantern] = stage;
lanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternChitSM, "main"}); // ...
m_rtShaderGroups.push_back(lanternHg);
// closest hit shader
// ... group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
group.generalShader = VK_SHADER_UNUSED_KHR;
m_device.destroy(lanternChitSM); group.closestHitShader = eClosestHit;
m_rtShaderGroups.push_back(group);
group.closestHitShader = eClosestHitLantern;
m_rtShaderGroups.push_back(group);
```` ````
We don't have to modify `HelloVulkan::createRtShaderBindingTable`. Changes to the number of We don't have to modify `HelloVulkan::createRtShaderBindingTable`. Changes to the number of
@ -1102,41 +1109,53 @@ groups for primary rays. Add the following code to `HelloVulkan::createRtPipelin
after loading `raytraceShadow.rmiss.spv`. after loading `raytraceShadow.rmiss.spv`.
```` C ```` C
// Miss shader 2 is invoked when a shadow ray for lantern lighting misses the // Miss shader 2 is invoked when a shadow ray for lantern lighting misses the
// lantern. It shouldn't be invoked, but I include it just in case. // lantern. It shouldn't be invoked, but I include it just in case.
vk::ShaderModule lanternmissSM = nvvk::createShaderModule( stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true));
m_device, nvh::loadFile("shaders/lanternShadow.rmiss.spv", true, paths, true)); stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
stages[eMissLantern] = stage;
```` ````
and add this code for loading the last 2 closest hit shaders after loading and add this code for loading the last 2 closest hit shaders after loading
`lantern.rchit.spv`: `lantern.rchit.spv`:
```` C ```` C
// OBJ Lantern Shadow Ray Hit Group // Lantern Primary Ray Hit Group
vk::ShaderModule lanternShadowObjChitSM = stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, // stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
nvh::loadFile("shaders/lanternShadowObj.rchit.spv", true, paths, true)); stages[eClosestHitLantern] = stage;
// OBJ Lantern Shadow Ray Hit Group
stage.module =
nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
stages[eClosestHitLanternShdObj] = stage;
// ...
// Lantern Shadow Miss
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
group.generalShader = eMissLantern;
m_rtShaderGroups.push_back(group);
// closest hit shader
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
group.generalShader = VK_SHADER_UNUSED_KHR;
group.closestHitShader = eClosestHit;
m_rtShaderGroups.push_back(group);
group.closestHitShader = eClosestHitLantern;
m_rtShaderGroups.push_back(group);
group.closestHitShader = eClosestHitLanternShdObj;
m_rtShaderGroups.push_back(group);
group.closestHitShader = eClosestHitLanternShd;
m_rtShaderGroups.push_back(group);
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowObjHg{
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternShadowObjHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowObjChitSM, "main"});
m_rtShaderGroups.push_back(lanternShadowObjHg);
// Lantern Lantern Shadow Ray Hit Group
vk::ShaderModule lanternShadowLanternChitSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/lanternShadowLantern.rchit.spv", true, paths, true));
vk::RayTracingShaderGroupCreateInfoKHR lanternShadowLanternHg{
vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
lanternShadowLanternHg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, lanternShadowLanternChitSM, "main"});
m_rtShaderGroups.push_back(lanternShadowLanternHg);
```` ````
We need to destroy the added shader modules at the end of the function. We need to destroy the added shader modules at the end of the function.
@ -1386,7 +1405,7 @@ pass. There are minimal changes from before, we just have to
to account for the added shaders. to account for the added shaders.
```` C ```` C
using Stride = vk::StridedDeviceAddressRegionKHR; using Stride = VkStridedDeviceAddressRegionKHR;
std::array<Stride, 4> strideAddresses{ std::array<Stride, 4> strideAddresses{
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss
@ -1394,10 +1413,8 @@ pass. There are minimal changes from before, we just have to
Stride{0u, 0u, 0u}}; // callable Stride{0u, 0u, 0u}}; // callable
// First pass, illuminate scene with global light. // First pass, illuminate scene with global light.
cmdBuf.traceRaysKHR( vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3],
&strideAddresses[0], &strideAddresses[1], // m_size.width, m_size.height, 1);
&strideAddresses[2], &strideAddresses[3], //
m_size.width, m_size.height, 1);
```` ````
After that, we can open a loop for performing all lantern passes. After that, we can open a loop for performing all lantern passes.
@ -1412,25 +1429,23 @@ Because the additive blending in the shader requires read-modify-write operation
we need a barrier between every pass. we need a barrier between every pass.
```` C ```` C
// Barrier to ensure previous pass finished. // Barrier to ensure previous pass finished.
vk::Image offscreenImage{m_offscreenColor.image}; VkImage offscreenImage{m_offscreenColor.image};
vk::ImageSubresourceRange colorRange( VkImageSubresourceRange colorRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS};
vk::ImageAspectFlagBits::eColor, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
); imageBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
vk::ImageMemoryBarrier imageBarrier; imageBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
imageBarrier.setOldLayout(vk::ImageLayout::eGeneral); imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageBarrier.setNewLayout(vk::ImageLayout::eGeneral); imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageBarrier.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); imageBarrier.image = offscreenImage;
imageBarrier.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED); imageBarrier.subresourceRange = colorRange;
imageBarrier.setImage(offscreenImage); imageBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageBarrier.setSubresourceRange(colorRange); imageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imageBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); vkCmdPipelineBarrier(cmdBuf,
imageBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, //
cmdBuf.pipelineBarrier( VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, //
vk::PipelineStageFlagBits::eRayTracingShaderKHR, // VkDependencyFlags(0), //
vk::PipelineStageFlagBits::eRayTracingShaderKHR, // 0, nullptr, 0, nullptr, 1, &imageBarrier);
vk::DependencyFlags(0), //
{}, {}, {imageBarrier});
```` ````
Then, we can pass the number of the lantern pass being performed (`i`), and look Then, we can pass the number of the lantern pass being performed (`i`), and look
@ -1443,17 +1458,18 @@ is the first member of `LanternIndirectEntry`.
```` C ```` C
// Set lantern pass number. // Set lantern pass number.
m_rtPushConstants.lanternPassNumber = i; m_rtPushConstants.lanternPassNumber = i;
cmdBuf.pushConstants<RtPushConstant>(m_rtPipelineLayout, vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
vk::ShaderStageFlagBits::eRaygenKHR VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
| vk::ShaderStageFlagBits::eClosestHitKHR 0, sizeof(RtPushConstant), &m_rtPushConstants);
| vk::ShaderStageFlagBits::eMissKHR,
0, m_rtPushConstants);
VkDeviceAddress indirectDeviceAddress =
nvvk::getBufferDeviceAddress(m_device, m_lanternIndirectBuffer.buffer) + i * sizeof(LanternIndirectEntry);
// Execute lantern pass. // Execute lantern pass.
cmdBuf.traceRaysIndirectKHR( vkCmdTraceRaysIndirectKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], //
&strideAddresses[0], &strideAddresses[1], // &strideAddresses[2], &strideAddresses[3], //
&strideAddresses[2], &strideAddresses[3], // indirectDeviceAddress);
m_device.getBufferAddress({m_lanternIndirectBuffer.buffer}) + i * sizeof(LanternIndirectEntry));
} }
```` ````
@ -1480,10 +1496,10 @@ void HelloVulkan::destroyResources()
// #VKRay // #VKRay
// ... // ...
m_device.destroy(m_lanternIndirectDescPool); vkDestroyDescriptorPool(m_device, m_lanternIndirectDescPool, nullptr);
m_device.destroy(m_lanternIndirectDescSetLayout); vkDestroyDescriptorSetLayout(m_device, m_lanternIndirectDescSetLayout, nullptr);
m_device.destroy(m_lanternIndirectCompPipeline); vkDestroyPipeline(m_device, m_lanternIndirectCompPipeline, nullptr);
m_device.destroy(m_lanternIndirectCompPipelineLayout); vkDestroyPipelineLayout(m_device, m_lanternIndirectCompPipelineLayout, nullptr);
m_alloc.destroy(m_lanternIndirectBuffer); m_alloc.destroy(m_lanternIndirectBuffer);
m_alloc.destroy(m_lanternVertexBuffer); m_alloc.destroy(m_lanternVertexBuffer);
m_alloc.destroy(m_lanternIndexBuffer); m_alloc.destroy(m_lanternIndexBuffer);

View file

@ -3,7 +3,7 @@
Licensed as public domain or BSD 2-clause, whichever is more convenient for you. Licensed as public domain or BSD 2-clause, whichever is more convenient for you.
Originally from https://github.com/aras-p/markdeep-docs-style */ Originally from https://github.com/aras-p/markdeep-docs-style */
body { body {
max-width: 50em; max-width: 80em;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
text-align: left; text-align: left;
/*margin: 1.5em;*/ /*margin: 1.5em;*/

File diff suppressed because it is too large Load diff

View file

@ -7,8 +7,8 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
Project(${PROJNAME}) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")
@ -28,11 +28,12 @@ file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories(${TUTO_KHR_DIR}/common) include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
compile_glsl_directory( compile_glsl_directory(
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
VULKAN_TARGET "vulkan1.2" VULKAN_TARGET "vulkan1.2"
) )

View file

@ -19,9 +19,7 @@
#include <sstream> #include <sstream>
#include <vulkan/vulkan.hpp>
extern std::vector<std::string> defaultSearchPaths;
#define VMA_IMPLEMENTATION #define VMA_IMPLEMENTATION
@ -29,6 +27,7 @@ extern std::vector<std::string> defaultSearchPaths;
#include "obj_loader.h" #include "obj_loader.h"
#include "stb_image.h" #include "stb_image.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
@ -40,6 +39,9 @@ extern std::vector<std::string> defaultSearchPaths;
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices // Holding the camera matrices
struct CameraMatrices struct CameraMatrices
{ {
@ -50,16 +52,14 @@ struct CameraMatrices
nvmath::mat4f projInverse; nvmath::mat4f projInverse;
}; };
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
// //
void HelloVulkan::setup(const vk::Instance& instance, void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily)
{ {
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(instance, device, physicalDevice); m_alloc.init(instance, device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
@ -71,46 +71,46 @@ void HelloVulkan::setup(const vk::Instance& instance,
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Called at each frame to update the camera matrix // Called at each frame to update the camera matrix
// //
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; CameraMatrices hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); hostUBO.view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view); hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay // #VKRay
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.projInverse = nvmath::invert(hostUBO.proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.buffer = deviceUBO;
beforeBarrier.setOffset(0); beforeBarrier.offset = 0;
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); nullptr, 1, &beforeBarrier, 0, nullptr);
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO); vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
vk::BufferMemoryBarrier afterBarrier; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
afterBarrier.setBuffer(deviceUBO); afterBarrier.buffer = deviceUBO;
afterBarrier.setOffset(0); afterBarrier.offset = 0;
afterBarrier.setSize(sizeof hostUBO); afterBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); nullptr, 1, &afterBarrier, 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -118,39 +118,33 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// //
void HelloVulkan::createDescriptorSetLayout() void HelloVulkan::createDescriptorSetLayout()
{ {
using vkDS = vk::DescriptorSetLayoutBinding;
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
auto nbObj = static_cast<uint32_t>(m_objModel.size()); auto nbObj = static_cast<uint32_t>(m_objModel.size());
// Camera matrices (binding = 0) // Camera matrices (binding = 0)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR));
// Materials (binding = 1) // Materials (binding = 1)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj + 1,
vkDS(1, vkDT::eStorageBuffer, nbObj + 1, // Adding Implicit mat too VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Scene description (binding = 2) // Scene description (binding = 2)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
vkDS(2, vkDT::eStorageBuffer, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Textures (binding = 3) // Textures (binding = 3)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR)); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Materials (binding = 4) // Materials (binding = 4)
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Storing vertices (binding = 5) // Storing vertices (binding = 5)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
// Storing indices (binding = 6) // Storing indices (binding = 6)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
// Storing implicit obj (binding = 7) // Storing implicit obj (binding = 7)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
vkDS(7, vkDT::eStorageBuffer, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR
vkSS::eClosestHitKHR | vkSS::eIntersectionKHR | vkSS::eAnyHitKHR)); | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
@ -163,78 +157,76 @@ void HelloVulkan::createDescriptorSetLayout()
// //
void HelloVulkan::updateDescriptorSet() void HelloVulkan::updateDescriptorSet()
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
// All material buffers, 1 buffer per OBJ // All material buffers, 1 buffer per OBJ
std::vector<vk::DescriptorBufferInfo> dbiMat; std::vector<VkDescriptorBufferInfo> dbiMat;
std::vector<vk::DescriptorBufferInfo> dbiMatIdx; std::vector<VkDescriptorBufferInfo> dbiMatIdx;
std::vector<vk::DescriptorBufferInfo> dbiVert; std::vector<VkDescriptorBufferInfo> dbiVert;
std::vector<vk::DescriptorBufferInfo> dbiIdx; std::vector<VkDescriptorBufferInfo> dbiIdx;
for(auto& model : m_objModel) for(auto& m : m_objModel)
{ {
dbiMat.emplace_back(model.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiMatIdx.emplace_back(model.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiVert.emplace_back(model.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiIdx.emplace_back(model.indexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
} }
dbiMat.emplace_back(m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE); // Adding implicit mat dbiMat.push_back({m_implObjects.implMatBuf.buffer, 0, VK_WHOLE_SIZE}); // Adding implicit mat
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 5, dbiVert.data()));
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
// All texture samplers // All texture samplers
std::vector<vk::DescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
vk::DescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiImplDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiImplDesc));
// Writing the information // Writing the information
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating the pipeline layout // Creating the pipeline layout
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
using vkSS = vk::ShaderStageFlagBits; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstants)};
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
sizeof(ObjPushConstants)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
vk::DescriptorSetLayout descSetLayout(m_descSetLayout); createInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setSetLayoutCount(1); createInfo.pSetLayouts = &m_descSetLayout;
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); createInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); createInfo.pPushConstantRanges = &pushConstantRanges;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Creating the Pipeline // Creating the Pipeline
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass()); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass());
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({ gpb.addAttributeDescriptions({
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))}, {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))}, {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))}, {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))}, {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
}); });
m_graphicsPipeline = gpb.createPipeline(); m_graphicsPipeline = gpb.createPipeline();
@ -246,8 +238,6 @@ void HelloVulkan::createGraphicsPipeline()
// //
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
{ {
using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str()); LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -271,18 +261,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size()); model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
// Create the buffers on Device and copy vertices, indices and materials // Create the buffers on Device and copy vertices, indices and materials
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
m_alloc.createBuffer(cmdBuf, loader.m_vertices, | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
model.indexBuffer = model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
m_alloc.createBuffer(cmdBuf, loader.m_indices, model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
@ -298,17 +284,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
m_objInstance.emplace_back(instance); m_objInstance.emplace_back(instance);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating the uniform buffer holding the camera matrices // Creating the uniform buffer holding the camera matrices
// - Buffer is host visible // - Buffer is host visible
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits; m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
using vkMP = vk::MemoryPropertyFlagBits; VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
} }
@ -320,11 +304,10 @@ void HelloVulkan::createUniformBuffer()
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createSceneDescriptionBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits;
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
@ -333,15 +316,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating all textures and samplers // Creating all textures and samplers
// //
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
const std::vector<std::string>& textures)
{ {
using vkIU = vk::ImageUsageFlagBits; VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCreateInfo.maxLod = FLT_MAX;
vk::SamplerCreateInfo samplerCreateInfo{ VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
samplerCreateInfo.setMaxLod(FLT_MAX);
vk::Format format = vk::Format::eR8G8B8A8Srgb;
// If no textures are present, create a dummy one to accommodate the pipeline layout // If no textures are present, create a dummy one to accommodate the pipeline layout
if(textures.empty() && m_textures.empty()) if(textures.empty() && m_textures.empty())
@ -349,18 +332,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
nvvk::Texture texture; nvvk::Texture texture;
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u}; std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
vk::DeviceSize bufferSize = sizeof(color); VkDeviceSize bufferSize = sizeof(color);
auto imgSize = vk::Extent2D(1, 1); auto imgSize = VkExtent2D{1, 1};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the VKImage // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vk::ImageLayout::eShaderReadOnlyOptimal);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
else else
@ -373,8 +355,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -387,16 +368,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
pixels = reinterpret_cast<stbi_uc*>(color.data()); pixels = reinterpret_cast<stbi_uc*>(color.data());
} }
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4; VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
auto imgSize = vk::Extent2D(texWidth, texHeight); auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
{ {
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
vk::ImageViewCreateInfo ivInfo = VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
@ -411,10 +391,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
// //
void HelloVulkan::destroyResources() void HelloVulkan::destroyResources()
{ {
m_device.destroy(m_graphicsPipeline); vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
m_device.destroy(m_pipelineLayout); vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
m_device.destroy(m_descPool); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
m_device.destroy(m_descSetLayout); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_cameraMat);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_sceneDesc);
m_alloc.destroy(m_implObjects.implBuf); m_alloc.destroy(m_implObjects.implBuf);
@ -445,32 +426,31 @@ void HelloVulkan::destroyResources()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Drawing the scene in raster mode // Drawing the scene in raster mode
// //
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
{ {
using vkPBP = vk::PipelineBindPoint; VkDeviceSize offset{0};
using vkSS = vk::ShaderStageFlagBits;
vk::DeviceSize offset{0};
m_debug.beginLabel(cmdBuf, "Rasterize"); m_debug.beginLabel(cmdBuf, "Rasterize");
// Dynamic Viewport // Dynamic Viewport
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); setViewport(cmdBuf);
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
// Drawing all triangles // Drawing all triangles
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(int i = 0; i < m_objInstance.size(); ++i)
{ {
auto& inst = m_objInstance[i]; auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstants.instanceId = i; // Telling which instance is drawn m_pushConstants.instanceId = i; // Telling which instance is drawn
cmdBuf.pushConstants<ObjPushConstants>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
m_pushConstants);
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); sizeof(ObjPushConstants), &m_pushConstants);
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
} }
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }
@ -511,7 +491,7 @@ void HelloVulkan::initRayTracing()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Ray trace the scene // Ray trace the scene
// //
void HelloVulkan::raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor) void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
{ {
updateFrame(); updateFrame();
if(m_pushConstants.frame >= m_maxFrames) if(m_pushConstants.frame >= m_maxFrames)
@ -580,7 +560,7 @@ void HelloVulkan::addImplMaterial(const MaterialObj& mat)
// //
void HelloVulkan::createImplictBuffers() void HelloVulkan::createImplictBuffers()
{ {
using vkBU = vk::BufferUsageFlagBits; using vkBU = VkBufferUsageFlagBits;
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
// Not allowing empty buffers // Not allowing empty buffers
@ -589,11 +569,11 @@ void HelloVulkan::createImplictBuffers()
if(m_implObjects.implMat.empty()) if(m_implObjects.implMat.empty())
m_implObjects.implMat.push_back({}); m_implObjects.implMat.push_back({});
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl, m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl,
vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress); VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
m_implObjects.implMatBuf = | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, vkBU::eStorageBuffer); m_implObjects.implMatBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj"); m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj");

View file

@ -19,7 +19,7 @@
#pragma once #pragma once
#include "nvvk/appbase_vkpp.hpp" #include "nvvk/appbase_vk.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
@ -56,25 +56,21 @@ using Allocator = nvvk::ResourceAllocatorDedicated;
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
Offscreen& offscreen() { return m_offscreen; } Offscreen& offscreen() { return m_offscreen; }
Raytracer& raytracer() { return m_raytrace; } Raytracer& raytracer() { return m_raytrace; }
@ -87,12 +83,12 @@ public:
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
int m_maxFrames{10}; int m_maxFrames{10};
void resetFrame(); void resetFrame();
@ -115,7 +111,7 @@ public:
Raytracer m_raytrace; Raytracer m_raytrace;
void initRayTracing(); void initRayTracing();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
// Implicit // Implicit
ImplInst m_implObjects; ImplInst m_implObjects;

View file

@ -23,21 +23,18 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
#include "imgui/imgui_camera_widget.h"
#include <random> #include <random>
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -47,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -70,18 +68,15 @@ void renderUI(HelloVulkan& helloVk)
if(helloVk.m_pushConstants.lightType < 2) if(helloVk.m_pushConstants.lightType < 2)
{ {
changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, -20.f, 20.f);
-20.f, 20.f);
} }
if(helloVk.m_pushConstants.lightType > 0) if(helloVk.m_pushConstants.lightType > 0)
{ {
changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, -1.f, 1.f);
-1.f, 1.f);
} }
if(helloVk.m_pushConstants.lightType < 2) if(helloVk.m_pushConstants.lightType < 2)
{ {
changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f);
500.f);
} }
if(helloVk.m_pushConstants.lightType == 1) if(helloVk.m_pushConstants.lightType == 1)
{ {
@ -121,8 +116,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -151,7 +145,7 @@ int main(int argc, char** argv)
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -163,18 +157,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -189,11 +181,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -202,14 +193,13 @@ int main(int argc, char** argv)
// Setup Imgui // Setup Imgui
helloVk.initGUI(0); // Using sub-pass 0 helloVk.initGUI(0); // Using sub-pass 0
// Creating scene // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(0.5f)) nvmath::scale_mat4(nvmath::vec3f(0.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f)));
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f)));
std::random_device rd; // Will be used to obtain a seed for the random number engine std::random_device rd; // Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
std::normal_distribution<float> dis(2.0f, 2.0f); std::normal_distribution<float> dis(2.0f, 2.0f);
std::normal_distribution<float> disn(0.5f, 0.2f); std::normal_distribution<float> disn(0.5f, 0.2f);
@ -278,11 +268,12 @@ int main(int argc, char** argv)
// Start the Dear ImGui frame // Start the Dear ImGui frame
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
ImGui::NewFrame();
ImGuiH::Panel::Begin(); ImGuiH::Panel::Begin();
bool changed = false; bool changed = false;
// Edit 3 floats representing a color // Edit 3 floats representing a color
@ -292,11 +283,8 @@ int main(int argc, char** argv)
if(changed) if(changed)
helloVk.resetFrame(); helloVk.resetFrame();
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -305,28 +293,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(offscreen.renderPass()); offscreenRenderPassBeginInfo.renderPass = offscreen.renderPass();
offscreenRenderPassBeginInfo.setFramebuffer(offscreen.frameBuffer()); offscreenRenderPassBeginInfo.framebuffer = offscreen.frameBuffer();
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -335,40 +324,41 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
offscreen.draw(cmdBuf, helloVk.getSize()); offscreen.draw(cmdBuf, helloVk.getSize());
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -32,10 +32,7 @@ extern std::vector<std::string> defaultSearchPaths;
// Post-processing // Post-processing
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void Offscreen::setup(const vk::Device& device, void Offscreen::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
const vk::PhysicalDevice& physicalDevice,
nvvk::ResourceAllocator* allocator,
uint32_t queueFamily)
{ {
m_device = device; m_device = device;
m_alloc = allocator; m_alloc = allocator;
@ -46,14 +43,14 @@ void Offscreen::setup(const vk::Device& device,
void Offscreen::destroy() void Offscreen::destroy()
{ {
m_device.destroy(m_pipeline); vkDestroyPipeline(m_device, m_pipeline, nullptr);
m_device.destroy(m_pipelineLayout); vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
m_device.destroy(m_descPool); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
m_device.destroy(m_dsetLayout); vkDestroyDescriptorSetLayout(m_device, m_dsetLayout, nullptr);
vkDestroyRenderPass(m_device, m_renderPass, nullptr);
vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
m_alloc->destroy(m_colorTexture); m_alloc->destroy(m_colorTexture);
m_alloc->destroy(m_depthTexture); m_alloc->destroy(m_depthTexture);
m_device.destroy(m_renderPass);
m_device.destroy(m_framebuffer);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -66,30 +63,28 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
// Creating the color image // Creating the color image
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(size, m_colorFormat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(
vk::ImageUsageFlagBits::eColorAttachment size, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eSampled
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc->createImage(colorCreateInfo); nvvk::Image image = m_alloc->createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_colorTexture = m_alloc->createTexture(image, ivInfo, vk::SamplerCreateInfo());
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
m_colorTexture = m_alloc->createTexture(image, ivInfo, sampler);
m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
} }
// Creating the depth buffer // Creating the depth buffer
{ {
auto depthCreateInfo = auto depthCreateInfo = nvvk::makeImage2DCreateInfo(size, m_depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
nvvk::makeImage2DCreateInfo(size, m_depthFormat, nvvk::Image image = m_alloc->createImage(depthCreateInfo);
vk::ImageUsageFlagBits::eDepthStencilAttachment);
nvvk::Image image = m_alloc->createImage(depthCreateInfo);
vk::ImageViewCreateInfo depthStencilView; VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
depthStencilView.setViewType(vk::ImageViewType::e2D); depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.setFormat(m_depthFormat); depthStencilView.format = m_depthFormat;
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
depthStencilView.setImage(image.image); depthStencilView.image = image.image;
m_depthTexture = m_alloc->createTexture(image, depthStencilView); m_depthTexture = m_alloc->createTexture(image, depthStencilView);
} }
@ -98,11 +93,9 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
{ {
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
auto cmdBuf = genCmdBuf.createCommandBuffer(); auto cmdBuf = genCmdBuf.createCommandBuffer();
nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
vk::ImageLayout::eGeneral); nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, VK_IMAGE_LAYOUT_UNDEFINED,
nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, vk::ImageLayout::eUndefined, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
vk::ImageLayout::eDepthStencilAttachmentOptimal,
vk::ImageAspectFlagBits::eDepth);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
} }
@ -111,50 +104,46 @@ void Offscreen::createFramebuffer(VkExtent2D& size)
if(!m_renderPass) if(!m_renderPass)
{ {
m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true, m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true,
vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral); VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
} }
// Creating the frame buffer for offscreen // Creating the frame buffer for offscreen
std::vector<vk::ImageView> attachments = {m_colorTexture.descriptor.imageView, std::vector<VkImageView> attachments = {m_colorTexture.descriptor.imageView, m_depthTexture.descriptor.imageView};
m_depthTexture.descriptor.imageView};
m_device.destroy(m_framebuffer); vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
vk::FramebufferCreateInfo info; VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
info.setRenderPass(m_renderPass); info.renderPass = m_renderPass;
info.setAttachmentCount(2); info.attachmentCount = 2;
info.setPAttachments(attachments.data()); info.pAttachments = attachments.data();
info.setWidth(size.width); info.width = size.width;
info.setHeight(size.height); info.height = size.height;
info.setLayers(1); info.layers = 1;
m_framebuffer = m_device.createFramebuffer(info); vkCreateFramebuffer(m_device, &info, nullptr, &m_framebuffer);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more // The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
// The incoming render pass, is in which rendering pass it will be displayed (framebuffer) // The incoming render pass, is in which rendering pass it will be displayed (framebuffer)
// //
void Offscreen::createPipeline(vk::RenderPass& renderPass) void Offscreen::createPipeline(VkRenderPass& renderPass)
{ {
// Push constants in the fragment shader // Push constants in the fragment shader
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
// Creating the pipeline layout // Creating the pipeline layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
pipelineLayoutCreateInfo.setSetLayoutCount(1); pipelineLayoutCreateInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setPSetLayouts(&m_dsetLayout); pipelineLayoutCreateInfo.pSetLayouts = &m_dsetLayout;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRanges;
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_pipelineLayout);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass); nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass);
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
true), pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
vk::ShaderStageFlagBits::eVertex); pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), m_pipeline = pipelineGenerator.createPipeline();
vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_pipeline = pipelineGenerator.createPipeline();
m_debug.setObjectName(m_pipeline, "post"); m_debug.setObjectName(m_pipeline, "post");
} }
@ -164,11 +153,7 @@ void Offscreen::createPipeline(vk::RenderPass& renderPass)
// //
void Offscreen::createDescriptor() void Offscreen::createDescriptor()
{ {
using vkDS = vk::DescriptorSetLayoutBinding; m_dsetLayoutBinding.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
m_dsetLayoutBinding.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device); m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device);
m_descPool = m_dsetLayoutBinding.createPool(m_device); m_descPool = m_dsetLayoutBinding.createPool(m_device);
m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout); m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout);
@ -179,26 +164,28 @@ void Offscreen::createDescriptor()
// //
void Offscreen::updateDescriptorSet() void Offscreen::updateDescriptorSet()
{ {
vk::WriteDescriptorSet writeDescriptorSets = VkWriteDescriptorSet writeDescriptorSets = m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor);
m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor); vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Draw a full screen quad with the attached image // Draw a full screen quad with the attached image
// //
void Offscreen::draw(vk::CommandBuffer cmdBuf, VkExtent2D& size) void Offscreen::draw(VkCommandBuffer cmdBuf, VkExtent2D& size)
{ {
m_debug.beginLabel(cmdBuf, "Post"); m_debug.beginLabel(cmdBuf, "Post");
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)size.width, (float)size.height, 0, 1)}); VkViewport viewport{0, 0, (float)size.width, (float)size.height, 0, 1};
cmdBuf.setScissor(0, {{{0, 0}, {size.width, size.height}}}); vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
VkRect2D scissor{{0, 0}, {size.width, size.height}};
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
auto aspectRatio = static_cast<float>(size.width) / static_cast<float>(size.height); auto aspectRatio = static_cast<float>(size.width) / static_cast<float>(size.height);
cmdBuf.pushConstants<float>(m_pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, aspectRatio); vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_pipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_pipelineLayout, 0, m_dset, {}); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_dset, 0, nullptr);
cmdBuf.draw(3, 1, 0, 0); vkCmdDraw(cmdBuf, 3, 1, 0, 0);
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -18,8 +18,6 @@
*/ */
#include <vulkan/vulkan.hpp>
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp" #include "nvvk/resourceallocator_vk.hpp"
@ -33,40 +31,36 @@
class Offscreen class Offscreen
{ {
public: public:
void setup(const vk::Device& device, void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
const vk::PhysicalDevice& physicalDevice,
nvvk::ResourceAllocator* allocator,
uint32_t queueFamily);
void destroy(); void destroy();
void createFramebuffer(VkExtent2D& size); void createFramebuffer(VkExtent2D& size);
void createPipeline(vk::RenderPass& renderPass); void createPipeline(VkRenderPass& renderPass);
void createDescriptor(); void createDescriptor();
void updateDescriptorSet(); void updateDescriptorSet();
void draw(vk::CommandBuffer cmdBuf, VkExtent2D& size); void draw(VkCommandBuffer cmdBuf, VkExtent2D& size);
const vk::RenderPass& renderPass() { return m_renderPass; } const VkRenderPass& renderPass() { return m_renderPass; }
const vk::Framebuffer& frameBuffer() { return m_framebuffer; } const VkFramebuffer& frameBuffer() { return m_framebuffer; }
const nvvk::Texture& colorTexture() { return m_colorTexture; } const nvvk::Texture& colorTexture() { return m_colorTexture; }
private: private:
nvvk::DescriptorSetBindings m_dsetLayoutBinding; nvvk::DescriptorSetBindings m_dsetLayoutBinding;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_dsetLayout; VkDescriptorSetLayout m_dsetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_dset; VkDescriptorSet m_dset{VK_NULL_HANDLE};
vk::Pipeline m_pipeline; VkPipeline m_pipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_renderPass; VkRenderPass m_renderPass{VK_NULL_HANDLE};
vk::Framebuffer m_framebuffer; VkFramebuffer m_framebuffer{VK_NULL_HANDLE};
nvvk::Texture m_colorTexture; nvvk::Texture m_colorTexture;
vk::Format m_colorFormat{vk::Format::eR32G32B32A32Sfloat}; VkFormat m_colorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
nvvk::Texture m_depthTexture; nvvk::Texture m_depthTexture;
vk::Format m_depthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_depthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
nvvk::ResourceAllocator* m_alloc{ nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
nullptr}; // Allocator for buffer, images, acceleration structures VkDevice m_device;
vk::Device m_device; int m_graphicsQueueIndex{0};
int m_graphicsQueueIndex{0}; nvvk::DebugUtil m_debug; // Utility to name objects
nvvk::DebugUtil m_debug; // Utility to name objects
}; };

View file

@ -25,14 +25,12 @@
#include "nvh/alignment.hpp" #include "nvh/alignment.hpp"
#include "nvvk/shaders_vk.hpp" #include "nvvk/shaders_vk.hpp"
#include "obj_loader.h" #include "obj_loader.h"
#include "nvvk/buffers_vk.hpp"
extern std::vector<std::string> defaultSearchPaths; extern std::vector<std::string> defaultSearchPaths;
void Raytracer::setup(const vk::Device& device, void Raytracer::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
const vk::PhysicalDevice& physicalDevice,
nvvk::ResourceAllocator* allocator,
uint32_t queueFamily)
{ {
m_device = device; m_device = device;
m_physicalDevice = physicalDevice; m_physicalDevice = physicalDevice;
@ -40,12 +38,11 @@ void Raytracer::setup(const vk::Device& device,
m_graphicsQueueIndex = queueFamily; m_graphicsQueueIndex = queueFamily;
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, prop2.pNext = &m_rtProperties;
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>(); vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties); m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties);
m_debug.setup(device); m_debug.setup(device);
} }
@ -55,10 +52,10 @@ void Raytracer::destroy()
{ {
m_sbtWrapper.destroy(); m_sbtWrapper.destroy();
m_rtBuilder.destroy(); m_rtBuilder.destroy();
m_device.destroy(m_rtDescPool); vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr);
m_device.destroy(m_rtDescSetLayout); vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr);
m_device.destroy(m_rtPipeline); vkDestroyPipeline(m_device, m_rtPipeline, nullptr);
m_device.destroy(m_rtPipelineLayout); vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr);
m_alloc->destroy(m_rtSBTBuffer); m_alloc->destroy(m_rtSBTBuffer);
} }
@ -68,30 +65,30 @@ void Raytracer::destroy()
auto Raytracer::objectToVkGeometryKHR(const ObjModel& model) auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
{ {
// Building part // Building part
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat); triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
triangles.setVertexData(vertexAddress); triangles.vertexData.deviceAddress = vertexAddress;
triangles.setVertexStride(sizeof(VertexObj)); triangles.vertexStride = sizeof(VertexObj);
triangles.setIndexType(vk::IndexType::eUint32); triangles.indexType = VK_INDEX_TYPE_UINT32;
triangles.setIndexData(indexAddress); triangles.indexData.deviceAddress = indexAddress;
triangles.setTransformData({}); triangles.transformData = {};
triangles.setMaxVertex(model.nbVertices); triangles.maxVertex = model.nbVertices;
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
vk::AccelerationStructureGeometryKHR asGeom; VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
asGeom.geometry.setTriangles(triangles); asGeom.geometry.triangles = triangles;
vk::AccelerationStructureBuildRangeInfoKHR offset; VkAccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.firstVertex = 0;
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles offset.primitiveCount = model.nbIndices / 3; // Nb triangles
offset.setPrimitiveOffset(0); offset.primitiveOffset = 0;
offset.setTransformOffset(0); offset.transformOffset = 0;
nvvk::RaytracingBuilderKHR::BlasInput input; nvvk::RaytracingBuilderKHR::BlasInput input;
input.asGeometry.emplace_back(asGeom); input.asGeometry.emplace_back(asGeom);
@ -105,11 +102,11 @@ auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
// //
auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj) auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
{ {
vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer}); VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, implicitObj.implBuf.buffer);
vk::AccelerationStructureGeometryAabbsDataKHR aabbs; VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR};
aabbs.setData(dataAddress); aabbs.data.deviceAddress = dataAddress;
aabbs.setStride(sizeof(ObjImplicit)); aabbs.stride = sizeof(ObjImplicit);
// Setting up the build info of the acceleration // Setting up the build info of the acceleration
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
@ -118,11 +115,11 @@ auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
asGeom.geometry.aabbs = aabbs; asGeom.geometry.aabbs = aabbs;
vk::AccelerationStructureBuildRangeInfoKHR offset; VkAccelerationStructureBuildRangeInfoKHR offset;
offset.setFirstVertex(0); offset.firstVertex = 0;
offset.setPrimitiveCount(static_cast<uint32_t>(implicitObj.objImpl.size())); // Nb aabb offset.primitiveCount = static_cast<uint32_t>(implicitObj.objImpl.size()); // Nb aabb
offset.setPrimitiveOffset(0); offset.primitiveOffset = 0;
offset.setTransformOffset(0); offset.transformOffset = 0;
nvvk::RaytracingBuilderKHR::BlasInput input; nvvk::RaytracingBuilderKHR::BlasInput input;
input.asGeometry.emplace_back(asGeom); input.asGeometry.emplace_back(asGeom);
@ -153,8 +150,8 @@ void Raytracer::createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& imp
} }
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowCompaction); | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
} }
void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj) void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj)
@ -176,46 +173,48 @@ void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst&
if(!implicitObj.objImpl.empty()) if(!implicitObj.objImpl.empty())
{ {
nvvk::RaytracingBuilderKHR::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = implicitObj.transform; // Position of the instance rayInst.transform = implicitObj.transform; // Position of the instance
rayInst.instanceCustomId = rayInst.instanceCustomId = static_cast<uint32_t>(implicitObj.blasId); // Same for material index
static_cast<uint32_t>(implicitObj.blasId); // Same for material index rayInst.blasId = static_cast<uint32_t>(implicitObj.blasId);
rayInst.blasId = static_cast<uint32_t>(implicitObj.blasId); rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one)
rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one) rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// This descriptor set holds the Acceleration structure and the output image // This descriptor set holds the Acceleration structure and the output image
// //
void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage) void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
{ {
using vkDT = vk::DescriptorType; using vkDSLB = VkDescriptorSetLayoutBinding;
using vkSS = vk::ShaderStageFlagBits;
using vkDSLB = vk::DescriptorSetLayoutBinding;
m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1, m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
m_rtDescSetLayoutBind.addBinding( m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0];
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; allocateInfo.descriptorPool = m_rtDescPool;
descASInfo.setAccelerationStructureCount(1); allocateInfo.descriptorSetCount = 1;
descASInfo.setPAccelerationStructures(&tlas); allocateInfo.pSetLayouts = &m_rtDescSetLayout;
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral}; vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
std::vector<vk::WriteDescriptorSet> writes; VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
descASInfo.accelerationStructureCount = 1;
descASInfo.pAccelerationStructures = &tlas;
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo));
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -223,169 +222,188 @@ void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage)
// Writes the output image to the descriptor set // Writes the output image to the descriptor set
// - Required when changing resolution // - Required when changing resolution
// //
void Raytracer::updateRtDescriptorSet(const vk::ImageView& outputImage) void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage)
{ {
using vkDT = vk::DescriptorType; VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo);
// (1) Output buffer vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral};
vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo};
m_device.updateDescriptorSets(wds, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Pipeline for the ray tracer: all shaders, raygen, chit, miss // Pipeline for the ray tracer: all shaders, raygen, chit, miss
// //
void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout) void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout)
{ {
vk::ShaderModule raygenSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
vk::ShaderModule missSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
// The second miss shader is invoked when a shadow ray misses the geometry. It enum StageIndices
// simply indicates that no occlusion has been found {
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( eRaygen,
m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); eMiss,
eMiss2,
eClosestHit,
eAnyHit,
eClosestHit1,
eAnyHit1,
eIntersect,
eCall0,
eCall1,
eCall2,
eShaderGroupCount
};
// All stages
std::array<VkPipelineShaderStageCreateInfo, eShaderGroupCount> stages{};
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
stage.pName = "main"; // All the same entry point
// Raygen
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
stages[eRaygen] = stage;
// Miss
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
stages[eMiss] = stage;
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
stage.module =
nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
stages[eMiss2] = stage;
// Hit Group - Closest Hit
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
stages[eClosestHit] = stage;
// Hit Group - Closest Hit
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
stages[eAnyHit] = stage;
// Hit Group - 1
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
stages[eClosestHit1] = stage;
// Hit
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
stages[eAnyHit1] = stage;
// Hit
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
stages[eIntersect] = stage;
// Call0
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
stages[eCall0] = stage;
// Call1
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
stages[eCall1] = stage;
// Call2
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
stages[eCall2] = stage;
std::vector<vk::PipelineShaderStageCreateInfo> stages; // Shader groups
VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
group.anyHitShader = VK_SHADER_UNUSED_KHR;
group.closestHitShader = VK_SHADER_UNUSED_KHR;
group.generalShader = VK_SHADER_UNUSED_KHR;
group.intersectionShader = VK_SHADER_UNUSED_KHR;
// Raygen // Raygen
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral, group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, group.generalShader = eRaygen;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; m_rtShaderGroups.push_back(group);
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
m_rtShaderGroups.push_back(rg); // 0
// Miss // Miss
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral, group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, group.generalShader = eMiss;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; m_rtShaderGroups.push_back(group);
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
m_rtShaderGroups.push_back(mg); // 1
// Shadow Miss // Shadow Miss
mg.setGeneralShader(static_cast<uint32_t>(stages.size())); group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"}); group.generalShader = eMiss2;
m_rtShaderGroups.push_back(mg); // 2 m_rtShaderGroups.push_back(group);
// Hit Group0 - Closest Hit + AnyHit // closest hit shader
vk::ShaderModule chitSM = nvvk::createShaderModule( group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); group.generalShader = VK_SHADER_UNUSED_KHR;
vk::ShaderModule ahitSM = nvvk::createShaderModule( group.closestHitShader = eClosestHit;
m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true)); group.anyHitShader = eAnyHit;
m_rtShaderGroups.push_back(group);
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, // closest hit shader
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; group.generalShader = VK_SHADER_UNUSED_KHR;
hg.setClosestHitShader(static_cast<uint32_t>(stages.size())); group.closestHitShader = eClosestHit1;
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); group.anyHitShader = eAnyHit1;
hg.setAnyHitShader(static_cast<uint32_t>(stages.size())); group.intersectionShader = eIntersect;
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); m_rtShaderGroups.push_back(group);
m_rtShaderGroups.push_back(hg); // 3
// Hit Group1 - Closest Hit + Intersection (procedural)
vk::ShaderModule chit2SM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
vk::ShaderModule ahit2SM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
vk::ShaderModule rintSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
{
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit2SM, "main"});
hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
m_rtShaderGroups.push_back(hg); // 4
}
// Callable shaders // Callable shaders
vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral, group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, group.closestHitShader = VK_SHADER_UNUSED_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; group.anyHitShader = VK_SHADER_UNUSED_KHR;
group.intersectionShader = VK_SHADER_UNUSED_KHR;
group.generalShader = eCall0;
m_rtShaderGroups.push_back(group);
group.generalShader = eCall1;
m_rtShaderGroups.push_back(group);
group.generalShader = eCall2;
m_rtShaderGroups.push_back(group);
vk::ShaderModule call0 = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
vk::ShaderModule call1 = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
vk::ShaderModule call2 = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
m_rtShaderGroups.push_back(callGroup); // 5
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
m_rtShaderGroups.push_back(callGroup); // 6
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
m_rtShaderGroups.push_back(callGroup); //7
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
// Push constant: we want to be able to update constants used by the shaders // Push constant: we want to be able to update constants used by the shaders
vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
| vk::ShaderStageFlagBits::eClosestHitKHR | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
| vk::ShaderStageFlagBits::eMissKHR 0, sizeof(RtPushConstants)};
| vk::ShaderStageFlagBits::eCallableKHR,
0, sizeof(RtPushConstants)};
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant); pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant;
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
std::vector<vk::DescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout}; std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
pipelineLayoutCreateInfo.setSetLayoutCount(static_cast<uint32_t>(rtDescSetLayouts.size())); pipelineLayoutCreateInfo.setLayoutCount = static_cast<uint32_t>(rtDescSetLayouts.size());
pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data()); pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data();
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Assemble the shader stages and recursion depth info into the ray tracing pipeline // Assemble the shader stages and recursion depth info into the ray tracing pipeline
vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo; VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
rayPipelineInfo.setStageCount(static_cast<uint32_t>(stages.size())); // Stages are shaders rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size()); // Stages are shaders
rayPipelineInfo.setPStages(stages.data()); rayPipelineInfo.pStages = stages.data();
rayPipelineInfo.setGroupCount(static_cast<uint32_t>( rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect]) rayPipelineInfo.pGroups = m_rtShaderGroups.data();
rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
rayPipelineInfo.setLayout(m_rtPipelineLayout); // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
// in the ray generation to avoid deep recursion.
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
rayPipelineInfo.layout = m_rtPipelineLayout;
m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value; vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
m_device.destroy(raygenSM);
m_device.destroy(missSM); for(auto& s : stages)
m_device.destroy(shadowmissSM); vkDestroyShaderModule(m_device, s.module, nullptr);
m_device.destroy(chitSM);
m_device.destroy(ahitSM);
m_device.destroy(chit2SM);
m_device.destroy(ahit2SM);
m_device.destroy(rintSM);
m_device.destroy(call0);
m_device.destroy(call1);
m_device.destroy(call2);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Ray Tracing the scene // Ray Tracing the scene
// //
void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf, void Raytracer::raytrace(const VkCommandBuffer& cmdBuf,
const nvmath::vec4f& clearColor, const nvmath::vec4f& clearColor,
vk::DescriptorSet& sceneDescSet, VkDescriptorSet& sceneDescSet,
vk::Extent2D& size, VkExtent2D& size,
ObjPushConstants& sceneConstants) ObjPushConstants& sceneConstants)
{ {
m_debug.beginLabel(cmdBuf, "Ray trace"); m_debug.beginLabel(cmdBuf, "Ray trace");
// Initializing push constant values // Initializing push constant values
@ -398,19 +416,19 @@ void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
m_rtPushConstants.lightType = sceneConstants.lightType; m_rtPushConstants.lightType = sceneConstants.lightType;
m_rtPushConstants.frame = sceneConstants.frame; m_rtPushConstants.frame = sceneConstants.frame;
cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0, std::vector<VkDescriptorSet> descSets{m_rtDescSet, sceneDescSet};
{m_rtDescSet, sceneDescSet}, {}); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
cmdBuf.pushConstants<RtPushConstants>(m_rtPipelineLayout, vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0,
vk::ShaderStageFlagBits::eRaygenKHR (uint32_t)descSets.size(), descSets.data(), 0, nullptr);
| vk::ShaderStageFlagBits::eClosestHitKHR vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
| vk::ShaderStageFlagBits::eMissKHR VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR
| vk::ShaderStageFlagBits::eCallableKHR, | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
0, m_rtPushConstants); 0, sizeof(RtPushConstants), &m_rtPushConstants);
auto regions = m_sbtWrapper.getRegions(); auto& regions = m_sbtWrapper.getRegions();
cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], size.width, size.height, 1); vkCmdTraceRaysKHR(cmdBuf, &regions[0], &regions[1], &regions[2], &regions[3], size.width, size.height, 1);
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -18,8 +18,6 @@
*/ */
#include <vulkan/vulkan.hpp>
#include "nvmath/nvmath.h" #include "nvmath/nvmath.h"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -29,44 +27,40 @@
class Raytracer class Raytracer
{ {
public: public:
void setup(const vk::Device& device, void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
const vk::PhysicalDevice& physicalDevice,
nvvk::ResourceAllocator* allocator,
uint32_t queueFamily);
void destroy(); void destroy();
auto objectToVkGeometryKHR(const ObjModel& model); auto objectToVkGeometryKHR(const ObjModel& model);
auto implicitToVkGeometryKHR(const ImplInst& implicitObj); auto implicitToVkGeometryKHR(const ImplInst& implicitObj);
void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj); void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj);
void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj); void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj);
void createRtDescriptorSet(const vk::ImageView& outputImage); void createRtDescriptorSet(const VkImageView& outputImage);
void updateRtDescriptorSet(const vk::ImageView& outputImage); void updateRtDescriptorSet(const VkImageView& outputImage);
void createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout); void createRtPipeline(VkDescriptorSetLayout& sceneDescLayout);
void raytrace(const vk::CommandBuffer& cmdBuf, void raytrace(const VkCommandBuffer& cmdBuf,
const nvmath::vec4f& clearColor, const nvmath::vec4f& clearColor,
vk::DescriptorSet& sceneDescSet, VkDescriptorSet& sceneDescSet,
vk::Extent2D& size, VkExtent2D& size,
ObjPushConstants& sceneConstants); ObjPushConstants& sceneConstants);
private: private:
nvvk::ResourceAllocator* m_alloc{ nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
nullptr}; // Allocator for buffer, images, acceleration structures VkPhysicalDevice m_physicalDevice;
vk::PhysicalDevice m_physicalDevice; VkDevice m_device;
vk::Device m_device; int m_graphicsQueueIndex{0};
int m_graphicsQueueIndex{0}; nvvk::DebugUtil m_debug; // Utility to name objects
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::SBTWrapper m_sbtWrapper;
nvvk::SBTWrapper m_sbtWrapper;
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstants struct RtPushConstants
{ {

View file

@ -19,23 +19,24 @@
#include <sstream> #include <sstream>
#include <vulkan/vulkan.hpp>
extern std::vector<std::string> defaultSearchPaths;
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "obj_loader.h" #include "obj_loader.h"
#include "stb_image.h" #include "stb_image.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "nvh/alignment.hpp"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/images_vk.hpp" #include "nvvk/images_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
#include "nvvk/shaders_vk.hpp"
extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices // Holding the camera matrices
@ -50,13 +51,10 @@ struct CameraMatrices
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
// //
void HelloVulkan::setup(const vk::Instance& instance, void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily)
{ {
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(instance, device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
@ -64,43 +62,44 @@ void HelloVulkan::setup(const vk::Instance& instance,
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Called at each frame to update the camera matrix // Called at each frame to update the camera matrix
// //
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; CameraMatrices hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); hostUBO.view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view); hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = vk::PipelineStageFlagBits::eVertexShader; auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.buffer = deviceUBO;
beforeBarrier.setOffset(0); beforeBarrier.offset = 0;
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); nullptr, 1, &beforeBarrier, 0, nullptr);
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO); vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
vk::BufferMemoryBarrier afterBarrier; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
afterBarrier.setBuffer(deviceUBO); afterBarrier.buffer = deviceUBO;
afterBarrier.setOffset(0); afterBarrier.offset = 0;
afterBarrier.setSize(sizeof hostUBO); afterBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); nullptr, 1, &afterBarrier, 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -108,25 +107,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// //
void HelloVulkan::createDescriptorSetLayout() void HelloVulkan::createDescriptorSetLayout()
{ {
using vkDS = vk::DescriptorSetLayoutBinding;
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
auto nbObj = static_cast<uint32_t>(m_objModel.size()); auto nbObj = static_cast<uint32_t>(m_objModel.size());
// Camera matrices (binding = 0) // Camera matrices (binding = 0)
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex)); m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
// Materials (binding = 1) // Materials (binding = 1)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment));
// Scene description (binding = 2) // Scene description (binding = 2)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment));
// Textures (binding = 3) // Textures (binding = 3)
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment)); m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
// Materials (binding = 4) // Materials (binding = 4)
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment)); m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
@ -139,27 +132,27 @@ void HelloVulkan::createDescriptorSetLayout()
// //
void HelloVulkan::updateDescriptorSet() void HelloVulkan::updateDescriptorSet()
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
// All material buffers, 1 buffer per OBJ // All material buffers, 1 buffer per OBJ
std::vector<vk::DescriptorBufferInfo> dbiMat; std::vector<VkDescriptorBufferInfo> dbiMat;
std::vector<vk::DescriptorBufferInfo> dbiMatIdx; std::vector<VkDescriptorBufferInfo> dbiMatIdx;
for(auto &m : m_objModel) for(auto& m : m_objModel)
{ {
dbiMat.emplace_back(m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiMatIdx.emplace_back(m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
// All texture samplers // All texture samplers
std::vector<vk::DescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
@ -167,7 +160,7 @@ void HelloVulkan::updateDescriptorSet()
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
// Writing the information // Writing the information
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
@ -176,32 +169,29 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
using vkSS = vk::ShaderStageFlagBits; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
sizeof(ObjPushConstant)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
vk::DescriptorSetLayout descSetLayout(m_descSetLayout); createInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setSetLayoutCount(1); createInfo.pSetLayouts = &m_descSetLayout;
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); createInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); createInfo.pPushConstantRanges = &pushConstantRanges;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Creating the Pipeline // Creating the Pipeline
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({ gpb.addAttributeDescriptions({
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))}, {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))}, {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))}, {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))}, {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
}); });
m_graphicsPipeline = gpb.createPipeline(); m_graphicsPipeline = gpb.createPipeline();
@ -213,8 +203,6 @@ void HelloVulkan::createGraphicsPipeline()
// //
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
{ {
using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str()); LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -239,11 +227,11 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// Create the buffers on Device and copy vertices, indices and materials // Create the buffers on Device and copy vertices, indices and materials
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, vkBU::eVertexBuffer); model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, vkBU::eIndexBuffer); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer); model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer); model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
// Creates all textures found // Creates all textures found
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
@ -266,11 +254,8 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits; m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
using vkMP = vk::MemoryPropertyFlagBits; VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
} }
@ -282,11 +267,10 @@ void HelloVulkan::createUniformBuffer()
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createSceneDescriptionBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits;
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
@ -295,15 +279,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating all textures and samplers // Creating all textures and samplers
// //
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
const std::vector<std::string>& textures)
{ {
using vkIU = vk::ImageUsageFlagBits; VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCreateInfo.maxLod = FLT_MAX;
vk::SamplerCreateInfo samplerCreateInfo{ VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
samplerCreateInfo.setMaxLod(FLT_MAX);
vk::Format format = vk::Format::eR8G8B8A8Srgb;
// If no textures are present, create a dummy one to accommodate the pipeline layout // If no textures are present, create a dummy one to accommodate the pipeline layout
if(textures.empty() && m_textures.empty()) if(textures.empty() && m_textures.empty())
@ -311,18 +295,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
nvvk::Texture texture; nvvk::Texture texture;
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u}; std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
vk::DeviceSize bufferSize = sizeof(color); VkDeviceSize bufferSize = sizeof(color);
auto imgSize = vk::Extent2D(1, 1); auto imgSize = VkExtent2D{1, 1};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the dummy texture // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vk::ImageLayout::eShaderReadOnlyOptimal);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
else else
@ -335,8 +318,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -349,16 +331,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
pixels = reinterpret_cast<stbi_uc*>(color.data()); pixels = reinterpret_cast<stbi_uc*>(color.data());
} }
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4; VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
auto imgSize = vk::Extent2D(texWidth, texHeight); auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
{ {
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
vk::ImageViewCreateInfo ivInfo = VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
@ -373,10 +354,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
// //
void HelloVulkan::destroyResources() void HelloVulkan::destroyResources()
{ {
m_device.destroy(m_graphicsPipeline); vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
m_device.destroy(m_pipelineLayout); vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
m_device.destroy(m_descPool); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
m_device.destroy(m_descSetLayout); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_cameraMat);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_sceneDesc);
@ -394,14 +376,14 @@ void HelloVulkan::destroyResources()
} }
//#Post //#Post
m_device.destroy(m_postPipeline);
m_device.destroy(m_postPipelineLayout);
m_device.destroy(m_postDescPool);
m_device.destroy(m_postDescSetLayout);
m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenColor);
m_alloc.destroy(m_offscreenDepth); m_alloc.destroy(m_offscreenDepth);
m_device.destroy(m_offscreenRenderPass); vkDestroyPipeline(m_device, m_postPipeline, nullptr);
m_device.destroy(m_offscreenFramebuffer); vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
m_alloc.deinit(); m_alloc.deinit();
} }
@ -409,33 +391,31 @@ void HelloVulkan::destroyResources()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Drawing the scene in raster mode // Drawing the scene in raster mode
// //
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
{ {
using vkPBP = vk::PipelineBindPoint; VkDeviceSize offset{0};
using vkSS = vk::ShaderStageFlagBits;
vk::DeviceSize offset{0};
m_debug.beginLabel(cmdBuf, "Rasterize"); m_debug.beginLabel(cmdBuf, "Rasterize");
// Dynamic Viewport // Dynamic Viewport
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); setViewport(cmdBuf);
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
// Drawing all triangles // Drawing all triangles
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(int i = 0; i < m_objInstance.size(); ++i)
{ {
auto& inst = m_objInstance[i]; auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pushConstant.instanceId = i; // Telling which instance is drawn
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
m_pushConstant);
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); sizeof(ObjPushConstant), &m_pushConstant);
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
} }
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }
@ -466,29 +446,28 @@ void HelloVulkan::createOffscreenRender()
// Creating the color image // Creating the color image
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
vk::ImageUsageFlagBits::eColorAttachment VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
| vk::ImageUsageFlagBits::eSampled | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo); nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
} }
// Creating the depth buffer // Creating the depth buffer
auto depthCreateInfo = auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
vk::ImageUsageFlagBits::eDepthStencilAttachment);
{ {
nvvk::Image image = m_alloc.createImage(depthCreateInfo); nvvk::Image image = m_alloc.createImage(depthCreateInfo);
vk::ImageViewCreateInfo depthStencilView;
depthStencilView.setViewType(vk::ImageViewType::e2D); VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
depthStencilView.setFormat(m_offscreenDepthFormat); depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); depthStencilView.format = m_offscreenDepthFormat;
depthStencilView.setImage(image.image); depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
depthStencilView.image = image.image;
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
} }
@ -497,11 +476,9 @@ void HelloVulkan::createOffscreenRender()
{ {
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
auto cmdBuf = genCmdBuf.createCommandBuffer(); auto cmdBuf = genCmdBuf.createCommandBuffer();
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
vk::ImageLayout::eGeneral); nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
vk::ImageLayout::eDepthStencilAttachmentOptimal,
vk::ImageAspectFlagBits::eDepth);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
} }
@ -509,25 +486,23 @@ void HelloVulkan::createOffscreenRender()
// Creating a renderpass for the offscreen // Creating a renderpass for the offscreen
if(!m_offscreenRenderPass) if(!m_offscreenRenderPass)
{ {
m_offscreenRenderPass = m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
} }
// Creating the frame buffer for offscreen // Creating the frame buffer for offscreen
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView, std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
m_offscreenDepth.descriptor.imageView};
m_device.destroy(m_offscreenFramebuffer); vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
vk::FramebufferCreateInfo info; VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
info.setRenderPass(m_offscreenRenderPass); info.renderPass = m_offscreenRenderPass;
info.setAttachmentCount(2); info.attachmentCount = 2;
info.setPAttachments(attachments.data()); info.pAttachments = attachments.data();
info.setWidth(m_size.width); info.width = m_size.width;
info.setHeight(m_size.height); info.height = m_size.height;
info.setLayers(1); info.layers = 1;
m_offscreenFramebuffer = m_device.createFramebuffer(info); vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -536,26 +511,23 @@ void HelloVulkan::createOffscreenRender()
void HelloVulkan::createPostPipeline() void HelloVulkan::createPostPipeline()
{ {
// Push constants in the fragment shader // Push constants in the fragment shader
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
// Creating the pipeline layout // Creating the pipeline layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
pipelineLayoutCreateInfo.setSetLayoutCount(1); createInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); createInfo.pSetLayouts = &m_postDescSetLayout;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); createInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); createInfo.pPushConstantRanges = &pushConstantRanges;
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
m_renderPass); pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
true), pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
vk::ShaderStageFlagBits::eVertex); m_postPipeline = pipelineGenerator.createPipeline();
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline();
m_debug.setObjectName(m_postPipeline, "post"); m_debug.setObjectName(m_postPipeline, "post");
} }
@ -565,11 +537,7 @@ void HelloVulkan::createPostPipeline()
// //
void HelloVulkan::createPostDescriptor() void HelloVulkan::createPostDescriptor()
{ {
using vkDS = vk::DescriptorSetLayoutBinding; m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
@ -581,28 +549,25 @@ void HelloVulkan::createPostDescriptor()
// //
void HelloVulkan::updatePostDescriptorSet() void HelloVulkan::updatePostDescriptorSet()
{ {
vk::WriteDescriptorSet writeDescriptorSets = VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Draw a full screen quad with the attached image // Draw a full screen quad with the attached image
// //
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
{ {
m_debug.beginLabel(cmdBuf, "Post"); m_debug.beginLabel(cmdBuf, "Post");
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); setViewport(cmdBuf);
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height); auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
aspectRatio); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, vkCmdDraw(cmdBuf, 3, 1, 0, 0);
m_postDescSet, {});
cmdBuf.draw(3, 1, 0, 0);
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -18,9 +18,8 @@
*/ */
#pragma once #pragma once
#include <vulkan/vulkan.hpp>
#include "nvvk/appbase_vkpp.hpp" #include "nvvk/appbase_vk.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
@ -33,25 +32,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -88,12 +83,12 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
@ -109,18 +104,18 @@ public:
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
}; };

View file

@ -23,8 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -89,14 +86,12 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0), CameraManip.setLookat(nvmath::vec3f(2.0f, 2.0f, 2.0f), nvmath::vec3f(0, 0, 0), nvmath::vec3f(0, 1, 0));
nvmath::vec3f(0, 1, 0));
// Setup Vulkan // Setup Vulkan
if(!glfwVulkanSupported()) if(!glfwVulkanSupported())
@ -147,11 +142,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -196,8 +190,7 @@ int main(int argc, char** argv)
ImGuiH::Panel::Begin(); ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor)); ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -206,62 +199,63 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")
@ -76,4 +76,3 @@ _finalize_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")

File diff suppressed because it is too large Load diff

View file

@ -18,12 +18,12 @@
*/ */
#pragma once #pragma once
#include <vulkan/vulkan.hpp>
#include "nvvk/appbase_vkpp.hpp" #include "nvvk/appbase_vk.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -35,25 +35,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -90,39 +86,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -133,25 +131,25 @@ public:
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void createRtShaderBindingTable(); void createRtShaderBindingTable();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstant struct RtPushConstant
{ {
nvmath::vec4f clearColor; nvmath::vec4f clearColor;
nvmath::vec3f lightPosition; nvmath::vec3f lightPosition;
float lightIntensity; float lightIntensity{100.0f};
int lightType; int lightType{0};
} m_rtPushConstants; } m_rtPushConstants;
}; };

View file

@ -23,8 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -87,8 +86,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -117,7 +115,7 @@ int main(int argc, char** argv)
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -127,19 +125,19 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
&accelFeature); VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
vkctx.initInstance(contextInfo); vkctx.initInstance(contextInfo);
@ -149,16 +147,14 @@ int main(int argc, char** argv)
// Use a compatible device // Use a compatible device
vkctx.initDevice(compatibleDevices[0], contextInfo); vkctx.initDevice(compatibleDevices[0], contextInfo);
// Create example // Create example
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -219,9 +215,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -230,28 +224,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -260,40 +255,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

View file

@ -62,17 +62,20 @@ void HelloVulkan::animationInstances(float time)
Next, we update the buffer that describes the scene, which is used by the rasterizer to set each object's position, and also by the ray tracer to compute shading normals. Next, we update the buffer that describes the scene, which is used by the rasterizer to set each object's position, and also by the ray tracer to compute shading normals.
~~~~ C++ ~~~~ C++
// Update the buffer // Update the buffer
vk::DeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance); VkDeviceSize bufferSize = m_objInstance.size() * sizeof(ObjInstance);
nvvkBuffer stagingBuffer = m_alloc.createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc, nvvk::Buffer stagingBuffer =
vk::MemoryPropertyFlagBits::eHostVisible); m_alloc.createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
// Copy data to staging buffer // Copy data to staging buffer
auto* gInst = m_alloc.map(stagingBuffer); auto* gInst = m_alloc.map(stagingBuffer);
memcpy(gInst, m_objInstance.data(), bufferSize); memcpy(gInst, m_objInstance.data(), bufferSize);
m_alloc.unmap(stagingBuffer); m_alloc.unmap(stagingBuffer);
// Copy staging buffer to the Scene Description buffer // Copy staging buffer to the Scene Description buffer
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
cmdBuf.copyBuffer(stagingBuffer.buffer, m_sceneDesc.buffer, vk::BufferCopy(0, 0, bufferSize));
VkBufferCopy region{0, 0, bufferSize};
vkCmdCopyBuffer(cmdBuf, stagingBuffer.buffer, m_sceneDesc.buffer, 1, &region);
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
m_alloc.destroy(stagingBuffer); m_alloc.destroy(stagingBuffer);
@ -115,7 +118,7 @@ std::vector<nvvk::RaytracingBuilder::Instance> m_tlas;
Make sure to rename it to `m_tlas`, instead of `tlas`. Make sure to rename it to `m_tlas`, instead of `tlas`.
One important point is that we need to set the TLAS build flags to allow updates, by adding the`vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate` flag. One important point is that we need to set the TLAS build flags to allow updates, by adding the`VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR` flag.
This is absolutely needed, since otherwise the TLAS cannot be updated. This is absolutely needed, since otherwise the TLAS cannot be updated.
~~~~ C++ ~~~~ C++
@ -124,16 +127,17 @@ void HelloVulkan::createTopLevelAS()
m_tlas.reserve(m_objInstance.size()); m_tlas.reserve(m_objInstance.size());
for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++) for(uint32_t i = 0; i < static_cast<uint32_t>(m_objInstance.size()); i++)
{ {
nvvk::RaytracingBuilder::Instance rayInst; nvvk::RaytracingBuilderKHR::Instance rayInst;
rayInst.transform = m_objInstance[i].transform; // Position of the instance rayInst.transform = m_objInstance[i].transform; // Position of the instance
rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT rayInst.instanceCustomId = i; // gl_InstanceCustomIndexEXT
rayInst.blasId = m_objInstance[i].objIndex; rayInst.blasId = m_objInstance[i].objIndex;
rayInst.hitGroupId = m_objInstance[i].hitgroup; rayInst.hitGroupId = 0;
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
m_tlas.emplace_back(rayInst); m_tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(m_tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate); m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR;
m_rtBuilder.buildTlas(m_tlas, m_rtFlags);
} }
~~~~ ~~~~
@ -203,11 +207,11 @@ Add all of the following members to the `HelloVulkan` class:
void createCompPipelines(); void createCompPipelines();
nvvk::DescriptorSetBindings m_compDescSetLayoutBind; nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
vk::DescriptorPool m_compDescPool; VkDescriptorPool m_compDescPool;
vk::DescriptorSetLayout m_compDescSetLayout; VkDescriptorSetLayout m_compDescSetLayout;
vk::DescriptorSet m_compDescSet; VkDescriptorSet m_compDescSet;
vk::Pipeline m_compPipeline; VkPipeline m_compPipeline;
vk::PipelineLayout m_compPipelineLayout; VkPipelineLayout m_compPipelineLayout;
~~~~ ~~~~
The compute shader will work on a single `VertexObj` buffer. The compute shader will work on a single `VertexObj` buffer.
@ -215,8 +219,7 @@ The compute shader will work on a single `VertexObj` buffer.
~~~~ C++ ~~~~ C++
void HelloVulkan::createCompDescriptors() void HelloVulkan::createCompDescriptors()
{ {
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT);
0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
@ -227,12 +230,12 @@ void HelloVulkan::createCompDescriptors()
`updateCompDescriptors` will set the set the descriptor to the buffer of `VertexObj` objects to which the animation will be applied. `updateCompDescriptors` will set the set the descriptor to the buffer of `VertexObj` objects to which the animation will be applied.
~~~~ C++ ~~~~ C++
void HelloVulkan::updateCompDescriptors(nvvkBuffer& vertex) void HelloVulkan::updateCompDescriptors(nvvk::Buffer& vertex)
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
vk::DescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, dbiUnif)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &dbiUnif));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
~~~~ ~~~~
@ -243,27 +246,37 @@ to set the animation time.
void HelloVulkan::createCompPipelines() void HelloVulkan::createCompPipelines()
{ {
// pushing time // pushing time
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(float)}; VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float)};
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants};
m_compPipelineLayout = m_device.createPipelineLayout(layout_info); VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; createInfo.setLayoutCount = 1;
createInfo.pSetLayouts = &m_compDescSetLayout;
createInfo.pushConstantRangeCount = 1;
createInfo.pPushConstantRanges = &push_constants;
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_compPipelineLayout);
VkComputePipelineCreateInfo computePipelineCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
computePipelineCreateInfo.layout = m_compPipelineLayout;
computePipelineCreateInfo.stage = computePipelineCreateInfo.stage =
nvvk::createShaderStageInfo(m_device, nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true),
nvh::loadFile("shaders/anim.comp.spv", true, defaultSearchPaths),
VK_SHADER_STAGE_COMPUTE_BIT); VK_SHADER_STAGE_COMPUTE_BIT);
m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo, nullptr);
m_device.destroy(computePipelineCreateInfo.stage.module); vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_compPipeline);
vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr);
} }
~~~~ ~~~~
Finally, destroy the resources in `HelloVulkan::destroyResources()`: Finally, destroy the resources in `HelloVulkan::destroyResources()`:
~~~~ C++ ~~~~ C++
m_device.destroy(m_compDescPool); // #VK_compute
m_device.destroy(m_compDescSetLayout); vkDestroyPipeline(m_device, m_compPipeline, nullptr);
m_device.destroy(m_compPipeline); vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr);
m_device.destroy(m_compPipelineLayout); vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
~~~~ ~~~~
### `anim.comp` ### `anim.comp`
@ -338,14 +351,13 @@ void HelloVulkan::animationObject(float time)
updateCompDescriptors(model.vertexBuffer); updateCompDescriptors(model.vertexBuffer);
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer();
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time);
vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1);
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
{m_compDescSet}, {});
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(float),
&time);
cmdBuf.dispatch(model.nbVertices, 1, 1);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
} }
~~~~ ~~~~
@ -450,15 +462,15 @@ void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
m_blas.reserve(m_objModel.size()); m_blas.reserve(m_objModel.size());
for(const auto & obj : m_objModel) for(const auto& obj : m_objModel)
{ {
auto blas = objectToVkGeometryKHR(obj); auto blas = objectToVkGeometryKHR(obj);
// We could add more geometry in each BLAS, but we add only one for now // We could add more geometry in each BLAS, but we add only one for now
m_blas.push_back(blas); m_blas.push_back(blas);
} }
m_rtBuilder.buildBlas(m_blas, vk::BuildAccelerationStructureFlagBitsKHR::eAllowUpdate m_rtBuilder.buildBlas(m_blas, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR
| vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastBuild); | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
} }
~~~~ ~~~~

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -36,25 +36,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -91,39 +87,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -133,19 +131,19 @@ public:
void createRtDescriptorSet(); void createRtDescriptorSet();
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::SBTWrapper m_sbtWrapper; nvvk::SBTWrapper m_sbtWrapper;
std::vector<nvvk::RaytracingBuilderKHR::Instance> m_tlas; std::vector<nvvk::RaytracingBuilderKHR::Instance> m_tlas;
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> m_blas;
@ -168,11 +166,11 @@ public:
void createCompPipelines(); void createCompPipelines();
nvvk::DescriptorSetBindings m_compDescSetLayoutBind; nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
vk::DescriptorPool m_compDescPool; VkDescriptorPool m_compDescPool;
vk::DescriptorSetLayout m_compDescSetLayout; VkDescriptorSetLayout m_compDescSetLayout;
vk::DescriptorSet m_compDescSet; VkDescriptorSet m_compDescSet;
vk::Pipeline m_compPipeline; VkPipeline m_compPipeline;
vk::PipelineLayout m_compPipelineLayout; VkPipelineLayout m_compPipelineLayout;
vk::BuildAccelerationStructureFlagsKHR m_rtFlags; VkBuildAccelerationStructureFlagsKHR m_rtFlags;
}; };

View file

@ -23,7 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -33,13 +32,10 @@
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -47,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -74,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -88,12 +86,11 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
CameraManip.setLookat(nvmath::vec3f(4, 4, 4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0)); CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
// Setup Vulkan // Setup Vulkan
if(!glfwVulkanSupported()) if(!glfwVulkanSupported())
@ -131,16 +128,14 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -155,11 +150,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -229,8 +223,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -244,28 +237,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -274,40 +268,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

View file

@ -108,25 +108,30 @@ The any hit shader will be part of the hit shader group. Currently, the hit shad
In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahit.spv` In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahit.spv`
~~~~ C++ ~~~~ C++
vk::ShaderModule ahitSM = enum StageIndices
nvvk::createShaderModule(m_device, // {
nvh::loadFile("shaders/raytrace.rahit.spv", true, paths)); ...
eAnyHit,
eShaderGroupCount
};
// Hit Group - Any Hit
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
stages[eAnyHit] = stage;
~~~~ ~~~~
add the any hit shader to the hit group The Any Hit goes in the same Hit group as the Closest Hit, so we need to
add the Any Hit stage index and push back the shader module to the stages.
~~~~ C++ ~~~~ C++
hg.setClosestHitShader(static_cast<uint32_t>(stages.size())); // closest hit shader
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); // Payload 0
hg.setAnyHitShader(static_cast<uint32_t>(stages.size())); group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"}); group.generalShader = VK_SHADER_UNUSED_KHR;
m_rtShaderGroups.push_back(hg); group.closestHitShader = eClosestHit;
~~~~ group.anyHitShader = eAnyHit;
m_rtShaderGroups.push_back(group);
and at the end, delete it:
~~~~ C++
m_device.destroy(ahitSM);
~~~~ ~~~~
## Give access of the buffers to the Any Hit shader ## Give access of the buffers to the Any Hit shader
@ -137,38 +142,37 @@ This is the case for the material and scene description buffers
~~~~ C++ ~~~~ C++
// Materials (binding = 1) // Materials (binding = 1)
m_descSetLayoutBind.emplace_back( m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
vkDS(1, vkDT::eStorageBuffer, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Scene description (binding = 2) // Scene description (binding = 2)
m_descSetLayoutBind.emplace_back( // m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
vkDS(2, vkDT::eStorageBuffer, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
~~~~ ~~~~
and also for the vertex, index and material index buffers: and also for the vertex, index and material index buffers:
~~~~ C++ ~~~~ C++
// Materials (binding = 4) // Materials (binding = 4)
m_descSetLayoutBind.emplace_back( // m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
vkDS(4, vkDT::eStorageBuffer, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
vkSS::eFragment | vkSS::eClosestHitKHR | vkSS::eAnyHitKHR));
// Storing vertices (binding = 5) // Storing vertices (binding = 5)
m_descSetLayoutBind.emplace_back( // m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
// Storing indices (binding = 6) // Storing indices (binding = 6)
m_descSetLayoutBind.emplace_back( // m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj,
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR | vkSS::eAnyHitKHR)); VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
~~~~ ~~~~
## Opaque Flag ## Opaque Flag
In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `vk::GeometryFlagBitsKHR::eOpaque`. However, this avoided invoking the any hit shader. In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `VK_GEOMETRY_OPAQUE_BIT_KHR`. However, this avoided invoking the any hit shader.
We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `eNoDuplicateAnyHitInvocation` flag: We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR` flag:
~~~~ C++ ~~~~ C++
geometry.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // Avoid double hits;
~~~~ ~~~~
## Ray Generation Shader ## Ray Generation Shader
@ -364,8 +368,6 @@ traceRayEXT(topLevelAS, // acceleration structure
~~~~ ~~~~
### Ray tracing Pipeline ### Ray tracing Pipeline
The final step is to add the new Hit Group. This is a change in `HelloVulkan::createRtPipeline()`. The final step is to add the new Hit Group. This is a change in `HelloVulkan::createRtPipeline()`.
@ -373,22 +375,42 @@ We need to load the new any hit shader and create a new Hit Group.
Replace the `"shaders/raytrace.rahit.spv"` for `"shaders/raytrace_0.rahit.spv"` Replace the `"shaders/raytrace.rahit.spv"` for `"shaders/raytrace_0.rahit.spv"`
Load the new shader module.
~~~~ C
enum StageIndices
{
eRaygen,
eMiss,
eMiss2,
eClosestHit,
eAnyHit,
eAnyHit2,
eShaderGroupCount
};
// Hit Group - Any Hit
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_0.rahit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
stages[eAnyHit] = stage;
//
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
stages[eAnyHit2] = stage;
~~~~
Then, after the creating of the first Hit Group, create a new one, where only the any hit using payload 1 Then, after the creating of the first Hit Group, create a new one, where only the any hit using payload 1
is added. We are skipping the closest hit shader in the trace call, so we can ignore it in the Hit Group. is added. We are skipping the closest hit shader in the trace call, so we can ignore it in the Hit Group.
~~~~ C ~~~~ C
// Payload 1 // Payload 1
vk::ShaderModule ahit1SM = group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
nvvk::createShaderModule(m_device, // group.generalShader = VK_SHADER_UNUSED_KHR;
nvh::loadFile("shaders/raytrace_1.rahit.spv", true, paths)); group.closestHitShader = VK_SHADER_UNUSED_KHR;
hg.setClosestHitShader(VK_SHADER_UNUSED_NV); // Not used by shadow (skipped) group.anyHitShader = eAnyHit2;
hg.setAnyHitShader(static_cast<uint32_t>(stages.size())); m_rtShaderGroups.push_back(group);
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitNV, ahit1SM, "main"});
m_rtShaderGroups.push_back(hg);
~~~~ ~~~~
At the end of the function, delete the shader module `ahit1SM`.
**Note:** Re-Run **Note:** Re-Run
Everything should work as before, but now it does it right. Everything should work as before, but now it does it right.

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -35,25 +35,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -90,39 +86,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -133,21 +131,21 @@ public:
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void createRtShaderBindingTable(); void createRtShaderBindingTable();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
void resetFrame(); void resetFrame();
void updateFrame(); void updateFrame();
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
int m_maxFrames{10000}; int m_maxFrames{10000};
struct RtPushConstant struct RtPushConstant
{ {

View file

@ -23,7 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -33,11 +32,9 @@
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -87,8 +86,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -117,7 +115,7 @@ int main(int argc, char** argv)
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -131,13 +129,10 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
&accelFeature); VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
@ -156,11 +151,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -172,8 +166,7 @@ int main(int argc, char** argv)
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true),
nvmath::scale_mat4(nvmath::vec3f(1.5f)) nvmath::scale_mat4(nvmath::vec3f(1.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
* nvmath::translation_mat4(nvmath::vec3f(0.0f, 1.0f, 0.0f)));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
@ -215,6 +208,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -223,8 +217,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -233,28 +226,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -263,40 +257,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -36,35 +36,33 @@ The following are the buffers are they can be seen in [NSight Graphics](https://
## G-Buffer ## G-Buffer
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `vk::Format::eR32G32B32A32Sfloat` to store the position and normal and one `vk::Format::eR32Sfloat` for the ambient occlusion. The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion.
~~~~ C++ ~~~~ C++
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed) // The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
vk::ImageUsageFlagBits::eColorAttachment VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
| vk::ImageUsageFlagBits::eSampled | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo); nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_gBuffer.image, "G-Buffer"); m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
} }
// The ambient occlusion result (r32) // The ambient occlusion result (r32)
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
vk::ImageUsageFlagBits::eColorAttachment VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
| vk::ImageUsageFlagBits::eSampled | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo); nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer"); m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
} }
@ -76,9 +74,9 @@ The render pass for the fragment shader will need two color buffers, therefore w
``` ```
// Creating the frame buffer for offscreen // Creating the frame buffer for offscreen
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView, std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView,
m_gBuffer.descriptor.imageView, m_gBuffer.descriptor.imageView,
m_offscreenDepth.descriptor.imageView}; m_offscreenDepth.descriptor.imageView};
``` ```
### Renderpass ### Renderpass
@ -86,7 +84,7 @@ The render pass for the fragment shader will need two color buffers, therefore w
This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth) This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth)
``` ```
vk::ClearValue clearValues[3]; std::array<VkClearValue, 3> clearValues{};
``` ```
Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section. Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section.
@ -94,14 +92,14 @@ Since the clear value will be re-used by the offscreen (3 attachments) and the p
``` ```
// Offscreen render pass // Offscreen render pass
{ {
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0}); clearValues[1].color = {{0, 0, 0, 0}};
clearValues[2].setDepthStencil({1.0f, 0}); clearValues[2].depthStencil = {1.0f, 0};
``` ```
``` ```
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
clearValues[1].setDepthStencil({1.0f, 0}); clearValues[1].depthStencil = {1.0f, 0};
``` ```
### Fragment shader ### Fragment shader
@ -138,12 +136,9 @@ The shader takes two inputs, the G-Buffer and the TLAS, and has one output, the
// //
void HelloVulkan::createCompDescriptors() void HelloVulkan::createCompDescriptors()
{ {
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute)); m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
@ -162,15 +157,17 @@ when resizing the window and the G-Buffer and AO buffer are resized.
// //
void HelloVulkan::updateCompDescriptors() void HelloVulkan::updateCompDescriptors()
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas}; VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
descASInfo.accelerationStructureCount = 1;
descASInfo.pAccelerationStructures = &tlas;
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
~~~~ ~~~~
@ -200,40 +197,38 @@ struct AoControl
The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)). The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)).
This sets the current frame index, which allows us to accumulate AO samples over time. This sets the current frame index, which allows us to accumulate AO samples over time.
Next, we are adding a `vk::ImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader. Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
~~~~ C++ ~~~~ C++
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer // Adding a barrier to be sure the fragment has finished writing to the G-Buffer
// before the compute shader is using the buffer // before the compute shader is using the buffer
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vk::ImageMemoryBarrier imgMemBarrier; VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imgMemBarrier.setImage(m_gBuffer.image); imgMemBarrier.image = m_gBuffer.image;
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
imgMemBarrier.setSubresourceRange(range); imgMemBarrier.subresourceRange = range;
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
vk::PipelineStageFlagBits::eComputeShader, vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier}); VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
~~~~ ~~~~
Folowing is the call to dispatch the compute shader Folowing is the call to dispatch the compute shader
~~~~ C++ ~~~~ C++
// Preparing for the compute shader // Preparing for the compute shader
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0, vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
{m_compDescSet}, {});
// Sending the push constant information // Sending the push constant information
aoControl.frame = m_frame; aoControl.frame = m_frame;
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
sizeof(AoControl), &aoControl);
// Dispatching the shader // Dispatching the shader
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
~~~~ ~~~~
Then we are adding a final barrier to make sure the compute shader is done Then we are adding a final barrier to make sure the compute shader is done
@ -242,13 +237,9 @@ writing the AO so that the fragment shader (post) can use it.
~~~~ C++ ~~~~ C++
// Adding a barrier to be sure the compute shader has finished // Adding a barrier to be sure the compute shader has finished
// writing to the AO buffer before the post shader is using it // writing to the AO buffer before the post shader is using it
imgMemBarrier.setImage(m_aoBuffer.image); imgMemBarrier.image = m_aoBuffer.image;
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
imgMemBarrier.setSubresourceRange(range);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eFragmentShader,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
~~~~ ~~~~
## Update Frame ## Update Frame
@ -450,9 +441,9 @@ We have also have added `AoControl aoControl;` somwhere in main() and passing th
~~~~ ~~~~
// Rendering Scene // Rendering Scene
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
helloVk.runCompute(cmdBuf, aoControl); helloVk.runCompute(cmdBuf, aoControl);
} }
~~~~ ~~~~
@ -463,10 +454,10 @@ The post shader will combine the result of the fragment (color) and the result o
In `createPostDescriptor` we will need to add the descriptor In `createPostDescriptor` we will need to add the descriptor
~~~~ ~~~~
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment)); m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
~~~~ ~~~~
And the equivalent in `updatePostDescriptorSet` And the equivalent in `updatePostDescriptorSet()`
~~~~ ~~~~
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor)); writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));

View file

@ -19,25 +19,25 @@
#include <sstream> #include <sstream>
#include <vulkan/vulkan.hpp>
extern std::vector<std::string> defaultSearchPaths;
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "obj_loader.h" #include "obj_loader.h"
#include "stb_image.h" #include "stb_image.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "nvh/alignment.hpp"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/images_vk.hpp" #include "nvvk/images_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
#include "nvvk/shaders_vk.hpp" #include "nvvk/shaders_vk.hpp"
extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices // Holding the camera matrices
struct CameraMatrices struct CameraMatrices
@ -45,21 +45,17 @@ struct CameraMatrices
nvmath::mat4f view; nvmath::mat4f view;
nvmath::mat4f proj; nvmath::mat4f proj;
nvmath::mat4f viewInverse; nvmath::mat4f viewInverse;
// #VKRay
nvmath::mat4f projInverse;
}; };
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
// //
void HelloVulkan::setup(const vk::Instance& instance, void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily)
{ {
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(instance, device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
@ -67,46 +63,44 @@ void HelloVulkan::setup(const vk::Instance& instance,
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Called at each frame to update the camera matrix // Called at each frame to update the camera matrix
// //
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; CameraMatrices hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); hostUBO.view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view); hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.buffer = deviceUBO;
beforeBarrier.setOffset(0); beforeBarrier.offset = 0;
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); nullptr, 1, &beforeBarrier, 0, nullptr);
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO); vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
vk::BufferMemoryBarrier afterBarrier; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
afterBarrier.setBuffer(deviceUBO); afterBarrier.buffer = deviceUBO;
afterBarrier.setOffset(0); afterBarrier.offset = 0;
afterBarrier.setSize(sizeof hostUBO); afterBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); nullptr, 1, &afterBarrier, 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -114,22 +108,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// //
void HelloVulkan::createDescriptorSetLayout() void HelloVulkan::createDescriptorSetLayout()
{ {
using vkDS = vk::DescriptorSetLayoutBinding;
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
auto nbObj = static_cast<uint32_t>(m_objModel.size()); auto nbObj = static_cast<uint32_t>(m_objModel.size());
// Camera matrices (binding = 0) // Camera matrices (binding = 0)
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex)); m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
// Materials (binding = 1) // Materials (binding = 1)
m_descSetLayoutBind.addBinding(vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eFragment)); m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
// Scene description (binding = 2) // Scene description (binding = 2)
m_descSetLayoutBind.addBinding(vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment)); m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
// Textures (binding = 3) // Textures (binding = 3)
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment)); m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
// Materials (binding = 4) // Materials (binding = 4)
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment)); m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
@ -142,40 +133,39 @@ void HelloVulkan::createDescriptorSetLayout()
// //
void HelloVulkan::updateDescriptorSet() void HelloVulkan::updateDescriptorSet()
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
// All material buffers, 1 buffer per OBJ // All material buffers, 1 buffer per OBJ
std::vector<vk::DescriptorBufferInfo> dbiMat; std::vector<VkDescriptorBufferInfo> dbiMat;
std::vector<vk::DescriptorBufferInfo> dbiMatIdx; std::vector<VkDescriptorBufferInfo> dbiMatIdx;
std::vector<vk::DescriptorBufferInfo> dbiVert; std::vector<VkDescriptorBufferInfo> dbiVert;
std::vector<vk::DescriptorBufferInfo> dbiIdx; std::vector<VkDescriptorBufferInfo> dbiIdx;
for(auto& obj : m_objModel) for(auto& m : m_objModel)
{ {
dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
// All texture samplers // All texture samplers
std::vector<vk::DescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
// Writing the information // Writing the information
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -183,37 +173,34 @@ void HelloVulkan::updateDescriptorSet()
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
using vkSS = vk::ShaderStageFlagBits; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
sizeof(ObjPushConstant)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
vk::DescriptorSetLayout descSetLayout(m_descSetLayout); createInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setSetLayoutCount(1); createInfo.pSetLayouts = &m_descSetLayout;
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); createInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); createInfo.pPushConstantRanges = &pushConstantRanges;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Creating the Pipeline // Creating the Pipeline
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({ gpb.addAttributeDescriptions({
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))}, {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))}, {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))}, {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))}, {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
}); });
vk::PipelineColorBlendAttachmentState res; VkPipelineColorBlendAttachmentState res{};
res.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG res.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA; res.colorBlendOp = VK_BLEND_OP_ADD;
gpb.addBlendAttachmentState(res); gpb.addBlendAttachmentState(res);
m_graphicsPipeline = gpb.createPipeline(); m_graphicsPipeline = gpb.createPipeline();
@ -225,8 +212,6 @@ void HelloVulkan::createGraphicsPipeline()
// //
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
{ {
using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str()); LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -250,18 +235,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size()); model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
// Create the buffers on Device and copy vertices, indices and materials // Create the buffers on Device and copy vertices, indices and materials
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
m_alloc.createBuffer(cmdBuf, loader.m_vertices, | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
model.indexBuffer = model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
m_alloc.createBuffer(cmdBuf, loader.m_indices, model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
@ -277,17 +258,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
m_objInstance.emplace_back(instance); m_objInstance.emplace_back(instance);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating the uniform buffer holding the camera matrices // Creating the uniform buffer holding the camera matrices
// - Buffer is host visible // - Buffer is host visible
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits; m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
using vkMP = vk::MemoryPropertyFlagBits; VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
} }
@ -299,11 +278,10 @@ void HelloVulkan::createUniformBuffer()
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createSceneDescriptionBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits;
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
@ -312,15 +290,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating all textures and samplers // Creating all textures and samplers
// //
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
const std::vector<std::string>& textures)
{ {
using vkIU = vk::ImageUsageFlagBits; VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCreateInfo.maxLod = FLT_MAX;
vk::SamplerCreateInfo samplerCreateInfo{ VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
samplerCreateInfo.setMaxLod(FLT_MAX);
vk::Format format = vk::Format::eR8G8B8A8Srgb;
// If no textures are present, create a dummy one to accommodate the pipeline layout // If no textures are present, create a dummy one to accommodate the pipeline layout
if(textures.empty() && m_textures.empty()) if(textures.empty() && m_textures.empty())
@ -328,18 +306,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
nvvk::Texture texture; nvvk::Texture texture;
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u}; std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
vk::DeviceSize bufferSize = sizeof(color); VkDeviceSize bufferSize = sizeof(color);
auto imgSize = vk::Extent2D(1, 1); auto imgSize = VkExtent2D{1, 1};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the VKImage // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vk::ImageLayout::eShaderReadOnlyOptimal);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
else else
@ -352,8 +329,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -366,16 +342,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
pixels = reinterpret_cast<stbi_uc*>(color.data()); pixels = reinterpret_cast<stbi_uc*>(color.data());
} }
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4; VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
auto imgSize = vk::Extent2D(texWidth, texHeight); auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
{ {
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
vk::ImageViewCreateInfo ivInfo = VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
@ -390,10 +365,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
// //
void HelloVulkan::destroyResources() void HelloVulkan::destroyResources()
{ {
m_device.destroy(m_graphicsPipeline); vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
m_device.destroy(m_pipelineLayout); vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
m_device.destroy(m_descPool); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
m_device.destroy(m_descSetLayout); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_cameraMat);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_sceneDesc);
@ -411,22 +387,22 @@ void HelloVulkan::destroyResources()
} }
//#Post //#Post
m_device.destroy(m_postPipeline);
m_device.destroy(m_postPipelineLayout);
m_device.destroy(m_postDescPool);
m_device.destroy(m_postDescSetLayout);
m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenColor);
m_alloc.destroy(m_gBuffer); m_alloc.destroy(m_gBuffer);
m_alloc.destroy(m_aoBuffer); m_alloc.destroy(m_aoBuffer);
m_alloc.destroy(m_offscreenDepth); m_alloc.destroy(m_offscreenDepth);
m_device.destroy(m_offscreenRenderPass); vkDestroyPipeline(m_device, m_postPipeline, nullptr);
m_device.destroy(m_offscreenFramebuffer); vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
// Compute // Compute
m_device.destroy(m_compDescPool); vkDestroyPipeline(m_device, m_compPipeline, nullptr);
m_device.destroy(m_compDescSetLayout); vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr);
m_device.destroy(m_compPipeline); vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr);
m_device.destroy(m_compPipelineLayout); vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
// #VKRay // #VKRay
m_rtBuilder.destroy(); m_rtBuilder.destroy();
@ -436,32 +412,31 @@ void HelloVulkan::destroyResources()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Drawing the scene in raster mode // Drawing the scene in raster mode
// //
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
{ {
using vkPBP = vk::PipelineBindPoint; VkDeviceSize offset{0};
using vkSS = vk::ShaderStageFlagBits;
vk::DeviceSize offset{0};
m_debug.beginLabel(cmdBuf, "Rasterize"); m_debug.beginLabel(cmdBuf, "Rasterize");
// Dynamic Viewport // Dynamic Viewport
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); setViewport(cmdBuf);
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
// Drawing all triangles // Drawing all triangles
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(int i = 0; i < m_objInstance.size(); ++i)
{ {
auto& inst = m_objInstance[i]; auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pushConstant.instanceId = i; // Telling which instance is drawn
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
m_pushConstant);
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); sizeof(ObjPushConstant), &m_pushConstant);
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
} }
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }
@ -491,64 +466,62 @@ void HelloVulkan::createOffscreenRender()
m_alloc.destroy(m_aoBuffer); m_alloc.destroy(m_aoBuffer);
m_alloc.destroy(m_offscreenDepth); m_alloc.destroy(m_offscreenDepth);
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
// Creating the color image // Creating the color image
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
vk::ImageUsageFlagBits::eColorAttachment VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
| vk::ImageUsageFlagBits::eSampled | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo); nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_offscreenColor.image, "offscreen"); m_debug.setObjectName(m_offscreenColor.image, "offscreen");
} }
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed) // The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
vk::ImageUsageFlagBits::eColorAttachment VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
| vk::ImageUsageFlagBits::eSampled | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo); nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_gBuffer.image, "G-Buffer"); m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
} }
// The ambient occlusion result (r32) // The ambient occlusion result (r32)
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
vk::ImageUsageFlagBits::eColorAttachment VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
| vk::ImageUsageFlagBits::eSampled | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo); nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer"); m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
} }
// Creating the depth buffer // Creating the depth buffer
auto depthCreateInfo = auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
vk::ImageUsageFlagBits::eDepthStencilAttachment);
{ {
nvvk::Image image = m_alloc.createImage(depthCreateInfo); nvvk::Image image = m_alloc.createImage(depthCreateInfo);
vk::ImageViewCreateInfo depthStencilView;
depthStencilView.setViewType(vk::ImageViewType::e2D); VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
depthStencilView.setFormat(m_offscreenDepthFormat); depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); depthStencilView.format = m_offscreenDepthFormat;
depthStencilView.setImage(image.image); depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
depthStencilView.image = image.image;
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
} }
@ -557,15 +530,11 @@ void HelloVulkan::createOffscreenRender()
{ {
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
auto cmdBuf = genCmdBuf.createCommandBuffer(); auto cmdBuf = genCmdBuf.createCommandBuffer();
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
vk::ImageLayout::eGeneral); nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
vk::ImageLayout::eGeneral); nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, vk::ImageLayout::eUndefined, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
vk::ImageLayout::eGeneral);
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
vk::ImageLayout::eDepthStencilAttachmentOptimal,
vk::ImageAspectFlagBits::eDepth);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
} }
@ -574,26 +543,23 @@ void HelloVulkan::createOffscreenRender()
if(!m_offscreenRenderPass) if(!m_offscreenRenderPass)
{ {
m_offscreenRenderPass = m_offscreenRenderPass =
nvvk::createRenderPass(m_device, nvvk::createRenderPass(m_device, {m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
{m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
m_offscreenDepthFormat, 1, true, true, vk::ImageLayout::eGeneral,
vk::ImageLayout::eGeneral);
} }
// Creating the frame buffer for offscreen // Creating the frame buffer for offscreen
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView, std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_gBuffer.descriptor.imageView,
m_gBuffer.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
m_offscreenDepth.descriptor.imageView};
m_device.destroy(m_offscreenFramebuffer); vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
vk::FramebufferCreateInfo info; VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
info.setRenderPass(m_offscreenRenderPass); info.renderPass = m_offscreenRenderPass;
info.setAttachmentCount(static_cast<int>(attachments.size())); info.attachmentCount = static_cast<int>(attachments.size());
info.setPAttachments(attachments.data()); info.pAttachments = attachments.data();
info.setWidth(m_size.width); info.width = m_size.width;
info.setHeight(m_size.height); info.height = m_size.height;
info.setLayers(1); info.layers = 1;
m_offscreenFramebuffer = m_device.createFramebuffer(info); vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -602,26 +568,23 @@ void HelloVulkan::createOffscreenRender()
void HelloVulkan::createPostPipeline() void HelloVulkan::createPostPipeline()
{ {
// Push constants in the fragment shader // Push constants in the fragment shader
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
// Creating the pipeline layout // Creating the pipeline layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
pipelineLayoutCreateInfo.setSetLayoutCount(1); createInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); createInfo.pSetLayouts = &m_postDescSetLayout;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); createInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); createInfo.pPushConstantRanges = &pushConstantRanges;
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
m_renderPass); pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
true), pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
vk::ShaderStageFlagBits::eVertex); m_postPipeline = pipelineGenerator.createPipeline();
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline();
m_debug.setObjectName(m_postPipeline, "post"); m_debug.setObjectName(m_postPipeline, "post");
} }
@ -631,12 +594,8 @@ void HelloVulkan::createPostPipeline()
// //
void HelloVulkan::createPostDescriptor() void HelloVulkan::createPostDescriptor()
{ {
using vkDS = vk::DescriptorSetLayoutBinding; m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
using vkDT = vk::DescriptorType; m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
using vkSS = vk::ShaderStageFlagBits;
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
@ -647,36 +606,32 @@ void HelloVulkan::createPostDescriptor()
// //
void HelloVulkan::updatePostDescriptorSet() void HelloVulkan::updatePostDescriptorSet()
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back( writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor)); writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Draw a full screen quad with the attached image // Draw a full screen quad with the attached image
// //
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
{ {
m_debug.beginLabel(cmdBuf, "Post"); m_debug.beginLabel(cmdBuf, "Post");
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); setViewport(cmdBuf);
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height); auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
aspectRatio); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, vkCmdDraw(cmdBuf, 3, 1, 0, 0);
m_postDescSet, {});
cmdBuf.draw(3, 1, 0, 0);
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Raytracing, creation of BLAS and TLAS //////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -685,45 +640,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, prop2.pNext = &m_rtProperties;
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>(); vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Convert an OBJ model into the ray tracing geometry used to build the BLAS
// //
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
// Building part // BLAS builder requires raw device addresses.
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); info.buffer = model.vertexBuffer.buffer;
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
info.buffer = model.indexBuffer.buffer;
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; uint32_t maxPrimitiveCount = model.nbIndices / 3;
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress);
triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration // Describe buffer as array of VertexObj.
vk::AccelerationStructureGeometryKHR asGeom; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); triangles.vertexData.deviceAddress = vertexAddress;
asGeom.geometry.setTriangles(triangles); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int)
triangles.indexType = VK_INDEX_TYPE_UINT32;
triangles.indexData.deviceAddress = indexAddress;
// Indicate identity transform by setting transformData to null device pointer.
//triangles.transformData = {};
triangles.maxVertex = model.nbVertices;
// The primitive itself // Identify the above data as containing opaque triangles.
vk::AccelerationStructureBuildRangeInfoKHR offset; VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
offset.setFirstVertex(0); asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
offset.setPrimitiveOffset(0); asGeom.geometry.triangles = triangles;
offset.setTransformOffset(0);
// Our blas is only one geometry, but could be made of many geometries // The entire array will be used to build the BLAS.
VkAccelerationStructureBuildRangeInfoKHR offset;
offset.firstVertex = 0;
offset.primitiveCount = maxPrimitiveCount;
offset.primitiveOffset = 0;
offset.transformOffset = 0;
// Our blas is made from only one geometry, but could be made of many geometries
nvvk::RaytracingBuilderKHR::BlasInput input; nvvk::RaytracingBuilderKHR::BlasInput input;
input.asGeometry.emplace_back(asGeom); input.asGeometry.emplace_back(asGeom);
input.asBuildOffsetInfo.emplace_back(offset); input.asBuildOffsetInfo.emplace_back(offset);
@ -746,7 +709,7 @@ void HelloVulkan::createBottomLevelAS()
// We could add more geometry in each BLAS, but we add only one for now // We could add more geometry in each BLAS, but we add only one for now
allBlas.emplace_back(blas); allBlas.emplace_back(blas);
} }
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
@ -763,7 +726,7 @@ void HelloVulkan::createTopLevelAS()
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
@ -776,12 +739,9 @@ void HelloVulkan::createTopLevelAS()
// //
void HelloVulkan::createCompDescriptors() void HelloVulkan::createCompDescriptors()
{ {
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute)); m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
@ -793,15 +753,17 @@ void HelloVulkan::createCompDescriptors()
// //
void HelloVulkan::updateCompDescriptors() void HelloVulkan::updateCompDescriptors()
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas}; VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
descASInfo.accelerationStructureCount = 1;
descASInfo.pAccelerationStructures = &tlas;
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo)); writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -810,24 +772,29 @@ void HelloVulkan::updateCompDescriptors()
void HelloVulkan::createCompPipelines() void HelloVulkan::createCompPipelines()
{ {
// pushing time // pushing time
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(AoControl)}; VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl)};
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants}; VkPipelineLayoutCreateInfo plCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
m_compPipelineLayout = m_device.createPipelineLayout(layout_info); plCreateInfo.setLayoutCount = 1;
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout}; plCreateInfo.pSetLayouts = &m_compDescSetLayout;
plCreateInfo.pushConstantRangeCount = 1;
plCreateInfo.pPushConstantRanges = &push_constants;
vkCreatePipelineLayout(m_device, &plCreateInfo, nullptr, &m_compPipelineLayout);
computePipelineCreateInfo.stage = VkComputePipelineCreateInfo cpCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
nvvk::createShaderStageInfo(m_device, cpCreateInfo.layout = m_compPipelineLayout;
nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true), cpCreateInfo.stage = nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
VK_SHADER_STAGE_COMPUTE_BIT); VK_SHADER_STAGE_COMPUTE_BIT);
m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo).value;
m_device.destroy(computePipelineCreateInfo.stage.module); vkCreateComputePipelines(m_device, {}, 1, &cpCreateInfo, nullptr, &m_compPipeline);
vkDestroyShaderModule(m_device, cpCreateInfo.stage.module, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Running compute shader // Running compute shader
// //
#define GROUP_SIZE 16 // Same group size as in compute shader #define GROUP_SIZE 16 // Same group size as in compute shader
void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl) void HelloVulkan::runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl)
{ {
updateFrame(); updateFrame();
@ -839,43 +806,38 @@ void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer // Adding a barrier to be sure the fragment has finished writing to the G-Buffer
// before the compute shader is using the buffer // before the compute shader is using the buffer
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vk::ImageMemoryBarrier imgMemBarrier; VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite); imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imgMemBarrier.setImage(m_gBuffer.image); imgMemBarrier.image = m_gBuffer.image;
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
imgMemBarrier.setSubresourceRange(range); imgMemBarrier.subresourceRange = range;
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
vk::PipelineStageFlagBits::eComputeShader, vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier}); VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
// Preparing for the compute shader // Preparing for the compute shader
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0, vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
{m_compDescSet}, {});
// Sending the push constant information // Sending the push constant information
aoControl.frame = m_frame; aoControl.frame = m_frame;
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
sizeof(AoControl), &aoControl);
// Dispatching the shader // Dispatching the shader
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
// Adding a barrier to be sure the compute shader has finished // Adding a barrier to be sure the compute shader has finished
// writing to the AO buffer before the post shader is using it // writing to the AO buffer before the post shader is using it
imgMemBarrier.setImage(m_aoBuffer.image); imgMemBarrier.image = m_aoBuffer.image;
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral); vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral); VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
imgMemBarrier.setSubresourceRange(range);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eFragmentShader,
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -46,25 +46,21 @@ struct AoControl
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -89,7 +85,7 @@ public:
// Information pushed at each draw call // Information pushed at each draw call
struct ObjPushConstant struct ObjPushConstant
{ {
nvmath::vec3f lightPosition{3.5f, 8.f, 5.f}; nvmath::vec3f lightPosition{10.f, 15.f, 8.f};
int instanceId{0}; // To retrieve the transformation matrix int instanceId{0}; // To retrieve the transformation matrix
float lightIntensity{100.f}; float lightIntensity{100.f};
int lightType{0}; // 0: point, 1: infinite int lightType{0}; // 0: point, 1: infinite
@ -101,41 +97,43 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
nvvk::Texture m_offscreenDepth;
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
nvvk::Texture m_gBuffer; nvvk::Texture m_gBuffer;
nvvk::Texture m_aoBuffer; nvvk::Texture m_aoBuffer;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
// #Tuto_rayquery // #Tuto_rayquery
void initRayTracing(); void initRayTracing();
@ -143,22 +141,23 @@ public:
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
nvvk::RaytracingBuilderKHR m_rtBuilder; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder;
// #Tuto_animation // #Tuto_animation
void createCompDescriptors(); void createCompDescriptors();
void updateCompDescriptors(); void updateCompDescriptors();
void createCompPipelines(); void createCompPipelines();
void runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl); void runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl);
nvvk::DescriptorSetBindings m_compDescSetLayoutBind; nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
vk::DescriptorPool m_compDescPool; VkDescriptorPool m_compDescPool;
vk::DescriptorSetLayout m_compDescSetLayout; VkDescriptorSetLayout m_compDescSetLayout;
vk::DescriptorSet m_compDescSet; VkDescriptorSet m_compDescSet;
vk::Pipeline m_compPipeline; VkPipeline m_compPipeline;
vk::PipelineLayout m_compPipelineLayout; VkPipelineLayout m_compPipelineLayout;
// #Tuto_jitter_cam // #Tuto_jitter_cam
void updateFrame(); void updateFrame();

View file

@ -25,9 +25,6 @@
#include <array> #include <array>
#include <iostream> #include <iostream>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -36,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -48,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -75,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -89,8 +87,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -117,9 +114,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -129,19 +126,20 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures; VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeatures);
&accelFeatures); VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR};
vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures;
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures); contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
vkctx.initInstance(contextInfo); vkctx.initInstance(contextInfo);
@ -151,16 +149,14 @@ int main(int argc, char** argv)
// Use a compatible device // Use a compatible device
vkctx.initDevice(compatibleDevices[0], contextInfo); vkctx.initDevice(compatibleDevices[0], contextInfo);
// Create example // Create example
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -241,8 +237,7 @@ int main(int argc, char** argv)
helloVk.resetFrame(); helloVk.resetFrame();
} }
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -251,66 +246,67 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 3> clearValues; std::array<VkClearValue, 3> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
// Offscreen render pass // Offscreen render pass
{ {
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0}); clearValues[1].color = {{0, 0, 0, 0}};
clearValues[2].setDepthStencil({1.0f, 0}); clearValues[2].depthStencil = {1.0f, 0};
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(3); offscreenRenderPassBeginInfo.clearValueCount = (uint32_t)clearValues.size();
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
helloVk.runCompute(cmdBuf, aoControl); helloVk.runCompute(cmdBuf, aoControl);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
clearValues[1].setDepthStencil({1.0f, 0}); clearValues[1].depthStencil = {1.0f, 0};
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
catch(const std::system_error& e) catch(const std::system_error& e)
{ {
if(e.code() == vk::Result::eErrorDeviceLost) if(e.code().value() == VK_ERROR_DEVICE_LOST)
{ {
#if _WIN32 #if _WIN32
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1); MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
@ -322,10 +318,10 @@ int main(int argc, char** argv)
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

View file

@ -63,39 +63,50 @@ executeCallableEXT(pushC.lightType, 0);
In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit shader, we will add In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit shader, we will add
3 callable shaders, for each type of light. 3 callable shaders, for each type of light.
First create the shader modules
~~~~ C++
enum StageIndices
{
eRaygen,
eMiss,
eMiss2,
eClosestHit,
eCall0,
eCall1,
eCall2,
eShaderGroupCount
};
...
// Call0
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
stages[eCall0] = stage;
// Call1
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
stages[eCall1] = stage;
// Call2
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
stages[eCall2] = stage;
~~~~
Then 3 groups of callable shaders and the stages that goes with it.
~~~~ C++ ~~~~ C++
// Callable shaders // Callable shaders
vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral, group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, group.closestHitShader = VK_SHADER_UNUSED_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; group.generalShader = eCall0;
m_rtShaderGroups.push_back(group);
vk::ShaderModule call0 = group.generalShader = eCall1;
nvvk::createShaderModule(m_device, m_rtShaderGroups.push_back(group);
nvh::loadFile("shaders/light_point.rcall.spv", true, paths)); group.generalShader = eCall2;
vk::ShaderModule call1 = m_rtShaderGroups.push_back(group);
nvvk::createShaderModule(m_device,
nvh::loadFile("shaders/light_spot.rcall.spv", true, paths));
vk::ShaderModule call2 =
nvvk::createShaderModule(m_device, nvh::loadFile("shaders/light_inf.rcall.spv", true, paths));
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
m_rtShaderGroups.push_back(callGroup);
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
m_rtShaderGroups.push_back(callGroup);
~~~~ ~~~~
And at the end of the function, delete the shaders.
~~~~ C++
m_device.destroy(call0);
m_device.destroy(call1);
m_device.destroy(call2);
~~~~
#### Shaders #### Shaders
@ -106,29 +117,44 @@ Here are the source of all shaders
* [light_inf.rcall](shaders/light_inf.rcall) * [light_inf.rcall](shaders/light_inf.rcall)
### Passing Callable to traceRaysKHR ### Shading Binding Table
In this example, we will use the `nvvk::SBTWrapper`. It is using the information to create the ray tracing pipeline, to
create the buffers for the shading binding table.
In the `hello_vulkan.h` header, include the wrapper and add a new member.
~~~~C
#include "nvvk/sbtwrapper_vk.hpp"
...
nvvk::SBTWrapper m_sbtWrapper;
~~~~
In `HelloVulkan::initRayTracing()`, initialize it the following way.
~~~~C
m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties);
~~~~
In `HelloVulkan::createRtPipeline()`, immediately after creating the pipeline call to `vkCreateRayTracingPipelinesKHR()`,
create the SBT with the following command.
~~~~C
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
~~~~
In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Since they were added after the hit shader, we have in the SBT the following. In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Since they were added after the hit shader, we have in the SBT the following.
![SBT](images/sbt.png) ![SBT](images/sbt.png)
The SBT wrapper class give back the information we need. So instead of computing the various offsets, we can get directly the
Therefore, the callable starts at `4 * progSize` `VkStridedDeviceAddressRegionKHR` for each group type.
~~~~ C++ ~~~~ C++
std::array<stride, 4> strideAddresses{ auto& regions = m_sbtWrapper.getRegions();
stride{sbtAddress + 0u * progSize, progSize, progSize * 1}, // raygen vkCmdTraceRaysKHR(cmdBuf, &regions[0], &regions[1], &regions[2], &regions[3], m_size.width, m_size.height, 1);
stride{sbtAddress + 1u * progSize, progSize, progSize * 2}, // miss
stride{sbtAddress + 3u * progSize, progSize, progSize * 1}, // hit
stride{sbtAddress + 4u * progSize, progSize, progSize * 1}}; // callable
~~~~
Then we can call `traceRaysKHR`
~~~~ C++
cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2],
&strideAddresses[3], //
m_size.width, m_size.height, 1); //
~~~~ ~~~~
## Calling the Callable Shaders ## Calling the Callable Shaders

File diff suppressed because it is too large Load diff

View file

@ -19,17 +19,16 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
#include "nvvk/sbtwrapper_vk.hpp" #include "nvvk/sbtwrapper_vk.hpp"
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Simple rasterizer of OBJ objects // Simple rasterizer of OBJ objects
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` // - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
@ -37,25 +36,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -95,39 +90,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -137,19 +134,18 @@ public:
void createRtDescriptorSet(); void createRtDescriptorSet();
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstant struct RtPushConstant
{ {

View file

@ -23,18 +23,15 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "hello_vulkan.h"
#include "imgui.h" #include "imgui.h"
#include "hello_vulkan.h"
#include "imgui/imgui_camera_widget.h" #include "imgui/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -56,7 +54,7 @@ static void onErrorCallback(int error, const char* description)
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
ImGuiH::CameraWidget(); ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen)) if(ImGui::CollapsingHeader("Light"))
{ {
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0); ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
ImGui::SameLine(); ImGui::SameLine();
@ -104,8 +102,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -132,12 +129,13 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, false); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, false); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, false); contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
#endif #endif
contextInfo.addInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
@ -145,18 +143,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -171,11 +167,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -234,8 +229,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -244,28 +238,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -274,40 +269,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

View file

@ -128,9 +128,10 @@ attributes, we will store the offsets information of that geometry.
// The following is used to find the primitive mesh information in the CHIT // The following is used to find the primitive mesh information in the CHIT
std::vector<RtPrimitiveLookup> primLookup; std::vector<RtPrimitiveLookup> primLookup;
for(auto& primMesh : m_gltfScene.m_primMeshes) for(auto& primMesh : m_gltfScene.m_primMeshes)
{
primLookup.push_back({primMesh.firstIndex, primMesh.vertexOffset, primMesh.materialIndex}); primLookup.push_back({primMesh.firstIndex, primMesh.vertexOffset, primMesh.materialIndex});
m_rtPrimLookup = }
m_alloc.createBuffer(cmdBuf, primLookup, vk::BufferUsageFlagBits::eStorageBuffer); m_rtPrimLookup = m_alloc.createBuffer(cmdBuf, primLookup, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
~~~~ ~~~~
@ -145,35 +146,45 @@ The function is similar, only the input is different.
// //
auto HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim) auto HelloVulkan::primitiveToGeometry(const nvh::GltfPrimMesh& prim)
{ {
// Building part // BLAS builder requires raw device addresses.
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({m_vertexBuffer.buffer}); VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
vk::DeviceAddress indexAddress = m_device.getBufferAddress({m_indexBuffer.buffer}); info.buffer = m_vertexBuffer.buffer;
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
info.buffer = m_indexBuffer.buffer;
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; uint32_t maxPrimitiveCount = prim.indexCount / 3;
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(nvmath::vec3f));
triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress);
triangles.setTransformData({});
triangles.setMaxVertex(prim.vertexCount);
// Setting up the build info of the acceleration // Describe buffer as array of VertexObj.
vk::AccelerationStructureGeometryKHR asGeom; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit triangles.vertexData.deviceAddress = vertexAddress;
asGeom.geometry.setTriangles(triangles); triangles.vertexStride = sizeof(nvmath::vec3f);
// Describe index data (32-bit unsigned int)
triangles.indexType = VK_INDEX_TYPE_UINT32;
triangles.indexData.deviceAddress = indexAddress;
// Indicate identity transform by setting transformData to null device pointer.
//triangles.transformData = {};
triangles.maxVertex = prim.vertexCount;
vk::AccelerationStructureBuildRangeInfoKHR offset; // Identify the above data as containing opaque triangles.
offset.setFirstVertex(prim.vertexOffset); VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
offset.setPrimitiveCount(prim.indexCount / 3); asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
offset.setPrimitiveOffset(prim.firstIndex * sizeof(uint32_t)); asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
offset.setTransformOffset(0); asGeom.geometry.triangles = triangles;
nvvk::RaytracingBuilderKHR::Blas blas; VkAccelerationStructureBuildRangeInfoKHR offset;
blas.asGeometry.emplace_back(asGeom); offset.firstVertex = prim.vertexOffset;
blas.asBuildOffsetInfo.emplace_back(offset); offset.primitiveCount = prim.indexCount / 3;
return blas; offset.primitiveOffset = prim.firstIndex * sizeof(uint32_t);
offset.transformOffset = 0;
// Our blas is made from only one geometry, but could be made of many geometries
nvvk::RaytracingBuilderKHR::BlasInput input;
input.asGeometry.emplace_back(asGeom);
input.asBuildOffsetInfo.emplace_back(offset);
return input;
} }
~~~~ ~~~~
@ -207,11 +218,9 @@ each node, we will be pushing the instance Id (retrieve the matrix) and the mate
don't have a scene graph, we could loop over all drawable nodes. don't have a scene graph, we could loop over all drawable nodes.
~~~~C ~~~~C
std::vector<vk::Buffer> vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer, std::vector<VkBuffer> vertexBuffers = {m_vertexBuffer.buffer, m_normalBuffer.buffer, m_uvBuffer.buffer};
m_uvBuffer.buffer}; vkCmdBindVertexBuffers(cmdBuf, 0, static_cast<uint32_t>(vertexBuffers.size()), vertexBuffers.data(), offsets.data());
cmdBuf.bindVertexBuffers(0, static_cast<uint32_t>(vertexBuffers.size()), vertexBuffers.data(), vkCmdBindIndexBuffer(cmdBuf, m_indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
offsets.data());
cmdBuf.bindIndexBuffer(m_indexBuffer.buffer, 0, vk::IndexType::eUint32);
uint32_t idxNode = 0; uint32_t idxNode = 0;
for(auto& node : m_gltfScene.m_nodes) for(auto& node : m_gltfScene.m_nodes)
@ -220,10 +229,9 @@ don't have a scene graph, we could loop over all drawable nodes.
m_pushConstant.instanceId = idxNode++; m_pushConstant.instanceId = idxNode++;
m_pushConstant.materialId = primitive.materialIndex; m_pushConstant.materialId = primitive.materialIndex;
cmdBuf.pushConstants<ObjPushConstant>( vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
m_pipelineLayout, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, sizeof(ObjPushConstant), &m_pushConstant);
m_pushConstant); vkCmdDrawIndexed(cmdBuf, primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0);
cmdBuf.drawIndexed(primitive.indexCount, 1, primitive.firstIndex, primitive.vertexOffset, 0);
} }
~~~~ ~~~~
@ -234,12 +242,12 @@ In `createRtDescriptorSet()`, the only change we will add is the primitive info
the data when hitting a triangle. the data when hitting a triangle.
~~~~C ~~~~C
m_rtDescSetLayoutBind.addBinding( m_rtDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
vkDSLB(2, vkDT::eStorageBuffer, 1, vkSS::eClosestHitNV | vkSS::eAnyHitNV)); // Primitive info VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); // Primitive info
.... // ...
vk::DescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo primitiveInfoDesc{m_rtPrimLookup.buffer, 0, VK_WHOLE_SIZE};
.... // ...
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &primitiveInfoDesc)); writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 2, &primitiveInfoDesc));
~~~~ ~~~~

File diff suppressed because it is too large Load diff

View file

@ -18,13 +18,12 @@
*/ */
#pragma once #pragma once
#include <vulkan/vulkan.hpp>
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvh/gltfscene.hpp" #include "nvh/gltfscene.hpp"
@ -38,23 +37,20 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadScene(const std::string& filename); void loadScene(const std::string& filename);
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, tinygltf::Model& gltfModel); void createTextureImages(const VkCommandBuffer& cmdBuf, tinygltf::Model& gltfModel);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// Structure used for retrieving the primitive information in the closest hit // Structure used for retrieving the primitive information in the closest hit
// The gl_InstanceCustomIndexNV // The gl_InstanceCustomIndexNV
@ -87,12 +83,12 @@ public:
ObjPushConstant m_pushConstant; ObjPushConstant m_pushConstant;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
@ -105,20 +101,20 @@ public:
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
auto primitiveToGeometry(const nvh::GltfPrimMesh& prim); auto primitiveToGeometry(const nvh::GltfPrimMesh& prim);
@ -128,20 +124,20 @@ public:
void createRtDescriptorSet(); void createRtDescriptorSet();
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
void updateFrame(); void updateFrame();
void resetFrame(); void resetFrame();
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::SBTWrapper m_sbtWrapper; nvvk::SBTWrapper m_sbtWrapper;
struct RtPushConstant struct RtPushConstant
{ {

View file

@ -23,8 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -73,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -87,8 +86,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -115,9 +113,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -127,20 +125,20 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
vk::PhysicalDeviceShaderClockFeaturesKHR clockFeature; VkPhysicalDeviceShaderClockFeaturesKHR clockFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_EXTENSION_NAME, false, &clockFeature); contextInfo.addDeviceExtension(VK_KHR_SHADER_CLOCK_EXTENSION_NAME, false, &clockFeature);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -151,16 +149,14 @@ int main(int argc, char** argv)
// Use a compatible device // Use a compatible device
vkctx.initDevice(compatibleDevices[0], contextInfo); vkctx.initDevice(compatibleDevices[0], contextInfo);
// Create example // Create example
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -209,6 +205,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -217,8 +214,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -227,28 +223,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -257,40 +254,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

File diff suppressed because it is too large Load diff

View file

@ -18,13 +18,12 @@
*/ */
#pragma once #pragma once
#include <vulkan/vulkan.hpp>
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -36,13 +35,10 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
@ -50,8 +46,7 @@ public:
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures);
nvmath::mat4 getViewMatrix() { return CameraManip.getMatrix(); } nvmath::mat4 getViewMatrix() { return CameraManip.getMatrix(); }
@ -62,10 +57,10 @@ public:
return nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, nearZ, 1000.0f); return nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, nearZ, 1000.0f);
} }
void updateUniformBuffer(const vk::CommandBuffer&); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -130,39 +125,41 @@ public:
std::vector<Lantern> m_lanterns; std::vector<Lantern> m_lanterns;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -183,7 +180,7 @@ public:
void createRtShaderBindingTable(); void createRtShaderBindingTable();
void createLanternIndirectBuffer(); void createLanternIndirectBuffer();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
// Used to store lantern model, generated at runtime. // Used to store lantern model, generated at runtime.
const float m_lanternModelRadius = 0.125; const float m_lanternModelRadius = 0.125;
@ -194,22 +191,22 @@ public:
// Index of lantern's BLAS in the BLAS array stored in m_rtBuilder. // Index of lantern's BLAS in the BLAS array stored in m_rtBuilder.
size_t m_lanternBlasId; size_t m_lanternBlasId;
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind; nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
vk::DescriptorPool m_lanternIndirectDescPool; VkDescriptorPool m_lanternIndirectDescPool;
vk::DescriptorSetLayout m_lanternIndirectDescSetLayout; VkDescriptorSetLayout m_lanternIndirectDescSetLayout;
vk::DescriptorSet m_lanternIndirectDescSet; VkDescriptorSet m_lanternIndirectDescSet;
vk::PipelineLayout m_lanternIndirectCompPipelineLayout; VkPipelineLayout m_lanternIndirectCompPipelineLayout;
vk::Pipeline m_lanternIndirectCompPipeline; VkPipeline m_lanternIndirectCompPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
// Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color, // Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color,
// position, etc. from when doing lantern lighting passes. // position, etc. from when doing lantern lighting passes.

View file

@ -23,8 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -74,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -88,8 +87,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -118,7 +116,7 @@ int main(int argc, char** argv)
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -128,19 +126,19 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
&accelFeature); VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
vkctx.initInstance(contextInfo); vkctx.initInstance(contextInfo);
@ -150,16 +148,14 @@ int main(int argc, char** argv)
// Use a compatible device // Use a compatible device
vkctx.initDevice(compatibleDevices[0], contextInfo); vkctx.initDevice(compatibleDevices[0], contextInfo);
// Create example // Create example
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -223,6 +219,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -231,9 +228,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -242,28 +237,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -272,40 +268,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

File diff suppressed because it is too large Load diff

View file

@ -22,9 +22,9 @@
// #VKRay // #VKRay
// //
// Choosing the allocator to use // Choosing the allocator to use
//#define ALLOC_DMA #define ALLOC_DMA
//#define ALLOC_DEDICATED //#define ALLOC_DEDICATED
#define ALLOC_VMA //#define ALLOC_VMA
#include <nvvk/resourceallocator_vk.hpp> #include <nvvk/resourceallocator_vk.hpp>
#if defined(ALLOC_DMA) #if defined(ALLOC_DMA)
@ -37,7 +37,7 @@ using Allocator = nvvk::ResourceAllocatorVma;
using Allocator = nvvk::ResourceAllocatorDedicated; using Allocator = nvvk::ResourceAllocatorDedicated;
#endif #endif
#include "nvvk/appbase_vkpp.hpp" #include "nvvk/appbase_vk.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
@ -52,25 +52,21 @@ using Allocator = nvvk::ResourceAllocatorDedicated;
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -107,12 +103,12 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
@ -123,25 +119,26 @@ public:
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -151,25 +148,25 @@ public:
void createRtDescriptorSet(); void createRtDescriptorSet();
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::SBTWrapper m_sbtWrapper; nvvk::SBTWrapper m_sbtWrapper;
struct RtPushConstant struct RtPushConstant
{ {
nvmath::vec4f clearColor; nvmath::vec4f clearColor;
nvmath::vec3f lightPosition; nvmath::vec3f lightPosition;
float lightIntensity; float lightIntensity{100.0f};
int lightType; int lightType{0};
} m_rtPushConstants; } m_rtPushConstants;
}; };

View file

@ -24,8 +24,6 @@
#include <array> #include <array>
#include <random> #include <random>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -35,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -56,9 +53,8 @@ struct MilliTimer
void reset() { startTime = std::chrono::high_resolution_clock::now(); } void reset() { startTime = std::chrono::high_resolution_clock::now(); }
double elapse() double elapse()
{ {
auto now = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now();
auto t = auto t = std::chrono::duration_cast<std::chrono::microseconds>(now - startTime).count() / 1000.0;
std::chrono::duration_cast<std::chrono::microseconds>(now - startTime).count() / 1000.0;
startTime = now; startTime = now;
return t; return t;
} }
@ -75,6 +71,7 @@ struct MilliTimer
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -102,6 +99,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -116,8 +114,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -144,9 +141,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -158,17 +155,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -183,11 +179,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -199,7 +194,7 @@ int main(int argc, char** argv)
MilliTimer timer; MilliTimer timer;
// Creation of the example // Creation of the example
std::random_device rd; //Will be used to obtain a seed for the random number engine std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd() std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::normal_distribution<float> dis(1.0f, 1.0f); std::normal_distribution<float> dis(1.0f, 1.0f);
std::normal_distribution<float> disn(0.05f, 0.05f); std::normal_distribution<float> disn(0.05f, 0.05f);
@ -209,12 +204,11 @@ int main(int argc, char** argv)
HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back(); HelloVulkan::ObjInstance& inst = helloVk.m_objInstance.back();
float scale = fabsf(disn(gen)); float scale = fabsf(disn(gen));
nvmath::mat4f mat = nvmath::mat4f mat = nvmath::translation_mat4(nvmath::vec3f{dis(gen), 2.0f + dis(gen), dis(gen)});
nvmath::translation_mat4(nvmath::vec3f{dis(gen), 2.0f + dis(gen), dis(gen)}); mat = mat * nvmath::rotation_mat4_x(dis(gen));
mat = mat * nvmath::rotation_mat4_x(dis(gen)); mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale));
mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale)); inst.transform = mat;
inst.transform = mat; inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform)));
inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform)));
} }
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
@ -259,6 +253,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -267,8 +262,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -277,28 +271,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -307,40 +302,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

View file

@ -71,25 +71,27 @@ The following implementation will create 2.000.000 spheres at random positions a
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating all spheres // Creating all spheres
// //
void HelloVulkan::createSpheres() void HelloVulkan::createSpheres(uint32_t nbSpheres)
{ {
std::random_device rd{}; std::random_device rd{};
std::mt19937 gen{rd()}; std::mt19937 gen{rd()};
std::normal_distribution<float> xzd{0.f, 5.f}; std::normal_distribution<float> xzd{0.f, 5.f};
std::normal_distribution<float> yd{3.f, 1.f}; std::normal_distribution<float> yd{6.f, 3.f};
std::uniform_real_distribution<float> radd{.05f, .2f}; std::uniform_real_distribution<float> radd{.05f, .2f};
// All spheres // All spheres
Sphere s; m_spheres.resize(nbSpheres);
for(uint32_t i = 0; i < 2000000; i++) for(uint32_t i = 0; i < nbSpheres; i++)
{ {
s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen)); Sphere s;
s.radius = radd(gen); s.center = nvmath::vec3f(xzd(gen), yd(gen), xzd(gen));
m_spheres.emplace_back(s); s.radius = radd(gen);
m_spheres[i] = std::move(s);
} }
// Axis aligned bounding box of each sphere // Axis aligned bounding box of each sphere
std::vector<Aabb> aabbs; std::vector<Aabb> aabbs;
aabbs.reserve(nbSpheres);
for(const auto& s : m_spheres) for(const auto& s : m_spheres)
{ {
Aabb aabb; Aabb aabb;
@ -99,28 +101,28 @@ void HelloVulkan::createSpheres()
} }
// Creating two materials // Creating two materials
MatrialObj mat; MaterialObj mat;
mat.diffuse = vec3f(0, 1, 1); mat.diffuse = nvmath::vec3f(0, 1, 1);
std::vector<MatrialObj> materials; std::vector<MaterialObj> materials;
std::vector<int> matIdx; std::vector<int> matIdx(nbSpheres);
materials.emplace_back(mat); materials.emplace_back(mat);
mat.diffuse = vec3f(1, 1, 0); mat.diffuse = nvmath::vec3f(1, 1, 0);
materials.emplace_back(mat); materials.emplace_back(mat);
// Assign a material to each sphere // Assign a material to each sphere
for(size_t i = 0; i < m_spheres.size(); i++) for(size_t i = 0; i < m_spheres.size(); i++)
{ {
matIdx.push_back(i % 2); matIdx[i] = i % 2;
} }
// Creating all buffers // Creating all buffers
using vkBU = vk::BufferUsageFlagBits; using vkBU = VkBufferUsageFlagBits;
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
auto cmdBuf = genCmdBuf.createCommandBuffer(); auto cmdBuf = genCmdBuf.createCommandBuffer();
m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, vkBU::eStorageBuffer); m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, vkBU::eShaderDeviceAddress); m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, vkBU::eStorageBuffer); m_spheresMatIndexBuffer = m_alloc.createBuffer(cmdBuf, matIdx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, vkBU::eStorageBuffer); m_spheresMatColorBuffer = m_alloc.createBuffer(cmdBuf, materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
// Debug information // Debug information
@ -148,39 +150,32 @@ What is changing compare to triangle primitive is the Aabb data (see Aabb struct
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Returning the ray tracing geometry used for the BLAS, containing all spheres // Returning the ray tracing geometry used for the BLAS, containing all spheres
// //
nvvk::RaytracingBuilderKHR::Blas HelloVulkan::sphereToVkGeometryKHR() nvvk::RaytracingBuilderKHR::BlasInput HelloVulkan::sphereToVkGeometryKHR()
{ {
vk::AccelerationStructureCreateGeometryTypeInfoKHR asCreate; VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
asCreate.setGeometryType(vk::GeometryTypeKHR::eAabbs); info.buffer = m_spheresAabbBuffer.buffer;
asCreate.setMaxPrimitiveCount((uint32_t)m_spheres.size()); // Nb triangles VkDeviceAddress dataAddress = vkGetBufferDeviceAddress(m_device, &info);
asCreate.setIndexType(vk::IndexType::eNoneKHR);
asCreate.setVertexFormat(vk::Format::eUndefined);
asCreate.setMaxVertexCount(0);
asCreate.setAllowsTransforms(VK_FALSE); // No adding transformation matrices
VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR};
aabbs.data.deviceAddress = dataAddress;
aabbs.stride = sizeof(Aabb);
vk::DeviceAddress dataAddress = m_device.getBufferAddress({m_spheresAabbBuffer.buffer}); // Setting up the build info of the acceleration (C version, c++ gives wrong type)
vk::AccelerationStructureGeometryAabbsDataKHR aabbs; VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
aabbs.setData(dataAddress); asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
aabbs.setStride(sizeof(Aabb)); asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
asGeom.geometry.aabbs = aabbs;
// Setting up the build info of the acceleration VkAccelerationStructureBuildRangeInfoKHR offset{};
vk::AccelerationStructureGeometryKHR asGeom; offset.firstVertex = 0;
asGeom.setGeometryType(asCreate.geometryType); offset.primitiveCount = (uint32_t)m_spheres.size(); // Nb aabb
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); offset.primitiveOffset = 0;
asGeom.geometry.setAabbs(aabbs); offset.transformOffset = 0;
vk::AccelerationStructureBuildOffsetInfoKHR offset; nvvk::RaytracingBuilderKHR::BlasInput input;
offset.setFirstVertex(0); input.asGeometry.emplace_back(asGeom);
offset.setPrimitiveCount(asCreate.maxPrimitiveCount); input.asBuildOffsetInfo.emplace_back(offset);
offset.setPrimitiveOffset(0); return input;
offset.setTransformOffset(0);
nvvk::RaytracingBuilderKHR::Blas blas;
blas.asGeometry.emplace_back(asGeom);
blas.asCreateGeometryInfo.emplace_back(asCreate);
blas.asBuildOffsetInfo.emplace_back(offset);
return blas;
} }
~~~~ ~~~~
@ -212,7 +207,7 @@ The function `createBottomLevelAS()` is creating a BLAS per OBJ, the following m
void HelloVulkan::createBottomLevelAS() void HelloVulkan::createBottomLevelAS()
{ {
// BLAS - Storing each primitive in a geometry // BLAS - Storing each primitive in a geometry
std::vector<nvvk::RaytracingBuilderKHR::Blas> allBlas; std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
allBlas.reserve(m_objModel.size()); allBlas.reserve(m_objModel.size());
for(const auto& obj : m_objModel) for(const auto& obj : m_objModel)
{ {
@ -228,7 +223,7 @@ void HelloVulkan::createBottomLevelAS()
allBlas.emplace_back(blas); allBlas.emplace_back(blas);
} }
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
~~~~ ~~~~
@ -261,19 +256,19 @@ In function `createDescriptorSetLayout()`, the addition of the material and mate
~~~~ C++ ~~~~ C++
// Materials (binding = 1) // Materials (binding = 1)
m_descSetLayoutBind.emplace_back(vkDS(1, vkDT::eStorageBuffer, nbObj + 1, m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj+1,
vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR)); VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
// Materials Index (binding = 4) // Materials Index (binding = 4)
m_descSetLayoutBind.emplace_back( m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj +1,
vkDS(4, vkDT::eStorageBuffer, nbObj + 1, vkSS::eFragment | vkSS::eClosestHitKHR)); VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
~~~~ ~~~~
And the new buffer holding the spheres And the new buffer holding the spheres
~~~~ C++ ~~~~ C++
// Storing spheres (binding = 7) // Storing spheres (binding = 7)
m_descSetLayoutBind.emplace_back( // m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
vkDS(7, vkDT::eStorageBuffer, 1, vkSS::eClosestHitKHR | vkSS::eIntersectionKHR)); VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR);
~~~~ ~~~~
The function `updateDescriptorSet()` which is writing the values of the buffer need also to be modified. The function `updateDescriptorSet()` which is writing the values of the buffer need also to be modified.
@ -281,22 +276,22 @@ The function `updateDescriptorSet()` which is writing the values of the buffer n
At the end of the loop on all models, lets add the new material and material index. At the end of the loop on all models, lets add the new material and material index.
~~~~ C++ ~~~~ C++
for(auto& model : m_objModel) for(auto& m : m_objModel)
{ {
dbiMat.emplace_back(model.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiMatIdx.emplace_back(model.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiVert.emplace_back(model.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiIdx.emplace_back(model.indexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
} }
dbiMat.emplace_back(m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMat.push_back({m_spheresMatColorBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiMatIdx.emplace_back(m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMatIdx.push_back({m_spheresMatIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
~~~~ ~~~~
Then write the buffer for the spheres Then write the buffer for the spheres
~~~~ C++ ~~~~ C++
vk::DescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, dbiSpheres)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &dbiSpheres));
~~~~ ~~~~
## Intersection Shader ## Intersection Shader
@ -306,44 +301,33 @@ The intersection shader is added to the Hit Group `VK_RAY_TRACING_SHADER_GROUP_T
Here is how the two hit group looks like: Here is how the two hit group looks like:
~~~~ C++ ~~~~ C++
// Hit Group0 - Closest Hit enum StageIndices
vk::ShaderModule chitSM =
nvvk::createShaderModule(m_device, //
nvh::loadFile("shaders/raytrace.rchit.spv", true, paths));
{ {
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, eRaygen,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, eMiss,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; eMiss2,
hg.setClosestHitShader(static_cast<uint32_t>(stages.size())); eClosestHit,
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"}); eClosestHit2,
m_rtShaderGroups.push_back(hg); eIntersection,
} eShaderGroupCount
};
// Hit Group1 - Closest Hit + Intersection (procedural) // Closest hit
vk::ShaderModule chit2SM = stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
nvvk::createShaderModule(m_device, // stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths)); stages[eClosestHit2] = stage;
vk::ShaderModule rintSM = // Intersection
nvvk::createShaderModule(m_device, // stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
nvh::loadFile("shaders/raytrace.rint.spv", true, paths)); stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
{ stages[eIntersection] = stage;
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
m_rtShaderGroups.push_back(hg);
}
~~~~ ~~~~
And destroy the two shaders at the end
~~~~ C++ ~~~~ C++
m_device.destroy(chit2SM); // closest hit shader + Intersection (Hit group 2)
m_device.destroy(rintSM); group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
group.closestHitShader = eClosestHit2;
group.intersectionShader = eIntersection;
m_rtShaderGroups.push_back(group);
~~~~ ~~~~
### raycommon.glsl ### raycommon.glsl

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -35,25 +35,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -90,39 +86,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -133,26 +131,26 @@ public:
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void createRtShaderBindingTable(); void createRtShaderBindingTable();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstant struct RtPushConstant
{ {
nvmath::vec4f clearColor; nvmath::vec4f clearColor;
nvmath::vec3f lightPosition; nvmath::vec3f lightPosition;
float lightIntensity; float lightIntensity{100.0f};
int lightType; int lightType{0};
} m_rtPushConstants; } m_rtPushConstants;

View file

@ -23,8 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -74,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -88,8 +87,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -116,9 +114,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -130,18 +128,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -156,11 +152,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -212,6 +207,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -220,8 +216,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -230,28 +225,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -260,40 +256,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -35,25 +35,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -90,39 +86,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -133,28 +131,28 @@ public:
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void createRtShaderBindingTable(); void createRtShaderBindingTable();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
void resetFrame(); void resetFrame();
void updateFrame(); void updateFrame();
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
int m_maxFrames{10}; int m_maxFrames{10};
struct RtPushConstant struct RtPushConstant
{ {
nvmath::vec4f clearColor; nvmath::vec4f clearColor;
nvmath::vec3f lightPosition; nvmath::vec3f lightPosition;
float lightIntensity; float lightIntensity{100.0f};
int lightType; int lightType{0};
int frame{0}; int frame{0};
} m_rtPushConstants; } m_rtPushConstants;
}; };

View file

@ -23,8 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -55,9 +53,8 @@ static void onErrorCallback(int error, const char* description)
// Extra UI // Extra UI
void renderUI(HelloVulkan& helloVk) void renderUI(HelloVulkan& helloVk)
{ {
bool changed = false; bool changed{false};
ImGuiH::CameraWidget();
changed |= ImGuiH::CameraWidget();
if(ImGui::CollapsingHeader("Light")) if(ImGui::CollapsingHeader("Light"))
{ {
auto& pc = helloVk.m_pushConstant; auto& pc = helloVk.m_pushConstant;
@ -81,6 +78,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -95,8 +93,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -123,9 +120,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -138,17 +135,15 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -163,11 +158,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -219,6 +213,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -232,8 +227,7 @@ int main(int argc, char** argv)
helloVk.resetFrame(); helloVk.resetFrame();
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -242,28 +236,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -272,40 +267,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")
@ -33,7 +33,7 @@ include_directories(${TUTO_KHR_DIR}/common)
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
compile_glsl_directory( compile_glsl_directory(
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
VULKAN_TARGET "vulkan1.2" VULKAN_TARGET "vulkan1.2"
) )

View file

@ -59,18 +59,31 @@ void main()
This new shader needs to be added to the raytracing pipeline. So, in `createRtPipeline` in `hello_vulkan.cpp`, load the new closest hit shader immediately after loading the first one. This new shader needs to be added to the raytracing pipeline. So, in `createRtPipeline` in `hello_vulkan.cpp`, load the new closest hit shader immediately after loading the first one.
~~~~ C++ ~~~~ C++
vk::ShaderModule chit2SM = enum StageIndices
nvvk::createShaderModule(m_device, // {
nvh::loadFile("shaders/raytrace2.rchit.spv", true, paths, true)); eRaygen,
eMiss,
eMiss2,
eClosestHit,
eClosestHit2,
eShaderGroupCount
};
// ...
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
stages[eClosestHit2] = stage;
~~~~ ~~~~
Then add a new hit group group immediately after adding the first hit group: Then add a new hit group group immediately after adding the first hit group:
~~~~ C++ ~~~~ C++
// Second group // Hit 2
hg.setClosestHitShader(static_cast<uint32_t>(stages.size())); group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"}); group.generalShader = VK_SHADER_UNUSED_KHR;
m_rtShaderGroups.push_back(hg); group.closestHitShader = eClosestHit2;
m_rtShaderGroups.push_back(group);
~~~~ ~~~~
### `raytrace.rgen` ### `raytrace.rgen`
@ -200,6 +213,36 @@ In `main`, after we set which hit group an instance will use, we can add the dat
### `HelloVulkan::createRtShaderBindingTable` ### `HelloVulkan::createRtShaderBindingTable`
**NEW**
The creation of the shading binding table as it was done, was using hardcoded offsets and potentially could lead to errors.
Instead, the new code uses the `nvvk::SBTWraper` that uses the ray tracing pipeline and the `VkRayTracingPipelineCreateInfoKHR` to
create the SBT information.
The wrapper will find the handles for each group and will add the
data `m_hitShaderRecord` to the Hit group.
```` C
// Find handle indices and add data
m_sbtWrapper.addIndices(rayPipelineInfo);
m_sbtWrapper.addData(SBTWrapper::eHit, 1, m_hitShaderRecord[0]);
m_sbtWrapper.addData(SBTWrapper::eHit, 2, m_hitShaderRecord[1]);
m_sbtWrapper.create(m_rtPipeline);
````
The buffer for Hit will have the following layout
```
| handle | handle,data | handle,data |
```
The wrapper will make sure the stride covers the largest data and is aligned
based on the GPU properties.
**OLD - for reference**
Since we are no longer compacting all handles in a continuous buffer, we need to fill the SBT as described above. Since we are no longer compacting all handles in a continuous buffer, we need to fill the SBT as described above.
After retrieving the handles of all 5 groups (raygen, miss, miss shadow, hit0, and hit1) After retrieving the handles of all 5 groups (raygen, miss, miss shadow, hit0, and hit1)
@ -255,16 +298,27 @@ Then write the new SBT like this, where only Hit 1 has extra data.
Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sbtBuffer`: Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sbtBuffer`:
~~~~ C++ ~~~~ C++
m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR); m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR);
~~~~ ~~~~
### `raytrace` ### `raytrace`
**NEW**
The mvvk::SBTWrapper gives use the information without having to compute the `VkStridedDeviceAddressRegionKHR`
``` C
auto& regions = m_sbtWrapper.getRegions();
vkCmdTraceRaysKHR(cmdBuf, &regions[0], &regions[1], &regions[2], &regions[3], m_size.width, m_size.height, 1);
```
**OLD**
Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`. Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`.
~~~~ C++ ~~~~ C++
vk::DeviceSize hitGroupSize = VkDeviceSize hitGroupSize =
nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer),
m_rtProperties.shaderGroupBaseAlignment); m_rtProperties.shaderGroupBaseAlignment);
~~~~ ~~~~
@ -272,7 +326,7 @@ Finally, since the size of the hit group is now larger than just the handle, we
The stride device address will be modified like this: The stride device address will be modified like this:
~~~~ C++ ~~~~ C++
using Stride = vk::StridedDeviceAddressRegionKHR; using Stride = VkStridedDeviceAddressRegionKHR;
std::array<Stride, 4> strideAddresses{ std::array<Stride, 4> strideAddresses{
Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen
Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss
@ -280,7 +334,7 @@ The stride device address will be modified like this:
Stride{0u, 0u, 0u}}; // callable Stride{0u, 0u, 0u}}; // callable
~~~~ ~~~~
!!! Note: **Note:**
The result should now show both `wuson` models with a yellow color. The result should now show both `wuson` models with a yellow color.
![](images/manyhits4.png) ![](images/manyhits4.png)

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -37,25 +37,21 @@ using nvvk::SBTWrapper;
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -93,39 +89,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -136,20 +134,19 @@ public:
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void createRtShaderBindingTable(); void createRtShaderBindingTable();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstant struct RtPushConstant
{ {
nvmath::vec4f clearColor; nvmath::vec4f clearColor;

View file

@ -23,19 +23,19 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui/imgui_camera_widget.h" #include "imgui/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -43,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -70,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -84,8 +86,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -112,9 +113,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -126,18 +127,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -152,11 +151,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -169,10 +167,10 @@ int main(int argc, char** argv)
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0))); nvmath::translation_mat4(nvmath::vec3f(-1, 0, 0)));
HelloVulkan::ObjInstance inst = helloVk.m_objInstance[0]; // Instance the wuson object HelloVulkan::ObjInstance inst = helloVk.m_objInstance[0]; // Instance the Wuson object
inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0)); inst.transform = nvmath::translation_mat4(nvmath::vec3f(1, 0, 0));
inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform)); inst.transformIT = nvmath::transpose(nvmath::invert(inst.transform));
helloVk.m_objInstance.push_back(inst); // Adding an instance of the wuson helloVk.m_objInstance.push_back(inst); // Adding an instance of the Wuson
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
@ -180,8 +178,8 @@ int main(int argc, char** argv)
helloVk.m_hitShaderRecord.resize(2); helloVk.m_hitShaderRecord.resize(2);
helloVk.m_hitShaderRecord[0].color = nvmath::vec4f(0, 1, 0, 0); // Green helloVk.m_hitShaderRecord[0].color = nvmath::vec4f(0, 1, 0, 0); // Green
helloVk.m_hitShaderRecord[1].color = nvmath::vec4f(0, 1, 1, 0); // Cyan helloVk.m_hitShaderRecord[1].color = nvmath::vec4f(0, 1, 1, 0); // Cyan
helloVk.m_objInstance[0].hitgroup = 1; // wuson 0 helloVk.m_objInstance[0].hitgroup = 1; // Wuson 0
helloVk.m_objInstance[1].hitgroup = 2; // wuson 1 helloVk.m_objInstance[1].hitgroup = 2; // Wuson 1
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
@ -197,7 +195,7 @@ int main(int argc, char** argv)
helloVk.createTopLevelAS(); helloVk.createTopLevelAS();
helloVk.createRtDescriptorSet(); helloVk.createRtDescriptorSet();
helloVk.createRtPipeline(); helloVk.createRtPipeline();
helloVk.createRtShaderBindingTable(); //helloVk.createRtShaderBindingTable();
helloVk.createPostDescriptor(); helloVk.createPostDescriptor();
helloVk.createPostPipeline(); helloVk.createPostPipeline();
@ -222,6 +220,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -230,8 +229,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -240,28 +238,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -270,40 +269,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")

View file

@ -26,14 +26,14 @@ First, let's remove all extra code
Remove most functions and members to keep only what is need to create the acceleration structure: Remove most functions and members to keep only what is need to create the acceleration structure:
~~~~ C++ ~~~~ C++
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
nvvk::RaytracingBuilderKHR::Blas objectToVkGeometryKHR(const ObjModel& model); auto objectToVkGeometryKHR(const ObjModel& model);
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
vk::PhysicalDeviceRayTracingPropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
~~~~ ~~~~
### hello_vulkan (source) ### hello_vulkan (source)
@ -58,11 +58,11 @@ m_descSetLayoutBind.emplace_back( //
In `HelloVulkan::updateDescriptorSet`, write the value to the descriptor set. In `HelloVulkan::updateDescriptorSet`, write the value to the descriptor set.
~~~~ C++ ~~~~ C++
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
descASInfo.setAccelerationStructureCount(1); descASInfo.accelerationStructureCount = 1;
descASInfo.setPAccelerationStructures(&tlas); descASInfo.pAccelerationStructures = &tlas;
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, descASInfo)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo));
~~~~ ~~~~

View file

@ -19,23 +19,24 @@
#include <sstream> #include <sstream>
#include <vulkan/vulkan.hpp>
extern std::vector<std::string> defaultSearchPaths;
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "obj_loader.h" #include "obj_loader.h"
#include "stb_image.h" #include "stb_image.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "nvh/alignment.hpp"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/images_vk.hpp" #include "nvvk/images_vk.hpp"
#include "nvvk/pipeline_vk.hpp" #include "nvvk/pipeline_vk.hpp"
#include "nvh/fileoperations.hpp"
#include "nvvk/commands_vk.hpp"
#include "nvvk/renderpasses_vk.hpp" #include "nvvk/renderpasses_vk.hpp"
#include "nvvk/shaders_vk.hpp"
extern std::vector<std::string> defaultSearchPaths;
// Holding the camera matrices // Holding the camera matrices
@ -48,17 +49,15 @@ struct CameraMatrices
nvmath::mat4f projInverse; nvmath::mat4f projInverse;
}; };
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Keep the handle on the device // Keep the handle on the device
// Initialize the tool to do all our allocations: buffers, images // Initialize the tool to do all our allocations: buffers, images
// //
void HelloVulkan::setup(const vk::Instance& instance, void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily)
{ {
AppBase::setup(instance, device, physicalDevice, queueFamily); AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
m_alloc.init(device, physicalDevice); m_alloc.init(instance, device, physicalDevice);
m_debug.setup(m_device); m_debug.setup(m_device);
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
} }
@ -66,46 +65,46 @@ void HelloVulkan::setup(const vk::Instance& instance,
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Called at each frame to update the camera matrix // Called at each frame to update the camera matrix
// //
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf) void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
{ {
// Prepare new UBO contents on host. // Prepare new UBO contents on host.
const float aspectRatio = m_size.width / static_cast<float>(m_size.height); const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
CameraMatrices hostUBO = {}; CameraMatrices hostUBO = {};
hostUBO.view = CameraManip.getMatrix(); hostUBO.view = CameraManip.getMatrix();
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f); hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). // hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewInverse = nvmath::invert(hostUBO.view); hostUBO.viewInverse = nvmath::invert(hostUBO.view);
// #VKRay // #VKRay
hostUBO.projInverse = nvmath::invert(hostUBO.proj); hostUBO.projInverse = nvmath::invert(hostUBO.proj);
// UBO on the device, and what stages access it. // UBO on the device, and what stages access it.
vk::Buffer deviceUBO = m_cameraMat.buffer; VkBuffer deviceUBO = m_cameraMat.buffer;
auto uboUsageStages = auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
// Ensure that the modified UBO is not visible to previous frames. // Ensure that the modified UBO is not visible to previous frames.
vk::BufferMemoryBarrier beforeBarrier; VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead); beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite); beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
beforeBarrier.setBuffer(deviceUBO); beforeBarrier.buffer = deviceUBO;
beforeBarrier.setOffset(0); beforeBarrier.offset = 0;
beforeBarrier.setSize(sizeof hostUBO); beforeBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer, vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {}); nullptr, 1, &beforeBarrier, 0, nullptr);
// Schedule the host-to-device upload. (hostUBO is copied into the cmd // Schedule the host-to-device upload. (hostUBO is copied into the cmd
// buffer so it is okay to deallocate when the function returns). // buffer so it is okay to deallocate when the function returns).
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO); vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
// Making sure the updated UBO will be visible. // Making sure the updated UBO will be visible.
vk::BufferMemoryBarrier afterBarrier; VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead); afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
afterBarrier.setBuffer(deviceUBO); afterBarrier.buffer = deviceUBO;
afterBarrier.setOffset(0); afterBarrier.offset = 0;
afterBarrier.setSize(sizeof hostUBO); afterBarrier.size = sizeof(hostUBO);
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages, vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {}); nullptr, 1, &afterBarrier, 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -113,36 +112,25 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
// //
void HelloVulkan::createDescriptorSetLayout() void HelloVulkan::createDescriptorSetLayout()
{ {
using vkDS = vk::DescriptorSetLayoutBinding;
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
auto nbTxt = static_cast<uint32_t>(m_textures.size()); auto nbTxt = static_cast<uint32_t>(m_textures.size());
auto nbObj = static_cast<uint32_t>(m_objModel.size()); auto nbObj = static_cast<uint32_t>(m_objModel.size());
// Camera matrices (binding = 0) // Camera matrices (binding = 0)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex | vkSS::eRaygenKHR));
// Materials (binding = 1) // Materials (binding = 1)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
// Scene description (binding = 2) // Scene description (binding = 2)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment | vkSS::eClosestHitKHR));
// Textures (binding = 3) // Textures (binding = 3)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment | vkSS::eClosestHitKHR));
// Materials (binding = 4) // Materials (binding = 4)
m_descSetLayoutBind.addBinding( m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment | vkSS::eClosestHitKHR));
// Storing vertices (binding = 5) // Storing vertices (binding = 5)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(5, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
// Storing indices (binding = 6) // Storing indices (binding = 6)
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(6, vkDT::eStorageBuffer, nbObj, vkSS::eClosestHitKHR));
// The top level acceleration structure // The top level acceleration structure
m_descSetLayoutBind.addBinding( // m_descSetLayoutBind.addBinding(7, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
vkDS(7, vkDT::eAccelerationStructureKHR, 1, vkSS::eFragment));
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
m_descPool = m_descSetLayoutBind.createPool(m_device, 1); m_descPool = m_descSetLayoutBind.createPool(m_device, 1);
@ -154,25 +142,25 @@ void HelloVulkan::createDescriptorSetLayout()
// //
void HelloVulkan::updateDescriptorSet() void HelloVulkan::updateDescriptorSet()
{ {
std::vector<vk::WriteDescriptorSet> writes; std::vector<VkWriteDescriptorSet> writes;
// Camera matrices and scene description // Camera matrices and scene description
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE}; VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
// All material buffers, 1 buffer per OBJ // All material buffers, 1 buffer per OBJ
std::vector<vk::DescriptorBufferInfo> dbiMat; std::vector<VkDescriptorBufferInfo> dbiMat;
std::vector<vk::DescriptorBufferInfo> dbiMatIdx; std::vector<VkDescriptorBufferInfo> dbiMatIdx;
std::vector<vk::DescriptorBufferInfo> dbiVert; std::vector<VkDescriptorBufferInfo> dbiVert;
std::vector<vk::DescriptorBufferInfo> dbiIdx; std::vector<VkDescriptorBufferInfo> dbiIdx;
for(auto& obj : m_objModel) for(auto& m : m_objModel)
{ {
dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE); dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
@ -180,55 +168,53 @@ void HelloVulkan::updateDescriptorSet()
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 6, dbiIdx.data()));
// All texture samplers // All texture samplers
std::vector<vk::DescriptorImageInfo> diit; std::vector<VkDescriptorImageInfo> diit;
for(auto& texture : m_textures) for(auto& texture : m_textures)
{ {
diit.emplace_back(texture.descriptor); diit.emplace_back(texture.descriptor);
} }
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data())); writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo; VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
descASInfo.setAccelerationStructureCount(1); descASInfo.accelerationStructureCount = 1;
descASInfo.setPAccelerationStructures(&tlas); descASInfo.pAccelerationStructures = &tlas;
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo)); writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 7, &descASInfo));
// Writing the information // Writing the information
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr); vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating the pipeline layout // Creating the pipeline layout
// //
void HelloVulkan::createGraphicsPipeline() void HelloVulkan::createGraphicsPipeline()
{ {
using vkSS = vk::ShaderStageFlagBits; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
sizeof(ObjPushConstant)};
// Creating the Pipeline Layout // Creating the Pipeline Layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
vk::DescriptorSetLayout descSetLayout(m_descSetLayout); createInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setSetLayoutCount(1); createInfo.pSetLayouts = &m_descSetLayout;
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout); createInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); createInfo.pPushConstantRanges = &pushConstantRanges;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
// Creating the Pipeline // Creating the Pipeline
std::vector<std::string> paths = defaultSearchPaths; std::vector<std::string> paths = defaultSearchPaths;
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
gpb.depthStencilState.depthTestEnable = true; gpb.depthStencilState.depthTestEnable = true;
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex); gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment); gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
gpb.addBindingDescription({0, sizeof(VertexObj)}); gpb.addBindingDescription({0, sizeof(VertexObj)});
gpb.addAttributeDescriptions({ gpb.addAttributeDescriptions({
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))}, {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))}, {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))}, {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))}, {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
}); });
m_graphicsPipeline = gpb.createPipeline(); m_graphicsPipeline = gpb.createPipeline();
@ -240,8 +226,6 @@ void HelloVulkan::createGraphicsPipeline()
// //
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform) void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
{ {
using vkBU = vk::BufferUsageFlagBits;
LOGI("Loading File: %s \n", filename.c_str()); LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader; ObjLoader loader;
loader.loadModel(filename); loader.loadModel(filename);
@ -265,18 +249,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size()); model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
// Create the buffers on Device and copy vertices, indices and materials // Create the buffers on Device and copy vertices, indices and materials
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
model.vertexBuffer = VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
m_alloc.createBuffer(cmdBuf, loader.m_vertices, | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR); model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
model.indexBuffer = model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
m_alloc.createBuffer(cmdBuf, loader.m_indices, model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
// Creates all textures found // Creates all textures found
createTextureImages(cmdBuf, loader.m_textures); createTextureImages(cmdBuf, loader.m_textures);
cmdBufGet.submitAndWait(cmdBuf); cmdBufGet.submitAndWait(cmdBuf);
@ -292,17 +272,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
m_objInstance.emplace_back(instance); m_objInstance.emplace_back(instance);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating the uniform buffer holding the camera matrices // Creating the uniform buffer holding the camera matrices
// - Buffer is host visible // - Buffer is host visible
// //
void HelloVulkan::createUniformBuffer() void HelloVulkan::createUniformBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits; m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
using vkMP = vk::MemoryPropertyFlagBits; VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat"); m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
} }
@ -314,11 +292,10 @@ void HelloVulkan::createUniformBuffer()
// //
void HelloVulkan::createSceneDescriptionBuffer() void HelloVulkan::createSceneDescriptionBuffer()
{ {
using vkBU = vk::BufferUsageFlagBits;
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
auto cmdBuf = cmdGen.createCommandBuffer(); auto cmdBuf = cmdGen.createCommandBuffer();
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer); m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
cmdGen.submitAndWait(cmdBuf); cmdGen.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc"); m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
@ -327,15 +304,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating all textures and samplers // Creating all textures and samplers
// //
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf, void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
const std::vector<std::string>& textures)
{ {
using vkIU = vk::ImageUsageFlagBits; VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCreateInfo.maxLod = FLT_MAX;
vk::SamplerCreateInfo samplerCreateInfo{ VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
samplerCreateInfo.setMaxLod(FLT_MAX);
vk::Format format = vk::Format::eR8G8B8A8Srgb;
// If no textures are present, create a dummy one to accommodate the pipeline layout // If no textures are present, create a dummy one to accommodate the pipeline layout
if(textures.empty() && m_textures.empty()) if(textures.empty() && m_textures.empty())
@ -343,18 +320,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
nvvk::Texture texture; nvvk::Texture texture;
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u}; std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
vk::DeviceSize bufferSize = sizeof(color); VkDeviceSize bufferSize = sizeof(color);
auto imgSize = vk::Extent2D(1, 1); auto imgSize = VkExtent2D{1, 1};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
// Creating the VKImage // Creating the dummy texture
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vk::ImageLayout::eShaderReadOnlyOptimal);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
else else
@ -367,8 +343,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
o << "media/textures/" << texture; o << "media/textures/" << texture;
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
stbi_uc* stbi_pixels = stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u}; std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
@ -381,16 +356,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
pixels = reinterpret_cast<stbi_uc*>(color.data()); pixels = reinterpret_cast<stbi_uc*>(color.data());
} }
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4; VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
auto imgSize = vk::Extent2D(texWidth, texHeight); auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true); auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
{ {
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
vk::ImageViewCreateInfo ivInfo = VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
m_textures.push_back(texture); m_textures.push_back(texture);
} }
@ -405,10 +379,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
// //
void HelloVulkan::destroyResources() void HelloVulkan::destroyResources()
{ {
m_device.destroy(m_graphicsPipeline); vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
m_device.destroy(m_pipelineLayout); vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
m_device.destroy(m_descPool); vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
m_device.destroy(m_descSetLayout); vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
m_alloc.destroy(m_cameraMat); m_alloc.destroy(m_cameraMat);
m_alloc.destroy(m_sceneDesc); m_alloc.destroy(m_sceneDesc);
@ -426,14 +401,15 @@ void HelloVulkan::destroyResources()
} }
//#Post //#Post
m_device.destroy(m_postPipeline);
m_device.destroy(m_postPipelineLayout);
m_device.destroy(m_postDescPool);
m_device.destroy(m_postDescSetLayout);
m_alloc.destroy(m_offscreenColor); m_alloc.destroy(m_offscreenColor);
m_alloc.destroy(m_offscreenDepth); m_alloc.destroy(m_offscreenDepth);
m_device.destroy(m_offscreenRenderPass); vkDestroyPipeline(m_device, m_postPipeline, nullptr);
m_device.destroy(m_offscreenFramebuffer); vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
// #VKRay // #VKRay
m_rtBuilder.destroy(); m_rtBuilder.destroy();
@ -443,32 +419,31 @@ void HelloVulkan::destroyResources()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Drawing the scene in raster mode // Drawing the scene in raster mode
// //
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf) void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
{ {
using vkPBP = vk::PipelineBindPoint; VkDeviceSize offset{0};
using vkSS = vk::ShaderStageFlagBits;
vk::DeviceSize offset{0};
m_debug.beginLabel(cmdBuf, "Rasterize"); m_debug.beginLabel(cmdBuf, "Rasterize");
// Dynamic Viewport // Dynamic Viewport
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); setViewport(cmdBuf);
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
// Drawing all triangles // Drawing all triangles
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {}); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
for(int i = 0; i < m_objInstance.size(); ++i) for(int i = 0; i < m_objInstance.size(); ++i)
{ {
auto& inst = m_objInstance[i]; auto& inst = m_objInstance[i];
auto& model = m_objModel[inst.objIndex]; auto& model = m_objModel[inst.objIndex];
m_pushConstant.instanceId = i; // Telling which instance is drawn m_pushConstant.instanceId = i; // Telling which instance is drawn
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
m_pushConstant);
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset}); vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32); sizeof(ObjPushConstant), &m_pushConstant);
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0); vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
} }
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }
@ -482,10 +457,12 @@ void HelloVulkan::onResize(int /*w*/, int /*h*/)
updatePostDescriptorSet(); updatePostDescriptorSet();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Post-processing // Post-processing
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Creating an offscreen frame buffer and the associated render pass // Creating an offscreen frame buffer and the associated render pass
// //
@ -497,29 +474,28 @@ void HelloVulkan::createOffscreenRender()
// Creating the color image // Creating the color image
{ {
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
vk::ImageUsageFlagBits::eColorAttachment VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
| vk::ImageUsageFlagBits::eSampled | VK_IMAGE_USAGE_STORAGE_BIT);
| vk::ImageUsageFlagBits::eStorage);
nvvk::Image image = m_alloc.createImage(colorCreateInfo); nvvk::Image image = m_alloc.createImage(colorCreateInfo);
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo()); VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
} }
// Creating the depth buffer // Creating the depth buffer
auto depthCreateInfo = auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
vk::ImageUsageFlagBits::eDepthStencilAttachment);
{ {
nvvk::Image image = m_alloc.createImage(depthCreateInfo); nvvk::Image image = m_alloc.createImage(depthCreateInfo);
vk::ImageViewCreateInfo depthStencilView;
depthStencilView.setViewType(vk::ImageViewType::e2D); VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
depthStencilView.setFormat(m_offscreenDepthFormat); depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); depthStencilView.format = m_offscreenDepthFormat;
depthStencilView.setImage(image.image); depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
depthStencilView.image = image.image;
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
} }
@ -528,11 +504,9 @@ void HelloVulkan::createOffscreenRender()
{ {
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
auto cmdBuf = genCmdBuf.createCommandBuffer(); auto cmdBuf = genCmdBuf.createCommandBuffer();
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined, nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
vk::ImageLayout::eGeneral); nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
vk::ImageLayout::eDepthStencilAttachmentOptimal,
vk::ImageAspectFlagBits::eDepth);
genCmdBuf.submitAndWait(cmdBuf); genCmdBuf.submitAndWait(cmdBuf);
} }
@ -540,24 +514,23 @@ void HelloVulkan::createOffscreenRender()
// Creating a renderpass for the offscreen // Creating a renderpass for the offscreen
if(!m_offscreenRenderPass) if(!m_offscreenRenderPass)
{ {
m_offscreenRenderPass = m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
true, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
} }
// Creating the frame buffer for offscreen
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
m_offscreenDepth.descriptor.imageView};
m_device.destroy(m_offscreenFramebuffer); // Creating the frame buffer for offscreen
vk::FramebufferCreateInfo info; std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
info.setRenderPass(m_offscreenRenderPass);
info.setAttachmentCount(2); vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
info.setPAttachments(attachments.data()); VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
info.setWidth(m_size.width); info.renderPass = m_offscreenRenderPass;
info.setHeight(m_size.height); info.attachmentCount = 2;
info.setLayers(1); info.pAttachments = attachments.data();
m_offscreenFramebuffer = m_device.createFramebuffer(info); info.width = m_size.width;
info.height = m_size.height;
info.layers = 1;
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -566,26 +539,23 @@ void HelloVulkan::createOffscreenRender()
void HelloVulkan::createPostPipeline() void HelloVulkan::createPostPipeline()
{ {
// Push constants in the fragment shader // Push constants in the fragment shader
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)}; VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
// Creating the pipeline layout // Creating the pipeline layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
pipelineLayoutCreateInfo.setSetLayoutCount(1); createInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout); createInfo.pSetLayouts = &m_postDescSetLayout;
pipelineLayoutCreateInfo.setPushConstantRangeCount(1); createInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges); createInfo.pPushConstantRanges = &pushConstantRanges;
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo); vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
// Pipeline: completely generic, no vertices // Pipeline: completely generic, no vertices
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
m_renderPass); pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
true), pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
vk::ShaderStageFlagBits::eVertex); m_postPipeline = pipelineGenerator.createPipeline();
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
vk::ShaderStageFlagBits::eFragment);
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
m_postPipeline = pipelineGenerator.createPipeline();
m_debug.setObjectName(m_postPipeline, "post"); m_debug.setObjectName(m_postPipeline, "post");
} }
@ -595,43 +565,36 @@ void HelloVulkan::createPostPipeline()
// //
void HelloVulkan::createPostDescriptor() void HelloVulkan::createPostDescriptor()
{ {
using vkDS = vk::DescriptorSetLayoutBinding; m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
using vkDT = vk::DescriptorType;
using vkSS = vk::ShaderStageFlagBits;
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Update the output // Update the output
// //
void HelloVulkan::updatePostDescriptorSet() void HelloVulkan::updatePostDescriptorSet()
{ {
vk::WriteDescriptorSet writeDescriptorSets = VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
m_device.updateDescriptorSets(writeDescriptorSets, nullptr);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Draw a full screen quad with the attached image // Draw a full screen quad with the attached image
// //
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf) void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
{ {
m_debug.beginLabel(cmdBuf, "Post"); m_debug.beginLabel(cmdBuf, "Post");
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)}); setViewport(cmdBuf);
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height); auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
aspectRatio); vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0, vkCmdDraw(cmdBuf, 3, 1, 0, 0);
m_postDescSet, {});
cmdBuf.draw(3, 1, 0, 0);
m_debug.endLabel(cmdBuf); m_debug.endLabel(cmdBuf);
} }
@ -646,45 +609,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
void HelloVulkan::initRayTracing() void HelloVulkan::initRayTracing()
{ {
// Requesting ray tracing properties // Requesting ray tracing properties
auto properties = VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2, prop2.pNext = &m_rtProperties;
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>(); vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS // Convert an OBJ model into the ray tracing geometry used to build the BLAS
// //
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
{ {
// Building part // BLAS builder requires raw device addresses.
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer}); VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer}); info.buffer = model.vertexBuffer.buffer;
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
info.buffer = model.indexBuffer.buffer;
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
vk::AccelerationStructureGeometryTrianglesDataKHR triangles; uint32_t maxPrimitiveCount = model.nbIndices / 3;
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
triangles.setVertexData(vertexAddress);
triangles.setVertexStride(sizeof(VertexObj));
triangles.setIndexType(vk::IndexType::eUint32);
triangles.setIndexData(indexAddress);
triangles.setTransformData({});
triangles.setMaxVertex(model.nbVertices);
// Setting up the build info of the acceleration // Describe buffer as array of VertexObj.
vk::AccelerationStructureGeometryKHR asGeom; VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles); triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque); triangles.vertexData.deviceAddress = vertexAddress;
asGeom.geometry.setTriangles(triangles); triangles.vertexStride = sizeof(VertexObj);
// Describe index data (32-bit unsigned int)
triangles.indexType = VK_INDEX_TYPE_UINT32;
triangles.indexData.deviceAddress = indexAddress;
// Indicate identity transform by setting transformData to null device pointer.
//triangles.transformData = {};
triangles.maxVertex = model.nbVertices;
// The primitive itself // Identify the above data as containing opaque triangles.
vk::AccelerationStructureBuildRangeInfoKHR offset; VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
offset.setFirstVertex(0); asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
offset.setPrimitiveOffset(0); asGeom.geometry.triangles = triangles;
offset.setTransformOffset(0);
// Our blas is only one geometry, but could be made of many geometries // The entire array will be used to build the BLAS.
VkAccelerationStructureBuildRangeInfoKHR offset;
offset.firstVertex = 0;
offset.primitiveCount = maxPrimitiveCount;
offset.primitiveOffset = 0;
offset.transformOffset = 0;
// Our blas is made from only one geometry, but could be made of many geometries
nvvk::RaytracingBuilderKHR::BlasInput input; nvvk::RaytracingBuilderKHR::BlasInput input;
input.asGeometry.emplace_back(asGeom); input.asGeometry.emplace_back(asGeom);
input.asBuildOffsetInfo.emplace_back(offset); input.asBuildOffsetInfo.emplace_back(offset);
@ -707,7 +678,7 @@ void HelloVulkan::createBottomLevelAS()
// We could add more geometry in each BLAS, but we add only one for now // We could add more geometry in each BLAS, but we add only one for now
allBlas.emplace_back(blas); allBlas.emplace_back(blas);
} }
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }
void HelloVulkan::createTopLevelAS() void HelloVulkan::createTopLevelAS()
@ -724,5 +695,5 @@ void HelloVulkan::createTopLevelAS()
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
tlas.emplace_back(rayInst); tlas.emplace_back(rayInst);
} }
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace); m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
} }

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -35,25 +35,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -90,39 +86,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -130,6 +128,6 @@ public:
void createBottomLevelAS(); void createBottomLevelAS();
void createTopLevelAS(); void createTopLevelAS();
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
}; };

View file

@ -23,10 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <iostream>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -36,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -48,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -75,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -89,8 +86,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -117,9 +113,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -129,18 +125,19 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR};
;
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeatures);
vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures;
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -151,16 +148,14 @@ int main(int argc, char** argv)
// Use a compatible device // Use a compatible device
vkctx.initDevice(compatibleDevices[0], contextInfo); vkctx.initDevice(compatibleDevices[0], contextInfo);
// Create example // Create example
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -173,6 +168,7 @@ int main(int argc, char** argv)
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
helloVk.createOffscreenRender(); helloVk.createOffscreenRender();
helloVk.createDescriptorSetLayout(); helloVk.createDescriptorSetLayout();
helloVk.createGraphicsPipeline(); helloVk.createGraphicsPipeline();
@ -193,110 +189,98 @@ int main(int argc, char** argv)
nvmath::vec4f clearColor = nvmath::vec4f(1, 1, 1, 1.00f); nvmath::vec4f clearColor = nvmath::vec4f(1, 1, 1, 1.00f);
helloVk.setupGlfwCallbacks(window); helloVk.setupGlfwCallbacks(window);
ImGui_ImplGlfw_InitForVulkan(window, true); ImGui_ImplGlfw_InitForVulkan(window, true);
// Main loop // Main loop
while(!glfwWindowShouldClose(window)) while(!glfwWindowShouldClose(window))
{ {
try glfwPollEvents();
if(helloVk.isMinimized())
continue;
// Start the Dear ImGui frame
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Show UI window.
if(helloVk.showGui())
{ {
glfwPollEvents(); ImGuiH::Panel::Begin();
if(helloVk.isMinimized()) ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
continue;
// Start the Dear ImGui frame renderUI(helloVk);
ImGui_ImplGlfw_NewFrame(); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::NewFrame(); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
// Show UI window.
if(helloVk.showGui())
{
ImGuiH::Panel::Begin();
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End();
}
// Start rendering the scene
helloVk.prepareFrame();
// Start command buffer of this frame
auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
// Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen
std::array<vk::ClearValue, 2> clearValues;
clearValues[0].setColor(
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass
{
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
offscreenRenderPassBeginInfo.setClearValueCount(2);
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
// Rendering Scene
{
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass();
}
}
// 2nd rendering pass: tone mapper, UI
{
vk::RenderPassBeginInfo postRenderPassBeginInfo;
postRenderPassBeginInfo.setClearValueCount(2);
postRenderPassBeginInfo.setPClearValues(clearValues.data());
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper
helloVk.drawPost(cmdBuf);
// Rendering UI
ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass();
}
// Submit for display
cmdBuf.end();
helloVk.submitFrame();
} }
catch(const std::system_error& e)
// Start rendering the scene
helloVk.prepareFrame();
// Start command buffer of this frame
auto curFrame = helloVk.getCurFrame();
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen
std::array<VkClearValue, 2> clearValues{};
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
clearValues[1].depthStencil = {1.0f, 0};
// Offscreen render pass
{ {
if(e.code() == vk::Result::eErrorDeviceLost) VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene
{ {
#if _WIN32 vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1); helloVk.rasterize(cmdBuf);
#endif vkCmdEndRenderPass(cmdBuf);
} }
std::cout << e.what() << std::endl;
return e.code().value();
} }
// 2nd rendering pass: tone mapper, UI
{
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf);
// Rendering UI
ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
vkCmdEndRenderPass(cmdBuf);
}
// Submit for display
vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")
@ -29,7 +29,6 @@ list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
include_directories(${TUTO_KHR_DIR}/common) include_directories(${TUTO_KHR_DIR}/common)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# GLSL to SPIR-V custom build # GLSL to SPIR-V custom build
compile_glsl_directory( compile_glsl_directory(
@ -39,7 +38,6 @@ compile_glsl_directory(
) )
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Sources # Sources
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})

View file

@ -44,8 +44,7 @@ Vulkan ray tracing allows recursive calls to traceRayEXT, up to a limit defined
In `createRtPipeline()` in `hello_vulkan.cpp`, bring the maximum recursion depth up to 10, making sure not to exceed the physical device's maximum recursion limit: In `createRtPipeline()` in `hello_vulkan.cpp`, bring the maximum recursion depth up to 10, making sure not to exceed the physical device's maximum recursion limit:
~~~~ C++ ~~~~ C++
rayPipelineInfo.setMaxPipelineRayRecursionDepth( rayPipelineInfo.maxPipelineRayRecursionDepth = std::max(10u, m_rtProperties.maxRecursionDepth); // Ray depth
std::max(10u, m_rtProperties.maxRecursionDepth)); // Ray depth
~~~~ ~~~~
### `raycommon.glsl` ### `raycommon.glsl`
@ -203,7 +202,7 @@ Since the ray generation shader now handles attenuation, we no longer need to at
Finally, we no longer need to have a deep recursion setting in `createRtPipeline` -- just a depth of 2, one for the initial ray generation segment and another for shadow rays. Finally, we no longer need to have a deep recursion setting in `createRtPipeline` -- just a depth of 2, one for the initial ray generation segment and another for shadow rays.
~~~~ C++ ~~~~ C++
rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
~~~~ ~~~~
In `raytrace.rgen`, we can now make the maximum ray depth significantly larger -- such as 100, for instance -- without causing a device lost error. In `raytrace.rgen`, we can now make the maximum ray depth significantly larger -- such as 100, for instance -- without causing a device lost error.

File diff suppressed because it is too large Load diff

View file

@ -19,11 +19,11 @@
#pragma once #pragma once
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -35,25 +35,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -90,39 +86,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -133,19 +131,19 @@ public:
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void createRtShaderBindingTable(); void createRtShaderBindingTable();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::Buffer m_rtSBTBuffer; nvvk::Buffer m_rtSBTBuffer;
struct RtPushConstant struct RtPushConstant
{ {

View file

@ -23,16 +23,15 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h"
#include "hello_vulkan.h" #include "hello_vulkan.h"
#include "imgui/imgui_camera_widget.h" #include "imgui/imgui_camera_widget.h"
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -44,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -71,6 +71,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -85,8 +86,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -113,9 +113,9 @@ int main(int argc, char** argv)
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo(true);
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
#ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -127,18 +127,16 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature;
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
&accelFeature);
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature;
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
@ -153,11 +151,10 @@ int main(int argc, char** argv)
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -168,11 +165,9 @@ int main(int argc, char** argv)
// Creation of the example // Creation of the example
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0)) nvmath::translation_mat4(nvmath::vec3f(-2, 0, 0)) * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(2, 0, 0)) nvmath::translation_mat4(nvmath::vec3f(2, 0, 0)) * nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
* nvmath::scale_mat4(nvmath::vec3f(.1f, 5.f, 5.f)));
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true),
nvmath::translation_mat4(nvmath::vec3f(0, -1, 0))); nvmath::translation_mat4(nvmath::vec3f(0, -1, 0)));
@ -216,6 +211,7 @@ int main(int argc, char** argv)
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// Show UI window. // Show UI window.
if(helloVk.showGui()) if(helloVk.showGui())
{ {
@ -225,8 +221,7 @@ int main(int argc, char** argv)
renderUI(helloVk); renderUI(helloVk);
ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50); ImGui::SliderInt("Max Depth", &helloVk.m_rtPushConstants.maxDepth, 1, 50);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -235,28 +230,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -265,40 +261,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# Project setting # Project setting
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
SET(PROJNAME vk_${PROJNAME}_KHR) set(PROJNAME vk_${PROJNAME}_KHR)
project(${PROJNAME} LANGUAGES C CXX) project(${PROJNAME} LANGUAGES C CXX)
message(STATUS "-------------------------------") message(STATUS "-------------------------------")
message(STATUS "Processing Project ${PROJNAME}:") message(STATUS "Processing Project ${PROJNAME}:")
@ -76,4 +76,3 @@ _finalize_target( ${PROJNAME} )
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")

View file

@ -95,14 +95,15 @@ In our example, we will have only integers for constant data. There are various
~~~~ C ~~~~ C
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
/// Helper to generate specialization info // Helper to generate specialization info
//
class Specialization class Specialization
{ {
public: public:
void add(uint32_t constantID, int32_t value) void add(uint32_t constantID, int32_t value)
{ {
spec_values.push_back(value); spec_values.push_back(value);
vk::SpecializationMapEntry entry; VkSpecializationMapEntry entry;
entry.constantID = constantID; entry.constantID = constantID;
entry.size = sizeof(int32_t); entry.size = sizeof(int32_t);
entry.offset = static_cast<uint32_t>(spec_entries.size() * sizeof(int32_t)); entry.offset = static_cast<uint32_t>(spec_entries.size() * sizeof(int32_t));
@ -115,40 +116,37 @@ public:
add(v.first, v.second); add(v.first, v.second);
} }
vk::SpecializationInfo* getSpecialization() VkSpecializationInfo* getSpecialization()
{ {
spec_info.setData<int32_t>(spec_values); spec_info.dataSize = static_cast<uint32_t>(spec_values.size() * sizeof(int32_t));
spec_info.setMapEntries(spec_entries); spec_info.pData = spec_values.data();
spec_info.mapEntryCount = static_cast<uint32_t>(spec_entries.size());
spec_info.pMapEntries = spec_entries.data();
return &spec_info; return &spec_info;
} }
private: private:
std::vector<int32_t> spec_values; std::vector<int32_t> spec_values;
std::vector<vk::SpecializationMapEntry> spec_entries; std::vector<VkSpecializationMapEntry> spec_entries;
vk::SpecializationInfo spec_info; VkSpecializationInfo spec_info;
}; };
~~~~ ~~~~
In `HelloVulkan::createRtPipeline()`, In `HelloVulkan::createRtPipeline()`, we will create 8 specialization of the closest hit shader.
first move the Closest Hit shader module creation up in the function next to the other one, as follow ... So the number of stages, will be 11 instead of 4.
~~~~ C ~~~~ C
vk::ShaderModule raygenSM = nvvk::createShaderModule( enum StageIndices
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); {
vk::ShaderModule missSM = nvvk::createShaderModule( eRaygen,
m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); eMiss,
eMiss2,
// The second miss shader is invoked when a shadow ray misses the geometry. It eClosestHit, // <---- 8 specialization of this one
// simply indicates that no occlusion has been found eShaderGroupCount = 11
vk::ShaderModule shadowmissSM = nvvk::createShaderModule( };
m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); ~~~~
vk::ShaderModule chitSM = nvvk::createShaderModule(
m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
~~~~
Thenjust after creating the shader modules, create a `Specialization` for each of the 8 on/off permutations of the 3 constants.
Then create a `Specialization` for each of the 8 on/off permutations of the 3 constants.
~~~~ C ~~~~ C
// Specialization // Specialization
@ -162,23 +160,35 @@ Thenjust after creating the shader modules, create a `Specialization` for each o
} }
~~~~ ~~~~
Then we will create as many HIT shader groups as we have specializations. This will give us the ability later to choose which 'specialization' we want to use. Now the shader group will be created 8 times, each with a different specialization.
~~~~ C
// Hit Group - Closest Hit
// Create many variation of the closest hit
for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++)
{
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
stage.pSpecializationInfo = specializations[s].getSpecialization();
stages[eClosestHit + s] = stage;
}
~~~~
**Tip** : We can avoid to create 8 shader modules, but we would have to properly deal with the
deletion of them at the end of the function.
We will also modify the creation of the hit group to create as many HIT shader groups as we have specializations. This will give us the ability later to choose which 'specialization' we want to use.
~~~~ C ~~~~ C
// Hit Group - Closest Hit + AnyHit // Hit Group - Closest Hit + AnyHit
for(size_t i = 0; i < specializations.size(); i++) // Creating many Hit groups, one for each specialization
for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++)
{ {
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR, group.generalShader = VK_SHADER_UNUSED_KHR;
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR}; group.closestHitShader = eClosestHit + s; // Using variation of the closest hit
hg.setClosestHitShader(static_cast<uint32_t>(stages.size())); m_rtShaderGroups.push_back(group);
vk::PipelineShaderStageCreateInfo stage;
stage.stage = vk::ShaderStageFlagBits::eClosestHitKHR;
stage.module = chitSM;
stage.pName = "main";
stage.pSpecializationInfo = specializations[i].getSpecialization();
stages.push_back(stage);
m_rtShaderGroups.push_back(hg);
} }
~~~~ ~~~~

File diff suppressed because it is too large Load diff

View file

@ -18,13 +18,12 @@
*/ */
#pragma once #pragma once
#include <vulkan/vulkan.hpp>
#include "nvvk/appbase_vk.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/debug_util_vk.hpp" #include "nvvk/debug_util_vk.hpp"
#include "nvvk/descriptorsets_vk.hpp" #include "nvvk/descriptorsets_vk.hpp"
#include "nvvk/memallocator_dma_vk.hpp" #include "nvvk/memallocator_dma_vk.hpp"
#include "nvvk/resourceallocator_vk.hpp"
// #VKRay // #VKRay
#include "nvvk/raytraceKHR_vk.hpp" #include "nvvk/raytraceKHR_vk.hpp"
@ -37,25 +36,21 @@
// - Rendering is done in an offscreen framebuffer // - Rendering is done in an offscreen framebuffer
// - The image of the framebuffer is displayed in post-process in a full-screen quad // - The image of the framebuffer is displayed in post-process in a full-screen quad
// //
class HelloVulkan : public nvvk::AppBase class HelloVulkan : public nvvk::AppBaseVk
{ {
public: public:
void setup(const vk::Instance& instance, void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
const vk::Device& device,
const vk::PhysicalDevice& physicalDevice,
uint32_t queueFamily) override;
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createGraphicsPipeline(); void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1)); void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void updateDescriptorSet(); void updateDescriptorSet();
void createUniformBuffer(); void createUniformBuffer();
void createSceneDescriptionBuffer(); void createSceneDescriptionBuffer();
void createTextureImages(const vk::CommandBuffer& cmdBuf, void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
const std::vector<std::string>& textures); void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
void onResize(int /*w*/, int /*h*/) override; void onResize(int /*w*/, int /*h*/) override;
void destroyResources(); void destroyResources();
void rasterize(const vk::CommandBuffer& cmdBuff); void rasterize(const VkCommandBuffer& cmdBuff);
// The OBJ model // The OBJ model
struct ObjModel struct ObjModel
@ -93,39 +88,41 @@ public:
std::vector<ObjInstance> m_objInstance; std::vector<ObjInstance> m_objInstance;
// Graphic pipeline // Graphic pipeline
vk::PipelineLayout m_pipelineLayout; VkPipelineLayout m_pipelineLayout;
vk::Pipeline m_graphicsPipeline; VkPipeline m_graphicsPipeline;
nvvk::DescriptorSetBindings m_descSetLayoutBind; nvvk::DescriptorSetBindings m_descSetLayoutBind;
vk::DescriptorPool m_descPool; VkDescriptorPool m_descPool;
vk::DescriptorSetLayout m_descSetLayout; VkDescriptorSetLayout m_descSetLayout;
vk::DescriptorSet m_descSet; VkDescriptorSet m_descSet;
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
nvvk::DebugUtil m_debug; // Utility to name objects nvvk::DebugUtil m_debug; // Utility to name objects
// #Post // #Post
void createOffscreenRender(); void createOffscreenRender();
void createPostPipeline(); void createPostPipeline();
void createPostDescriptor(); void createPostDescriptor();
void updatePostDescriptorSet(); void updatePostDescriptorSet();
void drawPost(vk::CommandBuffer cmdBuf); void drawPost(VkCommandBuffer cmdBuf);
nvvk::DescriptorSetBindings m_postDescSetLayoutBind; nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
vk::DescriptorPool m_postDescPool; VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
vk::DescriptorSetLayout m_postDescSetLayout; VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
vk::DescriptorSet m_postDescSet; VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
vk::Pipeline m_postPipeline; VkPipeline m_postPipeline{VK_NULL_HANDLE};
vk::PipelineLayout m_postPipelineLayout; VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
vk::RenderPass m_offscreenRenderPass; VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
vk::Framebuffer m_offscreenFramebuffer; VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
nvvk::Texture m_offscreenColor; nvvk::Texture m_offscreenColor;
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
nvvk::Texture m_offscreenDepth; nvvk::Texture m_offscreenDepth;
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32}; VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
// #VKRay // #VKRay
void initRayTracing(); void initRayTracing();
@ -135,19 +132,19 @@ public:
void createRtDescriptorSet(); void createRtDescriptorSet();
void updateRtDescriptorSet(); void updateRtDescriptorSet();
void createRtPipeline(); void createRtPipeline();
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor); void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties; VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder; nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
vk::DescriptorPool m_rtDescPool; VkDescriptorPool m_rtDescPool;
vk::DescriptorSetLayout m_rtDescSetLayout; VkDescriptorSetLayout m_rtDescSetLayout;
vk::DescriptorSet m_rtDescSet; VkDescriptorSet m_rtDescSet;
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups; std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
vk::PipelineLayout m_rtPipelineLayout; VkPipelineLayout m_rtPipelineLayout;
vk::Pipeline m_rtPipeline; VkPipeline m_rtPipeline;
nvvk::SBTWrapper m_sbtWrapper; nvvk::SBTWrapper m_sbtWrapper;
struct RtPushConstant struct RtPushConstant
{ {

View file

@ -23,8 +23,6 @@
// at the top of imgui.cpp. // at the top of imgui.cpp.
#include <array> #include <array>
#include <vulkan/vulkan.hpp>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_glfw.h"
#include "imgui.h" #include "imgui.h"
@ -34,7 +32,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "nvh/cameramanipulator.hpp" #include "nvh/cameramanipulator.hpp"
#include "nvh/fileoperations.hpp" #include "nvh/fileoperations.hpp"
#include "nvpsystem.hpp" #include "nvpsystem.hpp"
#include "nvvk/appbase_vkpp.hpp"
#include "nvvk/commands_vk.hpp" #include "nvvk/commands_vk.hpp"
#include "nvvk/context_vk.hpp" #include "nvvk/context_vk.hpp"
@ -46,6 +43,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Default search path for shaders // Default search path for shaders
std::vector<std::string> defaultSearchPaths; std::vector<std::string> defaultSearchPaths;
// GLFW Callback functions // GLFW Callback functions
static void onErrorCallback(int error, const char* description) static void onErrorCallback(int error, const char* description)
{ {
@ -84,6 +82,7 @@ void renderUI(HelloVulkan& helloVk)
static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_WIDTH = 1280;
static int const SAMPLE_HEIGHT = 720; static int const SAMPLE_HEIGHT = 720;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Application Entry // Application Entry
// //
@ -98,8 +97,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
// Setup camera // Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
@ -123,12 +121,12 @@ int main(int argc, char** argv)
}; };
// Requesting Vulkan extensions and layers // Requesting Vulkan extensions and layers
nvvk::ContextCreateInfo contextInfo(true); nvvk::ContextCreateInfo contextInfo;
contextInfo.setVersion(1, 2); contextInfo.setVersion(1, 2);
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef WIN32 #ifdef _WIN32
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else #else
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@ -138,19 +136,19 @@ int main(int argc, char** argv)
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
// #VKRay: Activate the ray tracing extension // #VKRay: Activate the ray tracing extension
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature);
&accelFeature); VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false,
&rtPipelineFeature);
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
// Creating Vulkan base application // Creating Vulkan base application
nvvk::Context vkctx{}; nvvk::Context vkctx{};
vkctx.initInstance(contextInfo); vkctx.initInstance(contextInfo);
@ -160,16 +158,14 @@ int main(int argc, char** argv)
// Use a compatible device // Use a compatible device
vkctx.initDevice(compatibleDevices[0], contextInfo); vkctx.initDevice(compatibleDevices[0], contextInfo);
// Create example // Create example
HelloVulkan helloVk; HelloVulkan helloVk;
// Window need to be opened to get the surface on which to draw // Window need to be opened to get the surface on which to draw
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
vkctx.setGCTQueueWithPresent(surface); vkctx.setGCTQueueWithPresent(surface);
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
vkctx.m_queueGCT.familyIndex);
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
helloVk.createDepthBuffer(); helloVk.createDepthBuffer();
helloVk.createRenderPass(); helloVk.createRenderPass();
@ -229,9 +225,7 @@ int main(int argc, char** argv)
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
renderUI(helloVk); renderUI(helloVk);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
ImGuiH::Panel::End(); ImGuiH::Panel::End();
} }
@ -240,28 +234,29 @@ int main(int argc, char** argv)
helloVk.prepareFrame(); helloVk.prepareFrame();
// Start command buffer of this frame // Start command buffer of this frame
auto curFrame = helloVk.getCurFrame(); auto curFrame = helloVk.getCurFrame();
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuf, &beginInfo);
// Updating camera buffer // Updating camera buffer
helloVk.updateUniformBuffer(cmdBuf); helloVk.updateUniformBuffer(cmdBuf);
// Clearing screen // Clearing screen
std::array<vk::ClearValue, 2> clearValues; std::array<VkClearValue, 2> clearValues{};
clearValues[0].setColor( clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].depthStencil = {1.0f, 0};
clearValues[1].setDepthStencil({1.0f, 0});
// Offscreen render pass // Offscreen render pass
{ {
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.clearValueCount = 2;
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass); offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer); offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
// Rendering Scene // Rendering Scene
if(useRaytracer) if(useRaytracer)
@ -270,40 +265,40 @@ int main(int argc, char** argv)
} }
else else
{ {
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.rasterize(cmdBuf); helloVk.rasterize(cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
} }
// 2nd rendering pass: tone mapper, UI // 2nd rendering pass: tone mapper, UI
{ {
vk::RenderPassBeginInfo postRenderPassBeginInfo; VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.clearValueCount = 2;
postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.pClearValues = clearValues.data();
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
// Rendering tonemapper // Rendering tonemapper
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
helloVk.drawPost(cmdBuf); helloVk.drawPost(cmdBuf);
// Rendering UI // Rendering UI
ImGui::Render(); ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
cmdBuf.endRenderPass(); vkCmdEndRenderPass(cmdBuf);
} }
// Submit for display // Submit for display
cmdBuf.end(); vkEndCommandBuffer(cmdBuf);
helloVk.submitFrame(); helloVk.submitFrame();
} }
// Cleanup // Cleanup
helloVk.getDevice().waitIdle(); vkDeviceWaitIdle(helloVk.getDevice());
helloVk.destroyResources(); helloVk.destroyResources();
helloVk.destroy(); helloVk.destroy();
vkctx.deinit(); vkctx.deinit();
glfwDestroyWindow(window); glfwDestroyWindow(window);