Using Vulkan C API
This commit is contained in:
parent
b3e6d84807
commit
e642e9dc3a
83 changed files with 8015 additions and 8163 deletions
|
|
@ -36,35 +36,33 @@ The following are the buffers are they can be seen in [NSight Graphics](https://
|
|||
|
||||
## G-Buffer
|
||||
|
||||
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `vk::Format::eR32G32B32A32Sfloat` to store the position and normal and one `vk::Format::eR32Sfloat` for the ambient occlusion.
|
||||
The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion.
|
||||
|
||||
~~~~ C++
|
||||
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
||||
}
|
||||
|
||||
// The ambient occlusion result (r32)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
||||
}
|
||||
|
|
@ -76,9 +74,9 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
|||
|
||||
```
|
||||
// Creating the frame buffer for offscreen
|
||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||
m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||
m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
```
|
||||
|
||||
### Renderpass
|
||||
|
|
@ -86,7 +84,7 @@ The render pass for the fragment shader will need two color buffers, therefore w
|
|||
This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth)
|
||||
|
||||
```
|
||||
vk::ClearValue clearValues[3];
|
||||
std::array<VkClearValue, 3> clearValues{};
|
||||
```
|
||||
|
||||
Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section.
|
||||
|
|
@ -94,14 +92,14 @@ Since the clear value will be re-used by the offscreen (3 attachments) and the p
|
|||
```
|
||||
// Offscreen render pass
|
||||
{
|
||||
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
|
||||
clearValues[2].setDepthStencil({1.0f, 0});
|
||||
clearValues[1].color = {{0, 0, 0, 0}};
|
||||
clearValues[2].depthStencil = {1.0f, 0};
|
||||
```
|
||||
|
||||
```
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
clearValues[1].setDepthStencil({1.0f, 0});
|
||||
clearValues[1].depthStencil = {1.0f, 0};
|
||||
```
|
||||
|
||||
### Fragment shader
|
||||
|
|
@ -138,12 +136,9 @@ The shader takes two inputs, the G-Buffer and the TLAS, and has one output, the
|
|||
//
|
||||
void HelloVulkan::createCompDescriptors()
|
||||
{
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
|
||||
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
|
||||
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
|
||||
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
|
||||
m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
|
||||
m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
|
||||
|
||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||
|
|
@ -162,15 +157,17 @@ when resizing the window and the G-Buffer and AO buffer are resized.
|
|||
//
|
||||
void HelloVulkan::updateCompDescriptors()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
|
||||
|
||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
|
||||
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||
descASInfo.accelerationStructureCount = 1;
|
||||
descASInfo.pAccelerationStructures = &tlas;
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
||||
|
||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
~~~~
|
||||
|
||||
|
|
@ -200,40 +197,38 @@ struct AoControl
|
|||
The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)).
|
||||
This sets the current frame index, which allows us to accumulate AO samples over time.
|
||||
|
||||
Next, we are adding a `vk::ImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
||||
Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader.
|
||||
|
||||
~~~~ C++
|
||||
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
||||
// before the compute shader is using the buffer
|
||||
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
|
||||
vk::ImageMemoryBarrier imgMemBarrier;
|
||||
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
||||
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
imgMemBarrier.setImage(m_gBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
imgMemBarrier.image = m_gBuffer.image;
|
||||
imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.subresourceRange = range;
|
||||
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
~~~~
|
||||
|
||||
Folowing is the call to dispatch the compute shader
|
||||
|
||||
~~~~ C++
|
||||
// Preparing for the compute shader
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
||||
{m_compDescSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||
|
||||
|
||||
// Sending the push constant information
|
||||
aoControl.frame = m_frame;
|
||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
|
||||
sizeof(AoControl), &aoControl);
|
||||
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
|
||||
|
||||
// Dispatching the shader
|
||||
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
|
||||
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
~~~~
|
||||
|
||||
Then we are adding a final barrier to make sure the compute shader is done
|
||||
|
|
@ -242,13 +237,9 @@ writing the AO so that the fragment shader (post) can use it.
|
|||
~~~~ C++
|
||||
// Adding a barrier to be sure the compute shader has finished
|
||||
// writing to the AO buffer before the post shader is using it
|
||||
imgMemBarrier.setImage(m_aoBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
imgMemBarrier.image = m_aoBuffer.image;
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
~~~~
|
||||
|
||||
## Update Frame
|
||||
|
|
@ -450,9 +441,9 @@ We have also have added `AoControl aoControl;` somwhere in main() and passing th
|
|||
~~~~
|
||||
// Rendering Scene
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
helloVk.runCompute(cmdBuf, aoControl);
|
||||
}
|
||||
~~~~
|
||||
|
|
@ -463,10 +454,10 @@ The post shader will combine the result of the fragment (color) and the result o
|
|||
In `createPostDescriptor` we will need to add the descriptor
|
||||
|
||||
~~~~
|
||||
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
~~~~
|
||||
|
||||
And the equivalent in `updatePostDescriptorSet`
|
||||
And the equivalent in `updatePostDescriptorSet()`
|
||||
|
||||
~~~~
|
||||
writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
||||
|
|
|
|||
|
|
@ -19,25 +19,25 @@
|
|||
|
||||
|
||||
#include <sstream>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "obj_loader.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
#include "hello_vulkan.h"
|
||||
#include "nvh/alignment.hpp"
|
||||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/images_vk.hpp"
|
||||
#include "nvvk/pipeline_vk.hpp"
|
||||
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/renderpasses_vk.hpp"
|
||||
#include "nvvk/shaders_vk.hpp"
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// Holding the camera matrices
|
||||
struct CameraMatrices
|
||||
|
|
@ -45,21 +45,17 @@ struct CameraMatrices
|
|||
nvmath::mat4f view;
|
||||
nvmath::mat4f proj;
|
||||
nvmath::mat4f viewInverse;
|
||||
// #VKRay
|
||||
nvmath::mat4f projInverse;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Keep the handle on the device
|
||||
// Initialize the tool to do all our allocations: buffers, images
|
||||
//
|
||||
void HelloVulkan::setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily)
|
||||
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
||||
{
|
||||
AppBase::setup(instance, device, physicalDevice, queueFamily);
|
||||
m_alloc.init(device, physicalDevice);
|
||||
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
||||
m_alloc.init(instance, device, physicalDevice);
|
||||
m_debug.setup(m_device);
|
||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
||||
}
|
||||
|
|
@ -67,46 +63,44 @@ void HelloVulkan::setup(const vk::Instance& instance,
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Called at each frame to update the camera matrix
|
||||
//
|
||||
void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
// Prepare new UBO contents on host.
|
||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||
CameraMatrices hostUBO = {};
|
||||
hostUBO.view = CameraManip.getMatrix();
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
hostUBO.proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
|
||||
// hostUBO.proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
||||
hostUBO.viewInverse = nvmath::invert(hostUBO.view);
|
||||
// #VKRay
|
||||
hostUBO.projInverse = nvmath::invert(hostUBO.proj);
|
||||
|
||||
// UBO on the device, and what stages access it.
|
||||
vk::Buffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages =
|
||||
vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eRayTracingShaderKHR;
|
||||
VkBuffer deviceUBO = m_cameraMat.buffer;
|
||||
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||
|
||||
// Ensure that the modified UBO is not visible to previous frames.
|
||||
vk::BufferMemoryBarrier beforeBarrier;
|
||||
beforeBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
beforeBarrier.setDstAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
beforeBarrier.setBuffer(deviceUBO);
|
||||
beforeBarrier.setOffset(0);
|
||||
beforeBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(uboUsageStages, vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {beforeBarrier}, {});
|
||||
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
beforeBarrier.buffer = deviceUBO;
|
||||
beforeBarrier.offset = 0;
|
||||
beforeBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &beforeBarrier, 0, nullptr);
|
||||
|
||||
|
||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
||||
// buffer so it is okay to deallocate when the function returns).
|
||||
cmdBuf.updateBuffer<CameraMatrices>(m_cameraMat.buffer, 0, hostUBO);
|
||||
vkCmdUpdateBuffer(cmdBuf, m_cameraMat.buffer, 0, sizeof(CameraMatrices), &hostUBO);
|
||||
|
||||
// Making sure the updated UBO will be visible.
|
||||
vk::BufferMemoryBarrier afterBarrier;
|
||||
afterBarrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite);
|
||||
afterBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
afterBarrier.setBuffer(deviceUBO);
|
||||
afterBarrier.setOffset(0);
|
||||
afterBarrier.setSize(sizeof hostUBO);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, uboUsageStages,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {afterBarrier}, {});
|
||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
||||
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
afterBarrier.buffer = deviceUBO;
|
||||
afterBarrier.offset = 0;
|
||||
afterBarrier.size = sizeof(hostUBO);
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
||||
nullptr, 1, &afterBarrier, 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -114,22 +108,19 @@ void HelloVulkan::updateUniformBuffer(const vk::CommandBuffer& cmdBuf)
|
|||
//
|
||||
void HelloVulkan::createDescriptorSetLayout()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
||||
auto nbObj = static_cast<uint32_t>(m_objModel.size());
|
||||
|
||||
// Camera matrices (binding = 0)
|
||||
m_descSetLayoutBind.addBinding(vkDS(0, vkDT::eUniformBuffer, 1, vkSS::eVertex));
|
||||
m_descSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||
// Materials (binding = 1)
|
||||
m_descSetLayoutBind.addBinding(vkDS(1, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Scene description (binding = 2)
|
||||
m_descSetLayoutBind.addBinding(vkDS(2, vkDT::eStorageBuffer, 1, vkSS::eVertex | vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Textures (binding = 3)
|
||||
m_descSetLayoutBind.addBinding(vkDS(3, vkDT::eCombinedImageSampler, nbTxt, vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
// Materials (binding = 4)
|
||||
m_descSetLayoutBind.addBinding(vkDS(4, vkDT::eStorageBuffer, nbObj, vkSS::eFragment));
|
||||
m_descSetLayoutBind.addBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nbObj, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
|
||||
|
||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
||||
|
|
@ -142,40 +133,39 @@ void HelloVulkan::createDescriptorSetLayout()
|
|||
//
|
||||
void HelloVulkan::updateDescriptorSet()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
|
||||
// Camera matrices and scene description
|
||||
vk::DescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiUnif{m_cameraMat.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 0, &dbiUnif));
|
||||
vk::DescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorBufferInfo dbiSceneDesc{m_sceneDesc.buffer, 0, VK_WHOLE_SIZE};
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 2, &dbiSceneDesc));
|
||||
|
||||
// All material buffers, 1 buffer per OBJ
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMat;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiMatIdx;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiVert;
|
||||
std::vector<vk::DescriptorBufferInfo> dbiIdx;
|
||||
for(auto& obj : m_objModel)
|
||||
std::vector<VkDescriptorBufferInfo> dbiMat;
|
||||
std::vector<VkDescriptorBufferInfo> dbiMatIdx;
|
||||
std::vector<VkDescriptorBufferInfo> dbiVert;
|
||||
std::vector<VkDescriptorBufferInfo> dbiIdx;
|
||||
for(auto& m : m_objModel)
|
||||
{
|
||||
dbiMat.emplace_back(obj.matColorBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMatIdx.emplace_back(obj.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiVert.emplace_back(obj.vertexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiIdx.emplace_back(obj.indexBuffer.buffer, 0, VK_WHOLE_SIZE);
|
||||
dbiMat.push_back({m.matColorBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiMatIdx.push_back({m.matIndexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiVert.push_back({m.vertexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
dbiIdx.push_back({m.indexBuffer.buffer, 0, VK_WHOLE_SIZE});
|
||||
}
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 1, dbiMat.data()));
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 4, dbiMatIdx.data()));
|
||||
|
||||
// All texture samplers
|
||||
std::vector<vk::DescriptorImageInfo> diit;
|
||||
std::vector<VkDescriptorImageInfo> diit;
|
||||
for(auto& texture : m_textures)
|
||||
{
|
||||
diit.emplace_back(texture.descriptor);
|
||||
}
|
||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, 3, diit.data()));
|
||||
|
||||
|
||||
// Writing the information
|
||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -183,37 +173,34 @@ void HelloVulkan::updateDescriptorSet()
|
|||
//
|
||||
void HelloVulkan::createGraphicsPipeline()
|
||||
{
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
vk::PushConstantRange pushConstantRanges = {vkSS::eVertex | vkSS::eFragment, 0,
|
||||
sizeof(ObjPushConstant)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ObjPushConstant)};
|
||||
|
||||
// Creating the Pipeline Layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
vk::DescriptorSetLayout descSetLayout(m_descSetLayout);
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&descSetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_pipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_descSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
||||
|
||||
|
||||
// Creating the Pipeline
|
||||
std::vector<std::string> paths = defaultSearchPaths;
|
||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
||||
gpb.depthStencilState.depthTestEnable = true;
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), vkSS::eVertex);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), vkSS::eFragment);
|
||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
||||
gpb.addAttributeDescriptions({
|
||||
{0, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, vk::Format::eR32G32B32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, vk::Format::eR32G32Sfloat, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
||||
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
||||
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
||||
});
|
||||
|
||||
vk::PipelineColorBlendAttachmentState res;
|
||||
res.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
|
||||
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
|
||||
VkPipelineColorBlendAttachmentState res{};
|
||||
res.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
res.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
gpb.addBlendAttachmentState(res);
|
||||
|
||||
m_graphicsPipeline = gpb.createPipeline();
|
||||
|
|
@ -225,8 +212,6 @@ void HelloVulkan::createGraphicsPipeline()
|
|||
//
|
||||
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
|
||||
LOGI("Loading File: %s \n", filename.c_str());
|
||||
ObjLoader loader;
|
||||
loader.loadModel(filename);
|
||||
|
|
@ -250,18 +235,14 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
||||
|
||||
// Create the buffers on Device and copy vertices, indices and materials
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
vk::CommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
model.vertexBuffer =
|
||||
m_alloc.createBuffer(cmdBuf, loader.m_vertices,
|
||||
vkBU::eVertexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
||||
model.indexBuffer =
|
||||
m_alloc.createBuffer(cmdBuf, loader.m_indices,
|
||||
vkBU::eIndexBuffer | vkBU::eStorageBuffer | vkBU::eShaderDeviceAddress
|
||||
| vkBU::eAccelerationStructureBuildInputReadOnlyKHR);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, vkBU::eStorageBuffer);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, vkBU::eStorageBuffer);
|
||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
||||
VkBufferUsageFlags rtUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rtUsage);
|
||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rtUsage);
|
||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
// Creates all textures found
|
||||
createTextureImages(cmdBuf, loader.m_textures);
|
||||
cmdBufGet.submitAndWait(cmdBuf);
|
||||
|
|
@ -277,17 +258,15 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
|
|||
m_objInstance.emplace_back(instance);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Creating the uniform buffer holding the camera matrices
|
||||
// - Buffer is host visible
|
||||
//
|
||||
void HelloVulkan::createUniformBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
using vkMP = vk::MemoryPropertyFlagBits;
|
||||
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices),
|
||||
vkBU::eUniformBuffer | vkBU::eTransferDst, vkMP::eDeviceLocal);
|
||||
m_cameraMat = m_alloc.createBuffer(sizeof(CameraMatrices), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_debug.setObjectName(m_cameraMat.buffer, "cameraMat");
|
||||
}
|
||||
|
||||
|
|
@ -299,11 +278,10 @@ void HelloVulkan::createUniformBuffer()
|
|||
//
|
||||
void HelloVulkan::createSceneDescriptionBuffer()
|
||||
{
|
||||
using vkBU = vk::BufferUsageFlagBits;
|
||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
||||
|
||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, vkBU::eStorageBuffer);
|
||||
m_sceneDesc = m_alloc.createBuffer(cmdBuf, m_objInstance, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
cmdGen.submitAndWait(cmdBuf);
|
||||
m_alloc.finalizeAndReleaseStaging();
|
||||
m_debug.setObjectName(m_sceneDesc.buffer, "sceneDesc");
|
||||
|
|
@ -312,15 +290,15 @@ void HelloVulkan::createSceneDescriptionBuffer()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Creating all textures and samplers
|
||||
//
|
||||
void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures)
|
||||
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
||||
{
|
||||
using vkIU = vk::ImageUsageFlagBits;
|
||||
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
samplerCreateInfo.maxLod = FLT_MAX;
|
||||
|
||||
vk::SamplerCreateInfo samplerCreateInfo{
|
||||
{}, vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear};
|
||||
samplerCreateInfo.setMaxLod(FLT_MAX);
|
||||
vk::Format format = vk::Format::eR8G8B8A8Srgb;
|
||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
|
||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
||||
if(textures.empty() && m_textures.empty())
|
||||
|
|
@ -328,18 +306,17 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
nvvk::Texture texture;
|
||||
|
||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
||||
vk::DeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = vk::Extent2D(1, 1);
|
||||
VkDeviceSize bufferSize = sizeof(color);
|
||||
auto imgSize = VkExtent2D{1, 1};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
||||
|
||||
// Creating the VKImage
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
// Creating the dummy texture
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
else
|
||||
|
|
@ -352,8 +329,7 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
o << "media/textures/" << texture;
|
||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
||||
|
||||
stbi_uc* stbi_pixels =
|
||||
stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
|
||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
||||
|
||||
|
|
@ -366,16 +342,15 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
||||
}
|
||||
|
||||
vk::DeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = vk::Extent2D(texWidth, texHeight);
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, vkIU::eSampled, true);
|
||||
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
||||
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
||||
|
||||
{
|
||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
||||
vk::ImageViewCreateInfo ivInfo =
|
||||
nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
||||
|
||||
m_textures.push_back(texture);
|
||||
}
|
||||
|
|
@ -390,10 +365,11 @@ void HelloVulkan::createTextureImages(const vk::CommandBuffer& cmdBuf,
|
|||
//
|
||||
void HelloVulkan::destroyResources()
|
||||
{
|
||||
m_device.destroy(m_graphicsPipeline);
|
||||
m_device.destroy(m_pipelineLayout);
|
||||
m_device.destroy(m_descPool);
|
||||
m_device.destroy(m_descSetLayout);
|
||||
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
||||
|
||||
m_alloc.destroy(m_cameraMat);
|
||||
m_alloc.destroy(m_sceneDesc);
|
||||
|
||||
|
|
@ -411,22 +387,22 @@ void HelloVulkan::destroyResources()
|
|||
}
|
||||
|
||||
//#Post
|
||||
m_device.destroy(m_postPipeline);
|
||||
m_device.destroy(m_postPipelineLayout);
|
||||
m_device.destroy(m_postDescPool);
|
||||
m_device.destroy(m_postDescSetLayout);
|
||||
m_alloc.destroy(m_offscreenColor);
|
||||
m_alloc.destroy(m_gBuffer);
|
||||
m_alloc.destroy(m_aoBuffer);
|
||||
m_alloc.destroy(m_offscreenDepth);
|
||||
m_device.destroy(m_offscreenRenderPass);
|
||||
m_device.destroy(m_offscreenFramebuffer);
|
||||
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
||||
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||
|
||||
// Compute
|
||||
m_device.destroy(m_compDescPool);
|
||||
m_device.destroy(m_compDescSetLayout);
|
||||
m_device.destroy(m_compPipeline);
|
||||
m_device.destroy(m_compPipelineLayout);
|
||||
vkDestroyPipeline(m_device, m_compPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr);
|
||||
vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr);
|
||||
|
||||
// #VKRay
|
||||
m_rtBuilder.destroy();
|
||||
|
|
@ -436,32 +412,31 @@ void HelloVulkan::destroyResources()
|
|||
//--------------------------------------------------------------------------------------------------
|
||||
// Drawing the scene in raster mode
|
||||
//
|
||||
void HelloVulkan::rasterize(const vk::CommandBuffer& cmdBuf)
|
||||
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
||||
{
|
||||
using vkPBP = vk::PipelineBindPoint;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
vk::DeviceSize offset{0};
|
||||
VkDeviceSize offset{0};
|
||||
|
||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
||||
|
||||
// Dynamic Viewport
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
||||
setViewport(cmdBuf);
|
||||
|
||||
// Drawing all triangles
|
||||
cmdBuf.bindPipeline(vkPBP::eGraphics, m_graphicsPipeline);
|
||||
cmdBuf.bindDescriptorSets(vkPBP::eGraphics, m_pipelineLayout, 0, {m_descSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
||||
|
||||
|
||||
for(int i = 0; i < m_objInstance.size(); ++i)
|
||||
{
|
||||
auto& inst = m_objInstance[i];
|
||||
auto& model = m_objModel[inst.objIndex];
|
||||
m_pushConstant.instanceId = i; // Telling which instance is drawn
|
||||
cmdBuf.pushConstants<ObjPushConstant>(m_pipelineLayout, vkSS::eVertex | vkSS::eFragment, 0,
|
||||
m_pushConstant);
|
||||
|
||||
cmdBuf.bindVertexBuffers(0, {model.vertexBuffer.buffer}, {offset});
|
||||
cmdBuf.bindIndexBuffer(model.indexBuffer.buffer, 0, vk::IndexType::eUint32);
|
||||
cmdBuf.drawIndexed(model.nbIndices, 1, 0, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||
sizeof(ObjPushConstant), &m_pushConstant);
|
||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
||||
}
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
@ -491,64 +466,62 @@ void HelloVulkan::createOffscreenRender()
|
|||
m_alloc.destroy(m_aoBuffer);
|
||||
m_alloc.destroy(m_offscreenDepth);
|
||||
|
||||
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||
|
||||
// Creating the color image
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_offscreenColor.image, "offscreen");
|
||||
}
|
||||
|
||||
// The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32G32B32A32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_gBuffer.image, "G-Buffer");
|
||||
}
|
||||
|
||||
// The ambient occlusion result (r32)
|
||||
{
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, vk::Format::eR32Sfloat,
|
||||
vk::ImageUsageFlagBits::eColorAttachment
|
||||
| vk::ImageUsageFlagBits::eSampled
|
||||
| vk::ImageUsageFlagBits::eStorage);
|
||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
|
||||
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
vk::ImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, vk::SamplerCreateInfo());
|
||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
||||
m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler);
|
||||
m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
m_debug.setObjectName(m_aoBuffer.image, "aoBuffer");
|
||||
}
|
||||
|
||||
|
||||
// Creating the depth buffer
|
||||
auto depthCreateInfo =
|
||||
nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat,
|
||||
vk::ImageUsageFlagBits::eDepthStencilAttachment);
|
||||
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
{
|
||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
||||
|
||||
vk::ImageViewCreateInfo depthStencilView;
|
||||
depthStencilView.setViewType(vk::ImageViewType::e2D);
|
||||
depthStencilView.setFormat(m_offscreenDepthFormat);
|
||||
depthStencilView.setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1});
|
||||
depthStencilView.setImage(image.image);
|
||||
|
||||
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthStencilView.format = m_offscreenDepthFormat;
|
||||
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
||||
depthStencilView.image = image.image;
|
||||
|
||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
||||
}
|
||||
|
|
@ -557,15 +530,11 @@ void HelloVulkan::createOffscreenRender()
|
|||
{
|
||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
||||
vk::ImageAspectFlagBits::eDepth);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
|
||||
genCmdBuf.submitAndWait(cmdBuf);
|
||||
}
|
||||
|
|
@ -574,26 +543,23 @@ void HelloVulkan::createOffscreenRender()
|
|||
if(!m_offscreenRenderPass)
|
||||
{
|
||||
m_offscreenRenderPass =
|
||||
nvvk::createRenderPass(m_device,
|
||||
{m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
|
||||
m_offscreenDepthFormat, 1, true, true, vk::ImageLayout::eGeneral,
|
||||
vk::ImageLayout::eGeneral);
|
||||
nvvk::createRenderPass(m_device, {m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer
|
||||
m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
||||
}
|
||||
|
||||
// Creating the frame buffer for offscreen
|
||||
std::vector<vk::ImageView> attachments = {m_offscreenColor.descriptor.imageView,
|
||||
m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_gBuffer.descriptor.imageView,
|
||||
m_offscreenDepth.descriptor.imageView};
|
||||
|
||||
m_device.destroy(m_offscreenFramebuffer);
|
||||
vk::FramebufferCreateInfo info;
|
||||
info.setRenderPass(m_offscreenRenderPass);
|
||||
info.setAttachmentCount(static_cast<int>(attachments.size()));
|
||||
info.setPAttachments(attachments.data());
|
||||
info.setWidth(m_size.width);
|
||||
info.setHeight(m_size.height);
|
||||
info.setLayers(1);
|
||||
m_offscreenFramebuffer = m_device.createFramebuffer(info);
|
||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
||||
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
info.renderPass = m_offscreenRenderPass;
|
||||
info.attachmentCount = static_cast<int>(attachments.size());
|
||||
info.pAttachments = attachments.data();
|
||||
info.width = m_size.width;
|
||||
info.height = m_size.height;
|
||||
info.layers = 1;
|
||||
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -602,26 +568,23 @@ void HelloVulkan::createOffscreenRender()
|
|||
void HelloVulkan::createPostPipeline()
|
||||
{
|
||||
// Push constants in the fragment shader
|
||||
vk::PushConstantRange pushConstantRanges = {vk::ShaderStageFlagBits::eFragment, 0, sizeof(float)};
|
||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
||||
|
||||
// Creating the pipeline layout
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(1);
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(&m_postDescSetLayout);
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRanges);
|
||||
m_postPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &m_postDescSetLayout;
|
||||
createInfo.pushConstantRangeCount = 1;
|
||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
||||
|
||||
|
||||
// Pipeline: completely generic, no vertices
|
||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout,
|
||||
m_renderPass);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths,
|
||||
true),
|
||||
vk::ShaderStageFlagBits::eVertex);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true),
|
||||
vk::ShaderStageFlagBits::eFragment);
|
||||
pipelineGenerator.rasterizationState.setCullMode(vk::CullModeFlagBits::eNone);
|
||||
m_postPipeline = pipelineGenerator.createPipeline();
|
||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
||||
m_postPipeline = pipelineGenerator.createPipeline();
|
||||
m_debug.setObjectName(m_postPipeline, "post");
|
||||
}
|
||||
|
||||
|
|
@ -631,12 +594,8 @@ void HelloVulkan::createPostPipeline()
|
|||
//
|
||||
void HelloVulkan::createPostDescriptor()
|
||||
{
|
||||
using vkDS = vk::DescriptorSetLayoutBinding;
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
|
||||
m_postDescSetLayoutBind.addBinding(vkDS(0, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_postDescSetLayoutBind.addBinding(vkDS(1, vkDT::eCombinedImageSampler, 1, vkSS::eFragment));
|
||||
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
||||
|
|
@ -647,36 +606,32 @@ void HelloVulkan::createPostDescriptor()
|
|||
//
|
||||
void HelloVulkan::updatePostDescriptorSet()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
writes.emplace_back(
|
||||
m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor));
|
||||
writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor));
|
||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Draw a full screen quad with the attached image
|
||||
//
|
||||
void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
||||
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
||||
{
|
||||
m_debug.beginLabel(cmdBuf, "Post");
|
||||
|
||||
cmdBuf.setViewport(0, {vk::Viewport(0, 0, (float)m_size.width, (float)m_size.height, 0, 1)});
|
||||
cmdBuf.setScissor(0, {{{0, 0}, {m_size.width, m_size.height}}});
|
||||
setViewport(cmdBuf);
|
||||
|
||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
||||
cmdBuf.pushConstants<float>(m_postPipelineLayout, vk::ShaderStageFlagBits::eFragment, 0,
|
||||
aspectRatio);
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, m_postPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_postPipelineLayout, 0,
|
||||
m_postDescSet, {});
|
||||
cmdBuf.draw(3, 1, 0, 0);
|
||||
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
||||
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Raytracing, creation of BLAS and TLAS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -685,45 +640,53 @@ void HelloVulkan::drawPost(vk::CommandBuffer cmdBuf)
|
|||
void HelloVulkan::initRayTracing()
|
||||
{
|
||||
// Requesting ray tracing properties
|
||||
auto properties =
|
||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
prop2.pNext = &m_rtProperties;
|
||||
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||
|
||||
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS
|
||||
// Convert an OBJ model into the ray tracing geometry used to build the BLAS
|
||||
//
|
||||
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
||||
{
|
||||
// Building part
|
||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
||||
// BLAS builder requires raw device addresses.
|
||||
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO};
|
||||
info.buffer = model.vertexBuffer.buffer;
|
||||
VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||
info.buffer = model.indexBuffer.buffer;
|
||||
VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(m_device, &info);
|
||||
|
||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
||||
triangles.setVertexData(vertexAddress);
|
||||
triangles.setVertexStride(sizeof(VertexObj));
|
||||
triangles.setIndexType(vk::IndexType::eUint32);
|
||||
triangles.setIndexData(indexAddress);
|
||||
triangles.setTransformData({});
|
||||
triangles.setMaxVertex(model.nbVertices);
|
||||
uint32_t maxPrimitiveCount = model.nbIndices / 3;
|
||||
|
||||
// Setting up the build info of the acceleration
|
||||
vk::AccelerationStructureGeometryKHR asGeom;
|
||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eOpaque);
|
||||
asGeom.geometry.setTriangles(triangles);
|
||||
// Describe buffer as array of VertexObj.
|
||||
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; // vec3 vertex position data.
|
||||
triangles.vertexData.deviceAddress = vertexAddress;
|
||||
triangles.vertexStride = sizeof(VertexObj);
|
||||
// Describe index data (32-bit unsigned int)
|
||||
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
triangles.indexData.deviceAddress = indexAddress;
|
||||
// Indicate identity transform by setting transformData to null device pointer.
|
||||
//triangles.transformData = {};
|
||||
triangles.maxVertex = model.nbVertices;
|
||||
|
||||
// The primitive itself
|
||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.setFirstVertex(0);
|
||||
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
|
||||
offset.setPrimitiveOffset(0);
|
||||
offset.setTransformOffset(0);
|
||||
// Identify the above data as containing opaque triangles.
|
||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||
asGeom.geometry.triangles = triangles;
|
||||
|
||||
// Our blas is only one geometry, but could be made of many geometries
|
||||
// The entire array will be used to build the BLAS.
|
||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.firstVertex = 0;
|
||||
offset.primitiveCount = maxPrimitiveCount;
|
||||
offset.primitiveOffset = 0;
|
||||
offset.transformOffset = 0;
|
||||
|
||||
// Our blas is made from only one geometry, but could be made of many geometries
|
||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||
input.asGeometry.emplace_back(asGeom);
|
||||
input.asBuildOffsetInfo.emplace_back(offset);
|
||||
|
|
@ -746,7 +709,7 @@ void HelloVulkan::createBottomLevelAS()
|
|||
// We could add more geometry in each BLAS, but we add only one for now
|
||||
allBlas.emplace_back(blas);
|
||||
}
|
||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||
}
|
||||
|
||||
void HelloVulkan::createTopLevelAS()
|
||||
|
|
@ -763,7 +726,7 @@ void HelloVulkan::createTopLevelAS()
|
|||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
tlas.emplace_back(rayInst);
|
||||
}
|
||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -776,12 +739,9 @@ void HelloVulkan::createTopLevelAS()
|
|||
//
|
||||
void HelloVulkan::createCompDescriptors()
|
||||
{
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] G-Buffer
|
||||
0, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [out] AO
|
||||
1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(vk::DescriptorSetLayoutBinding( // [in] TLAS
|
||||
2, vk::DescriptorType::eAccelerationStructureKHR, 1, vk::ShaderStageFlagBits::eCompute));
|
||||
m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer
|
||||
m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO
|
||||
m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS
|
||||
|
||||
m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device);
|
||||
m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1);
|
||||
|
|
@ -793,15 +753,17 @@ void HelloVulkan::createCompDescriptors()
|
|||
//
|
||||
void HelloVulkan::updateCompDescriptors()
|
||||
{
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor));
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor));
|
||||
|
||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo{1, &tlas};
|
||||
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||
descASInfo.accelerationStructureCount = 1;
|
||||
descASInfo.pAccelerationStructures = &tlas;
|
||||
writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo));
|
||||
|
||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
|
@ -810,24 +772,29 @@ void HelloVulkan::updateCompDescriptors()
|
|||
void HelloVulkan::createCompPipelines()
|
||||
{
|
||||
// pushing time
|
||||
vk::PushConstantRange push_constants = {vk::ShaderStageFlagBits::eCompute, 0, sizeof(AoControl)};
|
||||
vk::PipelineLayoutCreateInfo layout_info{{}, 1, &m_compDescSetLayout, 1, &push_constants};
|
||||
m_compPipelineLayout = m_device.createPipelineLayout(layout_info);
|
||||
vk::ComputePipelineCreateInfo computePipelineCreateInfo{{}, {}, m_compPipelineLayout};
|
||||
VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl)};
|
||||
VkPipelineLayoutCreateInfo plCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
plCreateInfo.setLayoutCount = 1;
|
||||
plCreateInfo.pSetLayouts = &m_compDescSetLayout;
|
||||
plCreateInfo.pushConstantRangeCount = 1;
|
||||
plCreateInfo.pPushConstantRanges = &push_constants;
|
||||
vkCreatePipelineLayout(m_device, &plCreateInfo, nullptr, &m_compPipelineLayout);
|
||||
|
||||
computePipelineCreateInfo.stage =
|
||||
nvvk::createShaderStageInfo(m_device,
|
||||
nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
|
||||
VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
m_compPipeline = m_device.createComputePipeline({}, computePipelineCreateInfo).value;
|
||||
m_device.destroy(computePipelineCreateInfo.stage.module);
|
||||
VkComputePipelineCreateInfo cpCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
|
||||
cpCreateInfo.layout = m_compPipelineLayout;
|
||||
cpCreateInfo.stage = nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true),
|
||||
VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
|
||||
vkCreateComputePipelines(m_device, {}, 1, &cpCreateInfo, nullptr, &m_compPipeline);
|
||||
|
||||
vkDestroyShaderModule(m_device, cpCreateInfo.stage.module, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Running compute shader
|
||||
//
|
||||
#define GROUP_SIZE 16 // Same group size as in compute shader
|
||||
void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
|
||||
void HelloVulkan::runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl)
|
||||
{
|
||||
updateFrame();
|
||||
|
||||
|
|
@ -839,43 +806,38 @@ void HelloVulkan::runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl)
|
|||
|
||||
// Adding a barrier to be sure the fragment has finished writing to the G-Buffer
|
||||
// before the compute shader is using the buffer
|
||||
vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
|
||||
vk::ImageMemoryBarrier imgMemBarrier;
|
||||
imgMemBarrier.setSrcAccessMask(vk::AccessFlagBits::eShaderWrite);
|
||||
imgMemBarrier.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
|
||||
imgMemBarrier.setImage(m_gBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
imgMemBarrier.image = m_gBuffer.image;
|
||||
imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
imgMemBarrier.subresourceRange = range;
|
||||
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
|
||||
|
||||
// Preparing for the compute shader
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eCompute, m_compPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_compPipelineLayout, 0,
|
||||
{m_compDescSet}, {});
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr);
|
||||
|
||||
|
||||
// Sending the push constant information
|
||||
aoControl.frame = m_frame;
|
||||
cmdBuf.pushConstants(m_compPipelineLayout, vk::ShaderStageFlagBits::eCompute, 0,
|
||||
sizeof(AoControl), &aoControl);
|
||||
vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl);
|
||||
|
||||
// Dispatching the shader
|
||||
cmdBuf.dispatch((m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE,
|
||||
(m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1);
|
||||
|
||||
|
||||
// Adding a barrier to be sure the compute shader has finished
|
||||
// writing to the AO buffer before the post shader is using it
|
||||
imgMemBarrier.setImage(m_aoBuffer.image);
|
||||
imgMemBarrier.setOldLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setNewLayout(vk::ImageLayout::eGeneral);
|
||||
imgMemBarrier.setSubresourceRange(range);
|
||||
cmdBuf.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
|
||||
vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::DependencyFlagBits::eDeviceGroup, {}, {}, {imgMemBarrier});
|
||||
imgMemBarrier.image = m_aoBuffer.image;
|
||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier);
|
||||
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/appbase_vk.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
#include "nvvk/memallocator_dma_vk.hpp"
|
||||
#include "nvvk/resourceallocator_vk.hpp"
|
||||
|
||||
// #VKRay
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
|
@ -46,25 +46,21 @@ struct AoControl
|
|||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
class HelloVulkan : public nvvk::AppBaseVk
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const vk::CommandBuffer& cmdBuf);
|
||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
||||
|
||||
// The OBJ model
|
||||
struct ObjModel
|
||||
|
|
@ -89,7 +85,7 @@ public:
|
|||
// Information pushed at each draw call
|
||||
struct ObjPushConstant
|
||||
{
|
||||
nvmath::vec3f lightPosition{3.5f, 8.f, 5.f};
|
||||
nvmath::vec3f lightPosition{10.f, 15.f, 8.f};
|
||||
int instanceId{0}; // To retrieve the transformation matrix
|
||||
float lightIntensity{100.f};
|
||||
int lightType{0}; // 0: point, 1: infinite
|
||||
|
|
@ -101,41 +97,43 @@ public:
|
|||
std::vector<ObjInstance> m_objInstance;
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
VkPipelineLayout m_pipelineLayout;
|
||||
VkPipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
VkDescriptorPool m_descPool;
|
||||
VkDescriptorSetLayout m_descSetLayout;
|
||||
VkDescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||
|
||||
|
||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
|
||||
|
||||
// #Post
|
||||
void createOffscreenRender();
|
||||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
void updatePostDescriptorSet();
|
||||
void drawPost(vk::CommandBuffer cmdBuf);
|
||||
void drawPost(VkCommandBuffer cmdBuf);
|
||||
|
||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||
vk::DescriptorPool m_postDescPool;
|
||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
||||
vk::DescriptorSet m_postDescSet;
|
||||
vk::Pipeline m_postPipeline;
|
||||
vk::PipelineLayout m_postPipelineLayout;
|
||||
vk::RenderPass m_offscreenRenderPass;
|
||||
vk::Framebuffer m_offscreenFramebuffer;
|
||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
||||
nvvk::Texture m_offscreenColor;
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
||||
nvvk::Texture m_gBuffer;
|
||||
nvvk::Texture m_aoBuffer;
|
||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
vk::Format m_offscreenDepthFormat{vk::Format::eX8D24UnormPack32};
|
||||
|
||||
// #Tuto_rayquery
|
||||
void initRayTracing();
|
||||
|
|
@ -143,22 +141,23 @@ public:
|
|||
void createBottomLevelAS();
|
||||
void createTopLevelAS();
|
||||
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
|
||||
|
||||
// #Tuto_animation
|
||||
void createCompDescriptors();
|
||||
void updateCompDescriptors();
|
||||
void createCompPipelines();
|
||||
void runCompute(vk::CommandBuffer cmdBuf, AoControl& aoControl);
|
||||
void runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl);
|
||||
|
||||
nvvk::DescriptorSetBindings m_compDescSetLayoutBind;
|
||||
vk::DescriptorPool m_compDescPool;
|
||||
vk::DescriptorSetLayout m_compDescSetLayout;
|
||||
vk::DescriptorSet m_compDescSet;
|
||||
vk::Pipeline m_compPipeline;
|
||||
vk::PipelineLayout m_compPipelineLayout;
|
||||
VkDescriptorPool m_compDescPool;
|
||||
VkDescriptorSetLayout m_compDescSetLayout;
|
||||
VkDescriptorSet m_compDescSet;
|
||||
VkPipeline m_compPipeline;
|
||||
VkPipelineLayout m_compPipelineLayout;
|
||||
|
||||
// #Tuto_jitter_cam
|
||||
void updateFrame();
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@
|
|||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
#include "backends/imgui_impl_glfw.h"
|
||||
#include "imgui.h"
|
||||
|
||||
|
|
@ -36,7 +33,6 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
#include "nvh/cameramanipulator.hpp"
|
||||
#include "nvh/fileoperations.hpp"
|
||||
#include "nvpsystem.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/commands_vk.hpp"
|
||||
#include "nvvk/context_vk.hpp"
|
||||
|
||||
|
|
@ -48,6 +44,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|||
// Default search path for shaders
|
||||
std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
// GLFW Callback functions
|
||||
static void onErrorCallback(int error, const char* description)
|
||||
{
|
||||
|
|
@ -75,6 +72,7 @@ void renderUI(HelloVulkan& helloVk)
|
|||
static int const SAMPLE_WIDTH = 1280;
|
||||
static int const SAMPLE_HEIGHT = 720;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Application Entry
|
||||
//
|
||||
|
|
@ -89,8 +87,7 @@ int main(int argc, char** argv)
|
|||
return 1;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
GLFWwindow* window =
|
||||
glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
||||
|
||||
// Setup camera
|
||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
|
|
@ -117,9 +114,9 @@ int main(int argc, char** argv)
|
|||
nvvk::ContextCreateInfo contextInfo(true);
|
||||
contextInfo.setVersion(1, 2);
|
||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true);
|
||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true);
|
||||
#ifdef WIN32
|
||||
contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#ifdef _WIN32
|
||||
contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#else
|
||||
contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||
|
|
@ -129,19 +126,20 @@ int main(int argc, char** argv)
|
|||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
|
||||
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
// #VKRay: Activate the ray tracing extension
|
||||
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures;
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false,
|
||||
&accelFeatures);
|
||||
vk::PhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures;
|
||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeatures);
|
||||
VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR};
|
||||
contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures);
|
||||
|
||||
|
||||
// Creating Vulkan base application
|
||||
nvvk::Context vkctx{};
|
||||
vkctx.initInstance(contextInfo);
|
||||
|
|
@ -151,16 +149,14 @@ int main(int argc, char** argv)
|
|||
// Use a compatible device
|
||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
||||
|
||||
|
||||
// Create example
|
||||
HelloVulkan helloVk;
|
||||
|
||||
// Window need to be opened to get the surface on which to draw
|
||||
const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
||||
vkctx.setGCTQueueWithPresent(surface);
|
||||
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice,
|
||||
vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
||||
helloVk.createDepthBuffer();
|
||||
helloVk.createRenderPass();
|
||||
|
|
@ -241,8 +237,7 @@ int main(int argc, char** argv)
|
|||
helloVk.resetFrame();
|
||||
}
|
||||
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
||||
1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
||||
ImGuiH::Panel::End();
|
||||
}
|
||||
|
|
@ -251,66 +246,67 @@ int main(int argc, char** argv)
|
|||
helloVk.prepareFrame();
|
||||
|
||||
// Start command buffer of this frame
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
auto curFrame = helloVk.getCurFrame();
|
||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
||||
|
||||
cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
|
||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
||||
|
||||
// Updating camera buffer
|
||||
helloVk.updateUniformBuffer(cmdBuf);
|
||||
|
||||
// Clearing screen
|
||||
std::array<vk::ClearValue, 3> clearValues;
|
||||
clearValues[0].setColor(
|
||||
std::array<float, 4>({clearColor[0], clearColor[1], clearColor[2], clearColor[3]}));
|
||||
std::array<VkClearValue, 3> clearValues{};
|
||||
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
||||
|
||||
|
||||
// Offscreen render pass
|
||||
{
|
||||
clearValues[1].setColor(std::array<float, 4>{0, 0, 0, 0});
|
||||
clearValues[2].setDepthStencil({1.0f, 0});
|
||||
vk::RenderPassBeginInfo offscreenRenderPassBeginInfo;
|
||||
offscreenRenderPassBeginInfo.setClearValueCount(3);
|
||||
offscreenRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
||||
offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
clearValues[1].color = {{0, 0, 0, 0}};
|
||||
clearValues[2].depthStencil = {1.0f, 0};
|
||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
offscreenRenderPassBeginInfo.clearValueCount = (uint32_t)clearValues.size();
|
||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
// Rendering Scene
|
||||
{
|
||||
cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.rasterize(cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
helloVk.runCompute(cmdBuf, aoControl);
|
||||
}
|
||||
}
|
||||
|
||||
// 2nd rendering pass: tone mapper, UI
|
||||
{
|
||||
clearValues[1].setDepthStencil({1.0f, 0});
|
||||
vk::RenderPassBeginInfo postRenderPassBeginInfo;
|
||||
postRenderPassBeginInfo.setClearValueCount(2);
|
||||
postRenderPassBeginInfo.setPClearValues(clearValues.data());
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
clearValues[1].depthStencil = {1.0f, 0};
|
||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
||||
postRenderPassBeginInfo.clearValueCount = 2;
|
||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
helloVk.drawPost(cmdBuf);
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
||||
cmdBuf.endRenderPass();
|
||||
vkCmdEndRenderPass(cmdBuf);
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
vkEndCommandBuffer(cmdBuf);
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
catch(const std::system_error& e)
|
||||
{
|
||||
if(e.code() == vk::Result::eErrorDeviceLost)
|
||||
if(e.code().value() == VK_ERROR_DEVICE_LOST)
|
||||
{
|
||||
#if _WIN32
|
||||
MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1);
|
||||
|
|
@ -322,10 +318,10 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
vkDeviceWaitIdle(helloVk.getDevice());
|
||||
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
|
||||
vkctx.deinit();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue