Added basic VK_NV_ray_tracing example (wip)
This commit is contained in:
parent
aa915d2c24
commit
b8b3fac9b4
8 changed files with 784 additions and 0 deletions
11
data/shaders/nv_ray_tracing_basic/closesthit.rchit
Normal file
11
data/shaders/nv_ray_tracing_basic/closesthit.rchit
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#version 460
|
||||||
|
#extension GL_NV_ray_tracing : require
|
||||||
|
#extension GL_EXT_nonuniform_qualifier : enable
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadInNV vec3 hitValue;
|
||||||
|
hitAttributeNV vec3 attribs;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
hitValue = vec3(1.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
BIN
data/shaders/nv_ray_tracing_basic/closesthit.rchit.spv
Normal file
BIN
data/shaders/nv_ray_tracing_basic/closesthit.rchit.spv
Normal file
Binary file not shown.
9
data/shaders/nv_ray_tracing_basic/miss.rmiss
Normal file
9
data/shaders/nv_ray_tracing_basic/miss.rmiss
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#version 460
|
||||||
|
#extension GL_NV_ray_tracing : require
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadInNV vec3 hitValue;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
hitValue = vec3(0.0, 0.0, 0.2);
|
||||||
|
}
|
||||||
BIN
data/shaders/nv_ray_tracing_basic/miss.rmiss.spv
Normal file
BIN
data/shaders/nv_ray_tracing_basic/miss.rmiss.spv
Normal file
Binary file not shown.
32
data/shaders/nv_ray_tracing_basic/raygen.rgen
Normal file
32
data/shaders/nv_ray_tracing_basic/raygen.rgen
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#version 460
|
||||||
|
#extension GL_NV_ray_tracing : require
|
||||||
|
|
||||||
|
layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
|
||||||
|
layout(binding = 1, set = 0, rgba8) uniform image2D image;
|
||||||
|
layout(binding = 2, set = 0) uniform CameraProperties
|
||||||
|
{
|
||||||
|
mat4 viewInverse;
|
||||||
|
mat4 projInverse;
|
||||||
|
} cam;
|
||||||
|
|
||||||
|
layout(location = 0) rayPayloadNV vec3 hitValue;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
const vec2 pixelCenter = vec2(gl_LaunchIDNV.xy) + vec2(0.5);
|
||||||
|
const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeNV.xy);
|
||||||
|
vec2 d = inUV * 2.0 - 1.0;
|
||||||
|
|
||||||
|
vec4 origin = cam.viewInverse * vec4(0,0,0,1);
|
||||||
|
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1) ;
|
||||||
|
vec4 direction = cam.viewInverse*vec4(normalize(target.xyz), 0) ;
|
||||||
|
|
||||||
|
uint rayFlags = gl_RayFlagsOpaqueNV;
|
||||||
|
uint cullMask = 0xff;
|
||||||
|
float tmin = 0.001;
|
||||||
|
float tmax = 10000.0;
|
||||||
|
|
||||||
|
traceNV(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
|
||||||
|
|
||||||
|
imageStore(image, ivec2(gl_LaunchIDNV.xy), vec4(hitValue, 0.0));
|
||||||
|
}
|
||||||
BIN
data/shaders/nv_ray_tracing_basic/raygen.rgen.spv
Normal file
BIN
data/shaders/nv_ray_tracing_basic/raygen.rgen.spv
Normal file
Binary file not shown.
|
|
@ -74,6 +74,7 @@ set(EXAMPLES
|
||||||
multithreading
|
multithreading
|
||||||
multiview
|
multiview
|
||||||
negativeviewportheight
|
negativeviewportheight
|
||||||
|
nv_ray_tracing_basic
|
||||||
occlusionquery
|
occlusionquery
|
||||||
offscreen
|
offscreen
|
||||||
parallaxmapping
|
parallaxmapping
|
||||||
|
|
|
||||||
731
examples/nv_ray_tracing_basic/nv_ray_tracing_basic.cpp
Normal file
731
examples/nv_ray_tracing_basic/nv_ray_tracing_basic.cpp
Normal file
|
|
@ -0,0 +1,731 @@
|
||||||
|
/*
|
||||||
|
* Vulkan Example - Basic example for ray tracing using VK_NV_ray_tracing
|
||||||
|
*
|
||||||
|
* Copyright (C) by Sascha Willems - www.saschawillems.de
|
||||||
|
*
|
||||||
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define GLM_FORCE_RADIANS
|
||||||
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <gli/gli.hpp>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include "vulkanexamplebase.h"
|
||||||
|
#include "VulkanDevice.hpp"
|
||||||
|
#include "VulkanBuffer.hpp"
|
||||||
|
|
||||||
|
#define ENABLE_VALIDATION false
|
||||||
|
|
||||||
|
// Ray tracing acceleration structure
|
||||||
|
struct AccelerationStructure {
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
VkAccelerationStructureInfoNV accelerationStructureInfo;
|
||||||
|
VkAccelerationStructureNV accelerationStructure;
|
||||||
|
uint64_t handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ray tracing geometry instance
|
||||||
|
struct GeometryInstance {
|
||||||
|
float transform[12];
|
||||||
|
uint32_t instanceId : 24;
|
||||||
|
uint32_t mask : 8;
|
||||||
|
uint32_t instanceOffset : 24;
|
||||||
|
uint32_t flags : 8;
|
||||||
|
uint64_t accelerationStructureHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Indices for the different ray tracing shader types used in this example
|
||||||
|
#define SHADER_INDEX_RAYGEN 0
|
||||||
|
#define SHADER_INDEX_MISS 1
|
||||||
|
#define SHADER_INDEX_CLOSEST_HIT 2
|
||||||
|
|
||||||
|
class VulkanExample : public VulkanExampleBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV;
|
||||||
|
PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV;
|
||||||
|
PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV;
|
||||||
|
PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV;
|
||||||
|
PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV;
|
||||||
|
PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV;
|
||||||
|
PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV;
|
||||||
|
PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV;
|
||||||
|
|
||||||
|
VkPhysicalDeviceRayTracingPropertiesNV rayTracingProperties{};
|
||||||
|
|
||||||
|
AccelerationStructure bottomLevelAS;
|
||||||
|
AccelerationStructure topLevelAS;
|
||||||
|
|
||||||
|
vks::Buffer vertexBuffer;
|
||||||
|
vks::Buffer indexBuffer;
|
||||||
|
uint32_t indexCount;
|
||||||
|
vks::Buffer shaderBindingTable;
|
||||||
|
|
||||||
|
struct StorageImage {
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
VkImage image;
|
||||||
|
VkImageView view;
|
||||||
|
VkFormat format;
|
||||||
|
} storageImage;
|
||||||
|
|
||||||
|
struct UniformData {
|
||||||
|
glm::mat4 viewInverse;
|
||||||
|
glm::mat4 projInverse;
|
||||||
|
} uniformData;
|
||||||
|
vks::Buffer ubo;
|
||||||
|
|
||||||
|
VkPipeline pipeline;
|
||||||
|
VkPipelineLayout pipelineLayout;
|
||||||
|
VkDescriptorSet descriptorSet;
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout;
|
||||||
|
|
||||||
|
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||||
|
{
|
||||||
|
title = "VK_NV_ray_tracing";
|
||||||
|
settings.overlay = true;
|
||||||
|
camera.type = Camera::CameraType::lookat;
|
||||||
|
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
|
||||||
|
camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||||
|
camera.setTranslation(glm::vec3(0.0f, 0.0f, -2.5f));
|
||||||
|
// Enable instance and device extensions required to use VK_NV_ray_tracing
|
||||||
|
enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||||
|
enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
enabledDeviceExtensions.push_back(VK_NV_RAY_TRACING_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
~VulkanExample()
|
||||||
|
{
|
||||||
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||||
|
|
||||||
|
vertexBuffer.destroy();
|
||||||
|
indexBuffer.destroy();
|
||||||
|
ubo.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set up a storage image that the ray generation shader will be writing to
|
||||||
|
*/
|
||||||
|
void createStorageImage()
|
||||||
|
{
|
||||||
|
VkImageCreateInfo image = vks::initializers::imageCreateInfo();
|
||||||
|
image.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
image.format = swapChain.colorFormat;
|
||||||
|
image.extent.width = width;
|
||||||
|
image.extent.height = height;
|
||||||
|
image.extent.depth = 1;
|
||||||
|
image.mipLevels = 1;
|
||||||
|
image.arrayLayers = 1;
|
||||||
|
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
|
||||||
|
image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &storageImage.image));
|
||||||
|
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
vkGetImageMemoryRequirements(device, storageImage.image, &memReqs);
|
||||||
|
VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
|
||||||
|
memoryAllocateInfo.allocationSize = memReqs.size;
|
||||||
|
memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &storageImage.memory));
|
||||||
|
VK_CHECK_RESULT(vkBindImageMemory(device, storageImage.image, storageImage.memory, 0));
|
||||||
|
|
||||||
|
VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
|
||||||
|
colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
colorImageView.format = swapChain.colorFormat;
|
||||||
|
colorImageView.subresourceRange = {};
|
||||||
|
colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
colorImageView.subresourceRange.baseMipLevel = 0;
|
||||||
|
colorImageView.subresourceRange.levelCount = 1;
|
||||||
|
colorImageView.subresourceRange.baseArrayLayer = 0;
|
||||||
|
colorImageView.subresourceRange.layerCount = 1;
|
||||||
|
colorImageView.image = storageImage.image;
|
||||||
|
VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &storageImage.view));
|
||||||
|
|
||||||
|
VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
|
vks::tools::setImageLayout(cmdBuffer, storageImage.image,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
|
||||||
|
vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The bottom level acceleration structure contains the scene's geometry (vertices, triangles)
|
||||||
|
*/
|
||||||
|
void createBottomLevelAccelerationStructure(const VkGeometryNV* geometries)
|
||||||
|
{
|
||||||
|
VkAccelerationStructureInfoNV accelerationStructureInfo{};
|
||||||
|
accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
|
||||||
|
accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
|
||||||
|
accelerationStructureInfo.instanceCount = 0;
|
||||||
|
accelerationStructureInfo.geometryCount = 1;
|
||||||
|
accelerationStructureInfo.pGeometries = geometries;
|
||||||
|
|
||||||
|
VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
|
||||||
|
accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
|
||||||
|
accelerationStructureCI.info = accelerationStructureInfo;
|
||||||
|
VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &bottomLevelAS.accelerationStructure));
|
||||||
|
|
||||||
|
VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
|
||||||
|
memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
|
||||||
|
memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
|
||||||
|
|
||||||
|
VkMemoryRequirements2 memoryRequirements2{};
|
||||||
|
vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
|
||||||
|
memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
|
||||||
|
memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &bottomLevelAS.memory));
|
||||||
|
|
||||||
|
VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
|
||||||
|
accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
|
||||||
|
accelerationStructureMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
|
||||||
|
accelerationStructureMemoryInfo.memory = bottomLevelAS.memory;
|
||||||
|
VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, bottomLevelAS.accelerationStructure, sizeof(uint64_t), &bottomLevelAS.handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The top level acceleration structure contains the scene's object instances
|
||||||
|
*/
|
||||||
|
void createTopLevelAccelerationStructure()
|
||||||
|
{
|
||||||
|
VkAccelerationStructureInfoNV accelerationStructureInfo{};
|
||||||
|
accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
|
||||||
|
accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV;
|
||||||
|
accelerationStructureInfo.instanceCount = 1;
|
||||||
|
accelerationStructureInfo.geometryCount = 0;
|
||||||
|
|
||||||
|
VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
|
||||||
|
accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
|
||||||
|
accelerationStructureCI.info = accelerationStructureInfo;
|
||||||
|
VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &topLevelAS.accelerationStructure));
|
||||||
|
|
||||||
|
VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
|
||||||
|
memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
|
||||||
|
memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
|
||||||
|
|
||||||
|
VkMemoryRequirements2 memoryRequirements2{};
|
||||||
|
vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
|
||||||
|
memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
|
||||||
|
memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &topLevelAS.memory));
|
||||||
|
|
||||||
|
VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
|
||||||
|
accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
|
||||||
|
accelerationStructureMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure;
|
||||||
|
accelerationStructureMemoryInfo.memory = topLevelAS.memory;
|
||||||
|
VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, topLevelAS.accelerationStructure, sizeof(uint64_t), &topLevelAS.handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create scene geometry and ray tracing acceleration structures
|
||||||
|
*/
|
||||||
|
void createScene()
|
||||||
|
{
|
||||||
|
// Setup vertices for a single uv-mapped quad made from two triangles
|
||||||
|
struct Vertex {
|
||||||
|
float pos[4];
|
||||||
|
};
|
||||||
|
std::vector<Vertex> vertices = {
|
||||||
|
{ { 1.0f, 1.0f, 0.0f, 1.0f } },
|
||||||
|
{ { -1.0f, 1.0f, 0.0f, 1.0f } },
|
||||||
|
{ { 0.0f, -1.0f, 0.0f, 1.0f } }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup indices
|
||||||
|
std::vector<uint32_t> indices = { 0, 1, 2 };
|
||||||
|
indexCount = static_cast<uint32_t>(indices.size());
|
||||||
|
|
||||||
|
// Create buffers
|
||||||
|
// For the sake of simplicity we won't stage the vertex data to the gpu memory
|
||||||
|
// Vertex buffer
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&vertexBuffer,
|
||||||
|
vertices.size() * sizeof(Vertex),
|
||||||
|
vertices.data()));
|
||||||
|
// Index buffer
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&indexBuffer,
|
||||||
|
indices.size() * sizeof(uint32_t),
|
||||||
|
indices.data()));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the bottom level acceleration structure containing the actual scene geometry
|
||||||
|
*/
|
||||||
|
VkGeometryNV geometry{};
|
||||||
|
geometry.sType = VK_STRUCTURE_TYPE_GEOMETRY_NV;
|
||||||
|
geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_NV;
|
||||||
|
geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV;
|
||||||
|
geometry.geometry.triangles.vertexData = vertexBuffer.buffer;
|
||||||
|
geometry.geometry.triangles.vertexOffset = 0;
|
||||||
|
geometry.geometry.triangles.vertexCount = static_cast<uint32_t>(vertices.size());
|
||||||
|
geometry.geometry.triangles.vertexStride = sizeof(Vertex);
|
||||||
|
geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
geometry.geometry.triangles.indexData = indexBuffer.buffer;
|
||||||
|
geometry.geometry.triangles.indexOffset = 0;
|
||||||
|
geometry.geometry.triangles.indexCount = indexCount;
|
||||||
|
geometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
|
geometry.geometry.triangles.transformData = VK_NULL_HANDLE;
|
||||||
|
geometry.geometry.triangles.transformOffset = 0;
|
||||||
|
geometry.geometry.aabbs = {};
|
||||||
|
geometry.geometry.aabbs.sType = { VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV };
|
||||||
|
geometry.flags = VK_GEOMETRY_OPAQUE_BIT_NV;
|
||||||
|
|
||||||
|
createBottomLevelAccelerationStructure(&geometry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the top-level acceleration structure that contains geometry instance information
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Single instance with a 3x3 transform matrix for the ray traced triangle
|
||||||
|
vks::Buffer instanceBuffer;
|
||||||
|
const float transform[12] = {
|
||||||
|
1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
GeometryInstance instance{};
|
||||||
|
std::memcpy(instance.transform, transform, sizeof(transform));
|
||||||
|
instance.instanceId = 0;
|
||||||
|
instance.mask = 0xff;
|
||||||
|
instance.instanceOffset = 0;
|
||||||
|
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV;
|
||||||
|
instance.accelerationStructureHandle = bottomLevelAS.handle;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&instanceBuffer,
|
||||||
|
sizeof(instance),
|
||||||
|
&instance));
|
||||||
|
|
||||||
|
createTopLevelAccelerationStructure();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Build the acceleration structure
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Acceleration structure build requires some scratch space to store temporary information
|
||||||
|
VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
|
||||||
|
memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
|
||||||
|
memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
|
||||||
|
|
||||||
|
VkMemoryRequirements2 memReqBottomLevelAS;
|
||||||
|
memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
|
||||||
|
vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqBottomLevelAS);
|
||||||
|
|
||||||
|
VkMemoryRequirements2 memReqTopLevelAS;
|
||||||
|
memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
|
||||||
|
vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqTopLevelAS);
|
||||||
|
|
||||||
|
const VkDeviceSize scratchBufferSize = std::max(memReqBottomLevelAS.memoryRequirements.size, memReqTopLevelAS.memoryRequirements.size);
|
||||||
|
|
||||||
|
vks::Buffer scratchBuffer;
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
&scratchBuffer,
|
||||||
|
scratchBufferSize));
|
||||||
|
|
||||||
|
VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Build bottom level acceleration structure
|
||||||
|
*/
|
||||||
|
VkAccelerationStructureInfoNV buildInfo{};
|
||||||
|
buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
|
||||||
|
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
|
||||||
|
buildInfo.geometryCount = 1;
|
||||||
|
buildInfo.pGeometries = &geometry;
|
||||||
|
|
||||||
|
vkCmdBuildAccelerationStructureNV(
|
||||||
|
cmdBuffer,
|
||||||
|
&buildInfo,
|
||||||
|
VK_NULL_HANDLE,
|
||||||
|
0,
|
||||||
|
VK_FALSE,
|
||||||
|
bottomLevelAS.accelerationStructure,
|
||||||
|
VK_NULL_HANDLE,
|
||||||
|
scratchBuffer.buffer,
|
||||||
|
0);
|
||||||
|
|
||||||
|
VkMemoryBarrier memoryBarrier = vks::initializers::memoryBarrier();
|
||||||
|
memoryBarrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
|
||||||
|
memoryBarrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
|
||||||
|
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Build top-level acceleration structure
|
||||||
|
*/
|
||||||
|
buildInfo.pGeometries = 0;
|
||||||
|
buildInfo.geometryCount = 0;
|
||||||
|
buildInfo.instanceCount = 1;
|
||||||
|
|
||||||
|
vkCmdBuildAccelerationStructureNV(
|
||||||
|
cmdBuffer,
|
||||||
|
&buildInfo,
|
||||||
|
instanceBuffer.buffer,
|
||||||
|
0,
|
||||||
|
VK_FALSE,
|
||||||
|
topLevelAS.accelerationStructure,
|
||||||
|
VK_NULL_HANDLE,
|
||||||
|
scratchBuffer.buffer,
|
||||||
|
0);
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
|
||||||
|
|
||||||
|
scratchBuffer.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize copyShaderIdentifier(uint8_t* data, const uint8_t* shaderHandleStorage, uint32_t groupIndex) {
|
||||||
|
const uint32_t shaderGroupHandleSize = rayTracingProperties.shaderGroupHandleSize;
|
||||||
|
memcpy(data, shaderHandleStorage + groupIndex * shaderGroupHandleSize, shaderGroupHandleSize);
|
||||||
|
data += shaderGroupHandleSize;
|
||||||
|
return shaderGroupHandleSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the Shader Binding Table that binds the programs and top-level acceleration structure
|
||||||
|
*/
|
||||||
|
void createShaderBindingTable() {
|
||||||
|
// Create buffer for the shader binding table
|
||||||
|
const uint32_t sbtSize = rayTracingProperties.shaderGroupHandleSize * 3;
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
|
||||||
|
&shaderBindingTable,
|
||||||
|
sbtSize));
|
||||||
|
shaderBindingTable.map();
|
||||||
|
|
||||||
|
auto shaderHandleStorage = new uint8_t[sbtSize];
|
||||||
|
// Get shader identifiers
|
||||||
|
VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesNV(device, pipeline, 0, 3, sbtSize, shaderHandleStorage));
|
||||||
|
auto* data = static_cast<uint8_t*>(shaderBindingTable.mapped);
|
||||||
|
// Copy the shader identifiers to the shader binding table
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
data += copyShaderIdentifier(data, shaderHandleStorage, SHADER_INDEX_RAYGEN);
|
||||||
|
data += copyShaderIdentifier(data, shaderHandleStorage, SHADER_INDEX_MISS);
|
||||||
|
data += copyShaderIdentifier(data, shaderHandleStorage, SHADER_INDEX_CLOSEST_HIT);
|
||||||
|
shaderBindingTable.unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the descriptor sets used for the ray tracing dispatch
|
||||||
|
*/
|
||||||
|
void createDescriptorSets()
|
||||||
|
{
|
||||||
|
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||||
|
{ VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1 },
|
||||||
|
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
|
||||||
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 }
|
||||||
|
};
|
||||||
|
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
|
||||||
|
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
||||||
|
|
||||||
|
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
|
||||||
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
|
||||||
|
|
||||||
|
VkWriteDescriptorSetAccelerationStructureNV descriptorAccelerationStructureInfo{};
|
||||||
|
descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV;
|
||||||
|
descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
|
||||||
|
descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure;
|
||||||
|
|
||||||
|
VkWriteDescriptorSet accelerationStructureWrite{};
|
||||||
|
accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
// The specialized acceleration structure descriptor has to be chained
|
||||||
|
accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
|
||||||
|
accelerationStructureWrite.dstSet = descriptorSet;
|
||||||
|
accelerationStructureWrite.dstBinding = 0;
|
||||||
|
accelerationStructureWrite.descriptorCount = 1;
|
||||||
|
accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
|
||||||
|
|
||||||
|
VkDescriptorImageInfo storageImageDescriptor{};
|
||||||
|
storageImageDescriptor.imageView = storageImage.view;
|
||||||
|
storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
|
||||||
|
VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
|
||||||
|
VkWriteDescriptorSet uniformBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor);
|
||||||
|
|
||||||
|
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
|
||||||
|
accelerationStructureWrite,
|
||||||
|
resultImageWrite,
|
||||||
|
uniformBufferWrite
|
||||||
|
};
|
||||||
|
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create our ray tracing pipeline
|
||||||
|
*/
|
||||||
|
void createRayTracingPipeline()
|
||||||
|
{
|
||||||
|
VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding{};
|
||||||
|
accelerationStructureLayoutBinding.binding = 0;
|
||||||
|
accelerationStructureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
|
||||||
|
accelerationStructureLayoutBinding.descriptorCount = 1;
|
||||||
|
accelerationStructureLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding resultImageLayoutBinding{};
|
||||||
|
resultImageLayoutBinding.binding = 1;
|
||||||
|
resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||||
|
resultImageLayoutBinding.descriptorCount = 1;
|
||||||
|
resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding uniformBufferBinding{};
|
||||||
|
uniformBufferBinding.binding = 2;
|
||||||
|
uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
uniformBufferBinding.descriptorCount = 1;
|
||||||
|
uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSetLayoutBinding> bindings({
|
||||||
|
accelerationStructureLayoutBinding,
|
||||||
|
resultImageLayoutBinding,
|
||||||
|
uniformBufferBinding
|
||||||
|
});
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
||||||
|
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
|
||||||
|
layoutInfo.pBindings = bindings.data();
|
||||||
|
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout));
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
|
||||||
|
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipelineLayoutCreateInfo.setLayoutCount = 1;
|
||||||
|
pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||||
|
|
||||||
|
std::array<VkPipelineShaderStageCreateInfo, 3> shaderStages;
|
||||||
|
shaderStages[SHADER_INDEX_RAYGEN] = loadShader(getAssetPath() + "shaders/nv_ray_tracing_basic/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_NV);
|
||||||
|
shaderStages[SHADER_INDEX_MISS] = loadShader(getAssetPath() + "shaders/nv_ray_tracing_basic/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_NV);
|
||||||
|
shaderStages[SHADER_INDEX_CLOSEST_HIT] = loadShader(getAssetPath() + "shaders/nv_ray_tracing_basic/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setup ray tracing shader groups
|
||||||
|
*/
|
||||||
|
std::array<VkRayTracingShaderGroupCreateInfoNV, 3> groups{};
|
||||||
|
for (auto& group : groups) {
|
||||||
|
// Init all groups with some default values
|
||||||
|
group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV;
|
||||||
|
group.generalShader = VK_SHADER_UNUSED_NV;
|
||||||
|
group.closestHitShader = VK_SHADER_UNUSED_NV;
|
||||||
|
group.anyHitShader = VK_SHADER_UNUSED_NV;
|
||||||
|
group.intersectionShader = VK_SHADER_UNUSED_NV;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Links shaders and types to ray tracing shader groups
|
||||||
|
groups[SHADER_INDEX_RAYGEN].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
|
||||||
|
groups[SHADER_INDEX_RAYGEN].generalShader = SHADER_INDEX_RAYGEN;
|
||||||
|
groups[SHADER_INDEX_MISS].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
|
||||||
|
groups[SHADER_INDEX_MISS].generalShader = SHADER_INDEX_MISS;
|
||||||
|
groups[SHADER_INDEX_CLOSEST_HIT].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV;
|
||||||
|
groups[SHADER_INDEX_CLOSEST_HIT].generalShader = VK_SHADER_UNUSED_NV;
|
||||||
|
groups[SHADER_INDEX_CLOSEST_HIT].closestHitShader = SHADER_INDEX_CLOSEST_HIT;
|
||||||
|
|
||||||
|
VkRayTracingPipelineCreateInfoNV rayPipelineInfo{};
|
||||||
|
rayPipelineInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV;
|
||||||
|
rayPipelineInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||||
|
rayPipelineInfo.pStages = shaderStages.data();
|
||||||
|
rayPipelineInfo.groupCount = static_cast<uint32_t>(groups.size());
|
||||||
|
rayPipelineInfo.pGroups = groups.data();
|
||||||
|
rayPipelineInfo.maxRecursionDepth = 1;
|
||||||
|
rayPipelineInfo.layout = pipelineLayout;
|
||||||
|
VK_CHECK_RESULT(vkCreateRayTracingPipelinesNV(device, nullptr, 1, &rayPipelineInfo, nullptr, &pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
|
||||||
|
*/
|
||||||
|
void createUniformBuffer()
|
||||||
|
{
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&ubo,
|
||||||
|
sizeof(uniformData),
|
||||||
|
&uniformData));
|
||||||
|
VK_CHECK_RESULT(ubo.map());
|
||||||
|
|
||||||
|
updateUniformBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Command buffer generation
|
||||||
|
*/
|
||||||
|
void buildCommandBuffers()
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
||||||
|
|
||||||
|
VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
|
||||||
|
{
|
||||||
|
VkClearValue clearValues[2];
|
||||||
|
clearValues[0].color = defaultClearColor;
|
||||||
|
clearValues[1].depthStencil = { 1.0f, 0 };
|
||||||
|
|
||||||
|
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
|
||||||
|
renderPassBeginInfo.renderPass = renderPass;
|
||||||
|
renderPassBeginInfo.framebuffer = frameBuffers[i];
|
||||||
|
renderPassBeginInfo.renderArea.extent.width = width;
|
||||||
|
renderPassBeginInfo.renderArea.extent.height = height;
|
||||||
|
renderPassBeginInfo.clearValueCount = 2;
|
||||||
|
renderPassBeginInfo.pClearValues = clearValues;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dispatch the ray tracing commands
|
||||||
|
*/
|
||||||
|
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipeline);
|
||||||
|
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
|
||||||
|
|
||||||
|
// Calculate shader binding offsets, which is pretty straight forward in our example
|
||||||
|
VkDeviceSize bindingOffsetRayGenShader = 0;
|
||||||
|
VkDeviceSize bindingOffsetMissShader = rayTracingProperties.shaderGroupHandleSize;
|
||||||
|
VkDeviceSize bindingOffsetHitShader = rayTracingProperties.shaderGroupHandleSize * 2;
|
||||||
|
VkDeviceSize bindingStride = rayTracingProperties.shaderGroupHandleSize;
|
||||||
|
|
||||||
|
vkCmdTraceRaysNV(drawCmdBuffers[i],
|
||||||
|
shaderBindingTable.buffer, bindingOffsetRayGenShader,
|
||||||
|
shaderBindingTable.buffer, bindingOffsetMissShader, bindingStride,
|
||||||
|
shaderBindingTable.buffer, bindingOffsetHitShader, bindingStride,
|
||||||
|
VK_NULL_HANDLE, 0, 0,
|
||||||
|
width, height, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copy raytracing output to swap chain image
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Prepare current swapchain image as transfer destination
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
swapChain.images[i],
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
// Prepare ray tracing output image as transfer source
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
storageImage.image,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
VkImageCopy copyRegion{};
|
||||||
|
copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||||
|
copyRegion.srcOffset = { 0, 0, 0 };
|
||||||
|
copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
|
||||||
|
copyRegion.dstOffset = { 0, 0, 0 };
|
||||||
|
copyRegion.extent = { width, height, 1 };
|
||||||
|
vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
|
||||||
|
|
||||||
|
// Transition swap chain image back for presentation
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
swapChain.images[i],
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
// Transition ray tracing output image back to general layout
|
||||||
|
vks::tools::setImageLayout(
|
||||||
|
drawCmdBuffers[i],
|
||||||
|
storageImage.image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
subresourceRange);
|
||||||
|
|
||||||
|
//@todo: Default render pass setup willl overwrite contents
|
||||||
|
//vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
//drawUI(drawCmdBuffers[i]);
|
||||||
|
//vkCmdEndRenderPass(drawCmdBuffers[i]);
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateUniformBuffers()
|
||||||
|
{
|
||||||
|
uniformData.projInverse = glm::inverse(camera.matrices.perspective);
|
||||||
|
uniformData.viewInverse = glm::inverse(camera.matrices.view);
|
||||||
|
memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare()
|
||||||
|
{
|
||||||
|
VulkanExampleBase::prepare();
|
||||||
|
|
||||||
|
// Query the ray tracing properties of the current implementation, we will need them later on
|
||||||
|
rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV;
|
||||||
|
VkPhysicalDeviceProperties2 deviceProps2{};
|
||||||
|
deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||||
|
deviceProps2.pNext = &rayTracingProperties;
|
||||||
|
vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2);
|
||||||
|
|
||||||
|
// Get VK_NV_ray_tracing related function pointers
|
||||||
|
vkCreateAccelerationStructureNV = reinterpret_cast<PFN_vkCreateAccelerationStructureNV>(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureNV"));
|
||||||
|
vkBindAccelerationStructureMemoryNV = reinterpret_cast<PFN_vkBindAccelerationStructureMemoryNV>(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryNV"));
|
||||||
|
vkGetAccelerationStructureHandleNV = reinterpret_cast<PFN_vkGetAccelerationStructureHandleNV>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureHandleNV"));
|
||||||
|
vkGetAccelerationStructureMemoryRequirementsNV = reinterpret_cast<PFN_vkGetAccelerationStructureMemoryRequirementsNV>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsNV"));
|
||||||
|
vkCmdBuildAccelerationStructureNV = reinterpret_cast<PFN_vkCmdBuildAccelerationStructureNV>(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV"));
|
||||||
|
vkCreateRayTracingPipelinesNV = reinterpret_cast<PFN_vkCreateRayTracingPipelinesNV>(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesNV"));
|
||||||
|
vkGetRayTracingShaderGroupHandlesNV = reinterpret_cast<PFN_vkGetRayTracingShaderGroupHandlesNV>(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesNV"));
|
||||||
|
vkCmdTraceRaysNV = reinterpret_cast<PFN_vkCmdTraceRaysNV>(vkGetDeviceProcAddr(device, "vkCmdTraceRaysNV"));
|
||||||
|
|
||||||
|
createScene();
|
||||||
|
createStorageImage();
|
||||||
|
createUniformBuffer();
|
||||||
|
createRayTracingPipeline();
|
||||||
|
createShaderBindingTable();
|
||||||
|
createDescriptorSets();
|
||||||
|
buildCommandBuffers();
|
||||||
|
prepared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw()
|
||||||
|
{
|
||||||
|
VulkanExampleBase::prepareFrame();
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
||||||
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||||
|
VulkanExampleBase::submitFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void render()
|
||||||
|
{
|
||||||
|
if (!prepared)
|
||||||
|
return;
|
||||||
|
draw();
|
||||||
|
if (camera.updated)
|
||||||
|
updateUniformBuffers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VULKAN_EXAMPLE_MAIN()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue