2019-07-25 11:52:09 +00:00
// Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// VulkanHpp Samples : RayTracing
// Simple sample how to ray trace using Vulkan
# include <numeric>
# include <random>
# include <sstream>
# include <vulkan/vulkan.hpp>
# include <GLFW/glfw3.h>
# define GLM_FORCE_DEPTH_ZERO_TO_ONE
# define GLM_FORCE_RADIANS
# define GLM_ENABLE_EXPERIMENTAL
# pragma warning(disable:4201) // disable warning C4201: nonstandard extension used: nameless struct/union; needed to get glm/detail/type_vec?.hpp without warnings
# include <glm/glm.hpp>
# include <glm/gtc/matrix_inverse.hpp>
# include <glm/gtc/matrix_transform.hpp>
# include "CameraManipulator.hpp"
2020-01-28 09:16:10 +00:00
# include "../utils/shaders.hpp"
# include "../utils/utils.hpp"
2019-07-25 11:52:09 +00:00
# include "SPIRV/GlslangToSpv.h"
static char const * AppName = " RayTracing " ;
static char const * EngineName = " Vulkan.hpp " ;
struct GeometryInstanceData
{
GeometryInstanceData ( glm : : mat4x4 const & transform_ , uint32_t instanceID_ , uint8_t mask_ , uint32_t instanceOffset_ , uint8_t flags_ , uint64_t accelerationStructureHandle_ )
: instanceId ( instanceID_ )
, mask ( mask_ )
, instanceOffset ( instanceOffset_ )
, flags ( flags_ )
, accelerationStructureHandle ( accelerationStructureHandle_ )
{
assert ( ! ( instanceID_ & 0xFF000000 ) & & ! ( instanceOffset_ & 0xFF000000 ) ) ;
memcpy ( transform , & transform_ , 12 * sizeof ( float ) ) ;
}
float transform [ 12 ] ; // Transform matrix, containing only the top 3 rows
uint32_t instanceId : 24 ; // Instance index
uint32_t mask : 8 ; // Visibility mask
uint32_t instanceOffset : 24 ; // Index of the hit group which will be invoked when a ray hits the instance
uint32_t flags : 8 ; // Instance flags, such as culling
uint64_t accelerationStructureHandle ; // Opaque handle of the bottom-level acceleration structure
} ;
static_assert ( sizeof ( GeometryInstanceData ) = = 64 , " GeometryInstanceData structure compiles to incorrect size " ) ;
struct AccelerationStructureData
{
2019-09-26 07:55:15 +00:00
vk : : UniqueAccelerationStructureNV acclerationStructure ;
std : : unique_ptr < vk : : su : : BufferData > scratchBufferData ;
std : : unique_ptr < vk : : su : : BufferData > resultBufferData ;
std : : unique_ptr < vk : : su : : BufferData > instanceBufferData ;
2019-07-25 11:52:09 +00:00
} ;
AccelerationStructureData createAccelerationStructureData ( vk : : PhysicalDevice const & physicalDevice , vk : : UniqueDevice const & device , vk : : UniqueCommandBuffer const & commandBuffer ,
2019-09-26 07:55:15 +00:00
std : : vector < std : : pair < vk : : AccelerationStructureNV , glm : : mat4x4 > > const & instances , std : : vector < vk : : GeometryNV > const & geometries )
2019-07-25 11:52:09 +00:00
{
assert ( instances . empty ( ) ^ geometries . empty ( ) ) ;
AccelerationStructureData accelerationStructureData ;
vk : : AccelerationStructureTypeNV accelerationStructureType = instances . empty ( ) ? vk : : AccelerationStructureTypeNV : : eBottomLevel : vk : : AccelerationStructureTypeNV : : eTopLevel ;
vk : : AccelerationStructureInfoNV accelerationStructureInfo ( accelerationStructureType , { } , vk : : su : : checked_cast < uint32_t > ( instances . size ( ) ) ,
vk : : su : : checked_cast < uint32_t > ( geometries . size ( ) ) , geometries . data ( ) ) ;
2019-09-26 07:55:15 +00:00
accelerationStructureData . acclerationStructure = device - > createAccelerationStructureNVUnique ( vk : : AccelerationStructureCreateInfoNV ( 0 , accelerationStructureInfo ) ) ;
2019-07-25 11:52:09 +00:00
vk : : AccelerationStructureMemoryRequirementsInfoNV objectRequirements ( vk : : AccelerationStructureMemoryRequirementsTypeNV : : eObject , * accelerationStructureData . acclerationStructure ) ;
2019-09-26 07:55:15 +00:00
vk : : DeviceSize resultSizeInBytes = device - > getAccelerationStructureMemoryRequirementsNV ( objectRequirements ) . memoryRequirements . size ;
2019-07-25 11:52:09 +00:00
assert ( 0 < resultSizeInBytes ) ;
2020-01-30 19:51:32 +00:00
accelerationStructureData . resultBufferData = std : : unique_ptr < vk : : su : : BufferData > ( new vk : : su : : BufferData ( physicalDevice , device , resultSizeInBytes , vk : : BufferUsageFlagBits : : eRayTracingNV ,
vk : : MemoryPropertyFlagBits : : eDeviceLocal ) ) ;
2019-07-25 11:52:09 +00:00
vk : : AccelerationStructureMemoryRequirementsInfoNV buildScratchRequirements ( vk : : AccelerationStructureMemoryRequirementsTypeNV : : eBuildScratch ,
* accelerationStructureData . acclerationStructure ) ;
vk : : AccelerationStructureMemoryRequirementsInfoNV updateScratchRequirements ( vk : : AccelerationStructureMemoryRequirementsTypeNV : : eUpdateScratch ,
* accelerationStructureData . acclerationStructure ) ;
vk : : DeviceSize scratchSizeInBytes =
2019-09-26 07:55:15 +00:00
std : : max ( device - > getAccelerationStructureMemoryRequirementsNV ( buildScratchRequirements ) . memoryRequirements . size ,
device - > getAccelerationStructureMemoryRequirementsNV ( updateScratchRequirements ) . memoryRequirements . size ) ;
2019-07-25 11:52:09 +00:00
assert ( 0 < scratchSizeInBytes ) ;
2020-01-30 19:51:32 +00:00
accelerationStructureData . scratchBufferData = std : : unique_ptr < vk : : su : : BufferData > ( new vk : : su : : BufferData ( physicalDevice , device , scratchSizeInBytes , vk : : BufferUsageFlagBits : : eRayTracingNV ,
vk : : MemoryPropertyFlagBits : : eDeviceLocal ) ) ;
2019-07-25 11:52:09 +00:00
if ( ! instances . empty ( ) )
{
2020-01-30 19:51:32 +00:00
accelerationStructureData . instanceBufferData = std : : unique_ptr < vk : : su : : BufferData > ( new vk : : su : : BufferData ( physicalDevice , device , instances . size ( ) * sizeof ( GeometryInstanceData ) ,
vk : : BufferUsageFlagBits : : eRayTracingNV ) ) ;
2019-07-25 11:52:09 +00:00
std : : vector < GeometryInstanceData > geometryInstanceData ;
for ( size_t i = 0 ; i < instances . size ( ) ; i + + )
{
uint64_t accelerationStructureHandle = 0 ;
2019-09-26 07:55:15 +00:00
device - > getAccelerationStructureHandleNV ( instances [ i ] . first , sizeof ( uint64_t ) , & accelerationStructureHandle ) ;
2019-07-25 11:52:09 +00:00
// For each instance we set its instance index to its index i in the instance vector, and set
// its hit group index to 2*i. The hit group index defines which entry of the shader binding
// table will contain the hit group to be executed when hitting this instance. We set this
// index to 2*i due to the use of 2 types of rays in the scene: the camera rays and the shadow
// rays. For each instance, the SBT will then have 2 hit groups
geometryInstanceData . push_back ( GeometryInstanceData ( glm : : transpose ( instances [ i ] . second ) , static_cast < uint32_t > ( i ) , 0xFF , static_cast < uint32_t > ( 2 * i ) ,
static_cast < uint8_t > ( vk : : GeometryInstanceFlagBitsNV : : eTriangleCullDisable ) , accelerationStructureHandle ) ) ;
}
accelerationStructureData . instanceBufferData - > upload ( device , geometryInstanceData ) ;
}
device - > bindAccelerationStructureMemoryNV ( vk : : BindAccelerationStructureMemoryInfoNV ( * accelerationStructureData . acclerationStructure ,
2019-09-26 07:55:15 +00:00
* accelerationStructureData . resultBufferData - > deviceMemory ) ) ;
2019-07-25 11:52:09 +00:00
commandBuffer - > buildAccelerationStructureNV ( vk : : AccelerationStructureInfoNV ( accelerationStructureType , { } , vk : : su : : checked_cast < uint32_t > ( instances . size ( ) ) ,
vk : : su : : checked_cast < uint32_t > ( geometries . size ( ) ) , geometries . data ( ) ) ,
accelerationStructureData . instanceBufferData ? * accelerationStructureData . instanceBufferData - > buffer : nullptr , 0 , false ,
2019-09-26 07:55:15 +00:00
* accelerationStructureData . acclerationStructure , nullptr , * accelerationStructureData . scratchBufferData - > buffer , 0 ) ;
2019-07-25 11:52:09 +00:00
commandBuffer - > pipelineBarrier ( vk : : PipelineStageFlagBits : : eAccelerationStructureBuildNV , vk : : PipelineStageFlagBits : : eAccelerationStructureBuildNV , { } ,
vk : : MemoryBarrier ( vk : : AccessFlagBits : : eAccelerationStructureWriteNV | vk : : AccessFlagBits : : eAccelerationStructureReadNV ,
vk : : AccessFlagBits : : eAccelerationStructureWriteNV | vk : : AccessFlagBits : : eAccelerationStructureReadNV ) , { } , { } ) ;
return accelerationStructureData ;
}
struct PerFrameData
{
vk : : UniqueCommandPool commandPool ;
vk : : UniqueCommandBuffer commandBuffer ;
vk : : UniqueFence fence ;
vk : : UniqueSemaphore presentCompleteSemaphore ;
vk : : UniqueSemaphore renderCompleteSemaphore ;
} ;
struct UniformBufferObject
{
glm : : mat4 model ;
glm : : mat4 view ;
glm : : mat4 proj ;
glm : : mat4 modelIT ;
glm : : mat4 viewInverse ;
glm : : mat4 projInverse ;
} ;
struct Material
{
glm : : vec3 diffuse = glm : : vec3 ( 0.7f , 0.7f , 0.7f ) ;
int textureID = - 1 ;
} ;
const size_t MaterialStride = ( ( sizeof ( Material ) + 15 ) / 16 ) * 16 ;
struct Vertex
{
Vertex ( glm : : vec3 const & p , glm : : vec3 const & n , glm : : vec2 const & tc , int m = 0 )
: pos ( p )
, nrm ( n )
, texCoord ( tc )
, matID ( m )
{ }
glm : : vec3 pos ;
glm : : vec3 nrm ;
glm : : vec2 texCoord ;
int matID ;
} ;
const size_t VertexStride = ( ( sizeof ( Vertex ) + 15 ) / 16 ) * 16 ;
static const std : : vector < Vertex > cubeData =
{
// pos nrm texcoord matID
// front face
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) , glm : : vec2 ( 1.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) , glm : : vec2 ( 0.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
// back face
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , - 1.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , - 1.0f ) , glm : : vec2 ( 1.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , - 1.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , - 1.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , - 1.0f ) , glm : : vec2 ( 0.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , - 1.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
// left face
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( - 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( - 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 1.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( - 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( - 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( - 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 0.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( - 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
// right face
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 1.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 0.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
// top face
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) , glm : : vec2 ( 1.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) , glm : : vec2 ( 0.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
// bottom face
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , - 1.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , - 1.0f , 0.0f ) , glm : : vec2 ( 1.0f , 0.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , - 1.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , - 1.0f , 0.0f ) , glm : : vec2 ( 1.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , 1.0f ) , glm : : vec3 ( 0.0f , - 1.0f , 0.0f ) , glm : : vec2 ( 0.0f , 1.0f ) , 0 ) } ,
{ Vertex ( glm : : vec3 ( - 1.0f , - 1.0f , - 1.0f ) , glm : : vec3 ( 0.0f , - 1.0f , 0.0f ) , glm : : vec2 ( 0.0f , 0.0f ) , 0 ) } ,
} ;
static std : : string vertexShaderText = R " (
# version 450
# extension GL_ARB_separate_shader_objects : enable
layout ( binding = 0 ) uniform UniformBufferObject
{
mat4 model ;
mat4 view ;
mat4 proj ;
mat4 modelIT ;
} ubo ;
layout ( location = 0 ) in vec3 inPosition ;
layout ( location = 1 ) in vec3 inNormal ;
layout ( location = 2 ) in vec2 inTexCoord ;
layout ( location = 3 ) in int inMatID ;
layout ( location = 0 ) flat out int outMatID ;
layout ( location = 1 ) out vec2 outTexCoord ;
layout ( location = 2 ) out vec3 outNormal ;
out gl_PerVertex
{
vec4 gl_Position ;
} ;
void main ( )
{
gl_Position = ubo . proj * ubo . view * ubo . model * vec4 ( inPosition , 1.0 ) ;
outMatID = inMatID ;
outTexCoord = inTexCoord ;
outNormal = vec3 ( ubo . modelIT * vec4 ( inNormal , 0.0 ) ) ;
}
) " ;
static std : : string fragmentShaderText = R " (
# version 450
# extension GL_ARB_separate_shader_objects : enable
# extension GL_EXT_nonuniform_qualifier : enable
layout ( location = 0 ) flat in int matIndex ;
layout ( location = 1 ) in vec2 texCoord ;
layout ( location = 2 ) in vec3 normal ;
struct Material
{
vec3 diffuse ;
int textureID ;
} ;
const int sizeofMat = 1 ;
layout ( binding = 1 ) buffer MaterialBufferObject { vec4 [ ] m ; } materials ;
layout ( binding = 2 ) uniform sampler2D [ ] textureSamplers ;
Material unpackMaterial ( )
{
Material m ;
vec4 d0 = materials . m [ sizeofMat * matIndex + 0 ] ;
m . diffuse = d0 . xyz ;
m . textureID = floatBitsToInt ( d0 . w ) ;
return m ;
}
layout ( location = 0 ) out vec4 outColor ;
void main ( )
{
vec3 lightVector = normalize ( vec3 ( 5 , 4 , 3 ) ) ;
float dot_product = max ( dot ( lightVector , normalize ( normal ) ) , 0.2 ) ;
Material m = unpackMaterial ( ) ;
vec3 c = m . diffuse ;
if ( 0 < = m . textureID )
{
c * = texture ( textureSamplers [ m . textureID ] , texCoord ) . xyz ;
}
c * = dot_product ;
outColor = vec4 ( c , 1 ) ;
}
) " ;
static std : : string raygenShaderText = R " (
# 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 UniformBufferObject
{
mat4 model ;
mat4 view ;
mat4 proj ;
mat4 modelIT ;
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 /*sbtRecordOffset*/ , 0 /*sbtRecordStride*/ , 0 /*missIndex*/ , origin . xyz , tmin , direction . xyz , tmax , 0 /*payload*/ ) ;
imageStore ( image , ivec2 ( gl_LaunchIDNV . xy ) , vec4 ( hitValue , 0.0 ) ) ;
}
) " ;
static std : : string missShaderText = R " (
# version 460
# extension GL_NV_ray_tracing : require
layout ( location = 0 ) rayPayloadInNV vec3 hitValue ;
void main ( )
{
hitValue = vec3 ( 0.0 , 0.1 , 0.3 ) ;
}
) " ;
static std : : string shadowMissShaderText = R " (
# version 460
# extension GL_NV_ray_tracing : require
layout ( location = 2 ) rayPayloadInNV bool isShadowed ;
void main ( )
{
isShadowed = false ;
} ) " ;
static std : : string closestHitShaderText = R " (
# version 460
# extension GL_NV_ray_tracing : require
# extension GL_EXT_nonuniform_qualifier : enable
layout ( location = 0 ) rayPayloadInNV vec3 hitValue ;
layout ( location = 2 ) rayPayloadNV bool isShadowed ;
hitAttributeNV vec3 attribs ;
layout ( binding = 0 , set = 0 ) uniform accelerationStructureNV topLevelAS ;
layout ( binding = 3 , set = 0 ) buffer Vertices { vec4 v [ ] ; } vertices ;
layout ( binding = 4 , set = 0 ) buffer Indices { uint i [ ] ; } indices ;
layout ( binding = 5 , set = 0 ) buffer MatColorBufferObject { vec4 [ ] m ; } materials ;
layout ( binding = 6 , set = 0 ) uniform sampler2D [ ] textureSamplers ;
struct Vertex
{
vec3 pos ;
vec3 nrm ;
vec2 texCoord ;
int matIndex ;
} ;
// Number of vec4 values used to represent a vertex
uint vertexSize = 3 ;
Vertex unpackVertex ( uint index )
{
Vertex v ;
vec4 d0 = vertices . v [ vertexSize * index + 0 ] ;
vec4 d1 = vertices . v [ vertexSize * index + 1 ] ;
vec4 d2 = vertices . v [ vertexSize * index + 2 ] ;
v . pos = d0 . xyz ;
v . nrm = vec3 ( d0 . w , d1 . xy ) ;
v . texCoord = d1 . zw ;
v . matIndex = floatBitsToInt ( d2 . x ) ;
return v ;
}
struct Material
{
vec3 diffuse ;
int textureID ;
} ;
// Number of vec4 values used to represent a material
const int sizeofMat = 1 ;
Material unpackMaterial ( int matIndex )
{
Material m ;
vec4 d0 = materials . m [ sizeofMat * matIndex + 0 ] ;
m . diffuse = d0 . xyz ;
m . textureID = floatBitsToInt ( d0 . w ) ;
return m ;
}
void main ( )
{
ivec3 ind = ivec3 ( indices . i [ 3 * gl_PrimitiveID ] , indices . i [ 3 * gl_PrimitiveID + 1 ] , indices . i [ 3 * gl_PrimitiveID + 2 ] ) ;
Vertex v0 = unpackVertex ( ind . x ) ;
Vertex v1 = unpackVertex ( ind . y ) ;
Vertex v2 = unpackVertex ( ind . z ) ;
const vec3 barycentrics = vec3 ( 1.0 - attribs . x - attribs . y , attribs . x , attribs . y ) ;
vec3 normal = normalize ( v0 . nrm * barycentrics . x + v1 . nrm * barycentrics . y + v2 . nrm * barycentrics . z ) ;
vec3 lightVector = normalize ( vec3 ( 5 , 4 , 3 ) ) ;
float dot_product = max ( dot ( lightVector , normal ) , 0.2 ) ;
Material mat = unpackMaterial ( v1 . matIndex ) ;
vec3 c = dot_product * mat . diffuse ;
if ( 0 < = mat . textureID )
{
vec2 texCoord = v0 . texCoord * barycentrics . x + v1 . texCoord * barycentrics . y + v2 . texCoord * barycentrics . z ;
c * = texture ( textureSamplers [ mat . textureID ] , texCoord ) . xyz ;
}
float tmin = 0.001 ;
float tmax = 100.0 ;
vec3 origin = gl_WorldRayOriginNV + gl_WorldRayDirectionNV * gl_HitTNV ;
isShadowed = true ;
traceNV ( topLevelAS , gl_RayFlagsTerminateOnFirstHitNV | gl_RayFlagsOpaqueNV | gl_RayFlagsSkipClosestHitShaderNV , 0xFF , 1 /* sbtRecordOffset */ , 0 /* sbtRecordStride */ , 1 /* missIndex */ , origin ,
tmin , lightVector , tmax , 2 /*payload location*/ ) ;
hitValue = c ;
if ( isShadowed )
{
hitValue * = 0.3f ;
}
}
) " ;
# ifndef IMGUI_VK_QUEUED_FRAMES
# define IMGUI_VK_QUEUED_FRAMES 2
# endif // !IMGUI_VK_QUEUED_FRAMES
struct AppInfo
{
vk : : su : : CameraManipulator cameraManipulator ;
bool useRasterRender = false ;
} ;
static void check_vk_result ( VkResult err )
{
if ( err ! = 0 )
{
std : : cerr < < AppName < < " : Vulkan error " < < vk : : to_string ( static_cast < vk : : Result > ( err ) ) ;
if ( err < 0 )
{
abort ( ) ;
}
}
}
static void cursorPosCallback ( GLFWwindow * window , double mouseX , double mouseY )
{
vk : : su : : CameraManipulator : : MouseButton mouseButton = ( glfwGetMouseButton ( window , GLFW_MOUSE_BUTTON_LEFT ) = = GLFW_PRESS )
? vk : : su : : CameraManipulator : : MouseButton : : Left
: ( glfwGetMouseButton ( window , GLFW_MOUSE_BUTTON_MIDDLE ) = = GLFW_PRESS )
? vk : : su : : CameraManipulator : : MouseButton : : Middle
: ( glfwGetMouseButton ( window , GLFW_MOUSE_BUTTON_RIGHT ) = = GLFW_PRESS )
? vk : : su : : CameraManipulator : : MouseButton : : Right
: vk : : su : : CameraManipulator : : MouseButton : : None ;
if ( mouseButton ! = vk : : su : : CameraManipulator : : MouseButton : : None )
{
vk : : su : : CameraManipulator : : ModifierFlags modifiers ;
if ( glfwGetKey ( window , GLFW_KEY_LEFT_ALT ) = = GLFW_PRESS )
{
modifiers | = vk : : su : : CameraManipulator : : ModifierFlagBits : : Alt ;
}
if ( glfwGetKey ( window , GLFW_KEY_LEFT_CONTROL ) = = GLFW_PRESS )
{
modifiers | = vk : : su : : CameraManipulator : : ModifierFlagBits : : Ctrl ;
}
if ( glfwGetKey ( window , GLFW_KEY_LEFT_SHIFT ) = = GLFW_PRESS )
{
modifiers | = vk : : su : : CameraManipulator : : ModifierFlagBits : : Shift ;
}
vk : : su : : CameraManipulator & cameraManipulator = reinterpret_cast < AppInfo * > ( glfwGetWindowUserPointer ( window ) ) - > cameraManipulator ;
cameraManipulator . mouseMove ( glm : : ivec2 ( static_cast < int > ( mouseX ) , static_cast < int > ( mouseY ) ) , mouseButton , modifiers ) ;
}
}
static void errorCallback ( int error , const char * description )
{
fprintf ( stderr , " GLFW Error %d: %s \n " , error , description ) ;
}
static void framebufferSizeCallback ( GLFWwindow * window , int w , int h )
{
vk : : su : : CameraManipulator & cameraManipulator = reinterpret_cast < AppInfo * > ( glfwGetWindowUserPointer ( window ) ) - > cameraManipulator ;
cameraManipulator . setWindowSize ( glm : : ivec2 ( w , h ) ) ;
}
static void keyCallback ( GLFWwindow * window , int key , int /*scancode*/ , int action , int /*mods*/ )
{
if ( action = = GLFW_PRESS )
{
switch ( key )
{
case GLFW_KEY_ESCAPE :
case ' Q ' :
glfwSetWindowShouldClose ( window , 1 ) ;
break ;
case ' R ' :
{
AppInfo * appInfo = reinterpret_cast < AppInfo * > ( glfwGetWindowUserPointer ( window ) ) ;
appInfo - > useRasterRender = ! appInfo - > useRasterRender ;
}
break ;
}
}
}
static void mouseButtonCallback ( GLFWwindow * window , int /*button*/ , int /*action*/ , int /*mods*/ )
{
double xpos , ypos ;
glfwGetCursorPos ( window , & xpos , & ypos ) ;
vk : : su : : CameraManipulator & cameraManipulator = reinterpret_cast < AppInfo * > ( glfwGetWindowUserPointer ( window ) ) - > cameraManipulator ;
cameraManipulator . setMousePosition ( glm : : ivec2 ( static_cast < int > ( xpos ) , static_cast < int > ( ypos ) ) ) ;
}
static void scrollCallback ( GLFWwindow * window , double /*xoffset*/ , double yoffset )
{
vk : : su : : CameraManipulator & cameraManipulator = reinterpret_cast < AppInfo * > ( glfwGetWindowUserPointer ( window ) ) - > cameraManipulator ;
cameraManipulator . wheel ( static_cast < int > ( yoffset ) ) ;
}
// random data and functions
static std : : random_device randomDevice ;
static std : : mt19937 randomGenerator ( randomDevice ( ) ) ;
template < typename T >
T random ( T minValue = std : : numeric_limits < T > : : min ( ) , T maxValue = std : : numeric_limits < T > : : max ( ) )
{
static_assert ( std : : numeric_limits < T > : : is_integer , " Type T needs to be an integral type! \n " ) ;
std : : uniform_int_distribution < > randomDistribution ( minValue , maxValue ) ;
return static_cast < T > ( randomDistribution ( randomGenerator ) ) ;
}
glm : : vec3 randomVec3 ( float minValue , float maxValue )
{
std : : uniform_real_distribution < float > randomDistribution ( minValue , maxValue ) ;
return glm : : vec3 ( randomDistribution ( randomGenerator ) , randomDistribution ( randomGenerator ) , randomDistribution ( randomGenerator ) ) ;
}
int main ( int /*argc*/ , char * * /*argv*/ )
{
// number of cubes in x-, y-, and z-direction
const size_t xMax = 10 ;
const size_t yMax = 10 ;
const size_t zMax = 10 ;
AppInfo appInfo ;
try
{
// Setup glfw
glfwSetErrorCallback ( errorCallback ) ;
if ( ! glfwInit ( ) )
{
std : : cerr < < AppName < < " : can't initialize glfw! \n " ;
return 1 ;
}
if ( ! glfwVulkanSupported ( ) )
{
std : : cerr < < AppName < < " : Vulkan not supported! \n " ;
return 1 ;
}
// create a window using glfw
glfwWindowHint ( GLFW_CLIENT_API , GLFW_NO_API ) ;
vk : : Extent2D windowExtent ( 1280 , 720 ) ;
GLFWwindow * window = glfwCreateWindow ( windowExtent . width , windowExtent . height , AppName , nullptr , nullptr ) ;
// install some callbacks
glfwSetCursorPosCallback ( window , cursorPosCallback ) ;
glfwSetFramebufferSizeCallback ( window , framebufferSizeCallback ) ;
glfwSetKeyCallback ( window , keyCallback ) ;
glfwSetMouseButtonCallback ( window , mouseButtonCallback ) ;
glfwSetScrollCallback ( window , scrollCallback ) ;
// Setup camera and make it available as the userPointer in the glfw window
appInfo . cameraManipulator . setWindowSize ( glm : : u32vec2 ( windowExtent . width , windowExtent . height ) ) ;
glm : : vec3 diagonal = 3.0f * glm : : vec3 ( static_cast < float > ( xMax ) , static_cast < float > ( yMax ) , static_cast < float > ( zMax ) ) ;
appInfo . cameraManipulator . setLookat ( 1.5f * diagonal , 0.5f * diagonal , glm : : vec3 ( 0 , 1 , 0 ) ) ;
glfwSetWindowUserPointer ( window , & appInfo ) ;
// Create Vulkan Instance with needed extensions
uint32_t glfwExtensionsCount ;
const char * * glfwExtensions = glfwGetRequiredInstanceExtensions ( & glfwExtensionsCount ) ;
std : : vector < std : : string > instanceExtensions ;
instanceExtensions . reserve ( glfwExtensionsCount + 1 ) ;
for ( uint32_t i = 0 ; i < glfwExtensionsCount ; i + + )
{
instanceExtensions . push_back ( glfwExtensions [ i ] ) ;
}
instanceExtensions . push_back ( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) ;
vk : : UniqueInstance instance = vk : : su : : createInstance ( AppName , EngineName , { } , instanceExtensions ) ;
# if !defined(NDEBUG)
2019-09-25 09:56:46 +00:00
vk : : UniqueDebugUtilsMessengerEXT debugUtilsMessenger = vk : : su : : createDebugUtilsMessenger ( instance ) ;
2019-07-25 11:52:09 +00:00
# endif
vk : : PhysicalDevice physicalDevice = instance - > enumeratePhysicalDevices ( ) . front ( ) ;
// Create Window Surface (using glfw)
vk : : SurfaceKHR surface ;
VkResult err = glfwCreateWindowSurface ( * instance , window , nullptr , reinterpret_cast < VkSurfaceKHR * > ( & surface ) ) ;
check_vk_result ( err ) ;
std : : pair < uint32_t , uint32_t > graphicsAndPresentQueueFamilyIndex = vk : : su : : findGraphicsAndPresentQueueFamilyIndex ( physicalDevice , surface ) ;
// Create a Device with ray tracing support (besides some other extensions needed) and needed features
auto supportedFeatures = physicalDevice . getFeatures2 < vk : : PhysicalDeviceFeatures2 , vk : : PhysicalDeviceDescriptorIndexingFeaturesEXT > ( ) ;
vk : : UniqueDevice device = vk : : su : : createDevice ( physicalDevice , graphicsAndPresentQueueFamilyIndex . first ,
{ VK_KHR_SWAPCHAIN_EXTENSION_NAME , VK_NV_RAY_TRACING_EXTENSION_NAME , VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME } ,
& supportedFeatures . get < vk : : PhysicalDeviceFeatures2 > ( ) . features , & supportedFeatures . get < vk : : PhysicalDeviceDescriptorIndexingFeaturesEXT > ( ) ) ;
// setup stuff per frame
std : : array < PerFrameData , IMGUI_VK_QUEUED_FRAMES > perFrameData ;
for ( int i = 0 ; i < IMGUI_VK_QUEUED_FRAMES ; i + + )
{
perFrameData [ i ] . commandPool = device - > createCommandPoolUnique ( vk : : CommandPoolCreateInfo ( vk : : CommandPoolCreateFlagBits : : eResetCommandBuffer , graphicsAndPresentQueueFamilyIndex . first ) ) ;
perFrameData [ i ] . commandBuffer = std : : move ( device - > allocateCommandBuffersUnique ( vk : : CommandBufferAllocateInfo ( * perFrameData [ i ] . commandPool , vk : : CommandBufferLevel : : ePrimary , 1 ) ) . front ( ) ) ;
perFrameData [ i ] . fence = device - > createFenceUnique ( vk : : FenceCreateInfo ( vk : : FenceCreateFlagBits : : eSignaled ) ) ;
perFrameData [ i ] . presentCompleteSemaphore = device - > createSemaphoreUnique ( vk : : SemaphoreCreateInfo ( ) ) ;
perFrameData [ i ] . renderCompleteSemaphore = device - > createSemaphoreUnique ( vk : : SemaphoreCreateInfo ( ) ) ;
}
vk : : Queue graphicsQueue = device - > getQueue ( graphicsAndPresentQueueFamilyIndex . first , 0 ) ;
vk : : Queue presentQueue = device - > getQueue ( graphicsAndPresentQueueFamilyIndex . second , 0 ) ;
// create a descriptor pool with a number of available descriptors
std : : vector < vk : : DescriptorPoolSize > poolSizes =
{
{ vk : : DescriptorType : : eCombinedImageSampler , 1000 } ,
{ vk : : DescriptorType : : eUniformBuffer , 1000 } ,
{ vk : : DescriptorType : : eStorageBuffer , 1000 } ,
} ;
vk : : UniqueDescriptorPool descriptorPool = vk : : su : : createDescriptorPool ( device , poolSizes ) ;
// setup swap chain, render pass, depth buffer and the frame buffers
vk : : su : : SwapChainData swapChainData ( physicalDevice , device , surface , windowExtent , vk : : ImageUsageFlagBits : : eColorAttachment | vk : : ImageUsageFlagBits : : eStorage , vk : : UniqueSwapchainKHR ( ) ,
graphicsAndPresentQueueFamilyIndex . first , graphicsAndPresentQueueFamilyIndex . second ) ;
vk : : SurfaceFormatKHR surfaceFormat = vk : : su : : pickSurfaceFormat ( physicalDevice . getSurfaceFormatsKHR ( surface ) ) ;
vk : : Format depthFormat = vk : : su : : pickDepthFormat ( physicalDevice ) ;
// setup a render pass
vk : : UniqueRenderPass renderPass = vk : : su : : createRenderPass ( device , surfaceFormat . format , depthFormat ) ;
vk : : su : : DepthBufferData depthBufferData ( physicalDevice , device , depthFormat , windowExtent ) ;
std : : vector < vk : : UniqueFramebuffer > framebuffers = vk : : su : : createFramebuffers ( device , renderPass , swapChainData . imageViews , depthBufferData . imageView , windowExtent ) ;
bool samplerAnisotropy = supportedFeatures . get < vk : : PhysicalDeviceFeatures2 > ( ) . features . samplerAnisotropy ;
// create some simple checkerboard textures, randomly sized and colored
const size_t textureCount = 10 ;
std : : vector < vk : : su : : TextureData > textures ;
textures . reserve ( textureCount ) ;
for ( size_t i = 0 ; i < textureCount ; i + + )
{
textures . push_back ( vk : : su : : TextureData ( physicalDevice , device , { random < uint32_t > ( 2 , 8 ) * 16 , random < uint32_t > ( 2 , 8 ) * 16 } ,
vk : : ImageUsageFlagBits : : eTransferDst | vk : : ImageUsageFlagBits : : eSampled , { } , samplerAnisotropy , true ) ) ;
}
vk : : su : : oneTimeSubmit ( device , perFrameData [ 0 ] . commandPool , graphicsQueue ,
[ & ] ( vk : : UniqueCommandBuffer const & commandBuffer )
{
for ( auto & t : textures )
{
t . setImage ( device , commandBuffer , vk : : su : : CheckerboardImageGenerator ( { random < uint8_t > ( ) , random < uint8_t > ( ) , random < uint8_t > ( ) } ,
{ random < uint8_t > ( ) , random < uint8_t > ( ) , random < uint8_t > ( ) } ) ) ;
}
} ) ;
// create some materials with a random diffuse color, referencing one of the above textures
const size_t materialCount = 10 ;
assert ( materialCount = = textureCount ) ;
std : : vector < Material > materials ( materialCount ) ;
for ( size_t i = 0 ; i < materialCount ; i + + )
{
materials [ i ] . diffuse = randomVec3 ( 0.0f , 1.0f ) ;
materials [ i ] . textureID = vk : : su : : checked_cast < uint32_t > ( i ) ;
}
vk : : su : : BufferData materialBufferData ( physicalDevice , device , materialCount * MaterialStride , vk : : BufferUsageFlagBits : : eStorageBuffer ) ;
materialBufferData . upload ( device , materials , MaterialStride ) ;
// create a a 3D-array of cubes, randomly jittered, using a random material
std : : vector < Vertex > vertices ;
vertices . reserve ( xMax * yMax * zMax * cubeData . size ( ) ) ;
for ( size_t x = 0 ; x < xMax ; x + + )
{
for ( size_t y = 0 ; y < yMax ; y + + )
{
for ( size_t z = 0 ; z < zMax ; z + + )
{
int m = random < int > ( 0 , materialCount - 1 ) ;
glm : : vec3 jitter = randomVec3 ( 0.0f , 0.6f ) ;
for ( auto const & v : cubeData )
{
vertices . push_back ( v ) ;
vertices . back ( ) . pos + = 3.0f * glm : : vec3 ( static_cast < float > ( x ) , static_cast < float > ( y ) , static_cast < float > ( z ) ) + jitter ;
vertices . back ( ) . matID = static_cast < int > ( m ) ;
}
}
}
}
// create an 1-1 index buffer
std : : vector < unsigned int > indices ( vertices . size ( ) ) ;
std : : iota ( indices . begin ( ) , indices . end ( ) , 0 ) ;
// there's just one vertex- and one index-buffer, but with more complex scene loaders there might be more!
vk : : su : : BufferData vertexBufferData ( physicalDevice , device , vertices . size ( ) * VertexStride ,
vk : : BufferUsageFlagBits : : eTransferDst | vk : : BufferUsageFlagBits : : eVertexBuffer | vk : : BufferUsageFlagBits : : eStorageBuffer ,
vk : : MemoryPropertyFlagBits : : eDeviceLocal ) ;
vertexBufferData . upload ( physicalDevice , device , perFrameData [ 0 ] . commandPool , graphicsQueue , vertices , VertexStride ) ;
vk : : su : : BufferData indexBufferData ( physicalDevice , device , indices . size ( ) * sizeof ( uint32_t ) ,
vk : : BufferUsageFlagBits : : eTransferDst | vk : : BufferUsageFlagBits : : eIndexBuffer | vk : : BufferUsageFlagBits : : eStorageBuffer ,
vk : : MemoryPropertyFlagBits : : eDeviceLocal ) ;
indexBufferData . upload ( physicalDevice , device , perFrameData [ 0 ] . commandPool , graphicsQueue , indices , sizeof ( uint32_t ) ) ;
glm : : mat4x4 transform ( glm : : mat4x4 ( 1.0f , 0.0f , 0.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f , 0.0f , 0.0f , 1.0f ) ) ;
vk : : UniqueDescriptorSetLayout descriptorSetLayout =
vk : : su : : createDescriptorSetLayout ( device ,
{
{ vk : : DescriptorType : : eUniformBuffer , 1 , vk : : ShaderStageFlagBits : : eVertex } ,
{ vk : : DescriptorType : : eStorageBuffer , 1 , vk : : ShaderStageFlagBits : : eVertex | vk : : ShaderStageFlagBits : : eFragment } ,
{ vk : : DescriptorType : : eCombinedImageSampler , static_cast < uint32_t > ( textures . size ( ) ) , vk : : ShaderStageFlagBits : : eFragment }
} ) ;
vk : : UniquePipelineLayout pipelineLayout = device - > createPipelineLayoutUnique ( vk : : PipelineLayoutCreateInfo ( { } , 1 , & ( * descriptorSetLayout ) ) ) ;
glslang : : InitializeProcess ( ) ;
vk : : UniqueShaderModule vertexShaderModule = vk : : su : : createShaderModule ( device , vk : : ShaderStageFlagBits : : eVertex , vertexShaderText ) ;
vk : : UniqueShaderModule fragmentShaderModule = vk : : su : : createShaderModule ( device , vk : : ShaderStageFlagBits : : eFragment , fragmentShaderText ) ;
glslang : : FinalizeProcess ( ) ;
vk : : UniquePipeline graphicsPipeline = vk : : su : : createGraphicsPipeline ( device , vk : : UniquePipelineCache ( ) , std : : make_pair ( * vertexShaderModule , nullptr ) ,
std : : make_pair ( * fragmentShaderModule , nullptr ) , VertexStride ,
{
{ vk : : Format : : eR32G32B32Sfloat , vk : : su : : checked_cast < uint32_t > ( offsetof ( Vertex , pos ) ) } ,
{ vk : : Format : : eR32G32B32Sfloat , vk : : su : : checked_cast < uint32_t > ( offsetof ( Vertex , nrm ) ) } ,
{ vk : : Format : : eR32G32Sfloat , vk : : su : : checked_cast < uint32_t > ( offsetof ( Vertex , texCoord ) ) } ,
{ vk : : Format : : eR32Sint , vk : : su : : checked_cast < uint32_t > ( offsetof ( Vertex , matID ) ) }
} , vk : : FrontFace : : eCounterClockwise , true , pipelineLayout , renderPass ) ;
vk : : su : : BufferData uniformBufferData ( physicalDevice , device , sizeof ( UniformBufferObject ) , vk : : BufferUsageFlagBits : : eUniformBuffer ) ;
vk : : UniqueDescriptorSet descriptorSet = std : : move ( device - > allocateDescriptorSetsUnique ( vk : : DescriptorSetAllocateInfo ( * descriptorPool , 1 , & * descriptorSetLayout ) ) . front ( ) ) ;
vk : : su : : updateDescriptorSets ( device , descriptorSet , { { vk : : DescriptorType : : eUniformBuffer , uniformBufferData . buffer , vk : : UniqueBufferView ( ) } ,
{ vk : : DescriptorType : : eStorageBuffer , materialBufferData . buffer , vk : : UniqueBufferView ( ) } } , textures ) ;
// RayTracing specific stuff
// create acceleration structures: one top-level, and just one bottom-level
AccelerationStructureData topLevelAS , bottomLevelAS ;
vk : : su : : oneTimeSubmit ( device , perFrameData [ 0 ] . commandPool , graphicsQueue ,
[ & ] ( vk : : UniqueCommandBuffer const & commandBuffer )
{
vk : : GeometryDataNV geometryDataNV ( vk : : GeometryTrianglesNV ( * vertexBufferData . buffer , 0 , vk : : su : : checked_cast < uint32_t > ( vertices . size ( ) ) , VertexStride ,
vk : : Format : : eR32G32B32Sfloat , * indexBufferData . buffer , 0 ,
vk : : su : : checked_cast < uint32_t > ( indices . size ( ) ) , vk : : IndexType : : eUint32 ) , { } ) ;
2019-09-26 07:55:15 +00:00
bottomLevelAS = createAccelerationStructureData ( physicalDevice , device , commandBuffer , { } , { vk : : GeometryNV ( vk : : GeometryTypeNV : : eTriangles , geometryDataNV ) } ) ;
2019-07-25 11:52:09 +00:00
topLevelAS = createAccelerationStructureData ( physicalDevice , device , commandBuffer , { std : : make_pair ( * bottomLevelAS . acclerationStructure , transform ) } ,
2019-09-26 07:55:15 +00:00
std : : vector < vk : : GeometryNV > ( ) ) ;
2019-07-25 11:52:09 +00:00
} ) ;
// create raytracing descriptor set
vk : : su : : oneTimeSubmit ( device , perFrameData [ 0 ] . commandPool , graphicsQueue ,
[ & ] ( vk : : UniqueCommandBuffer const & commandBuffer )
{
vk : : BufferMemoryBarrier bufferMemoryBarrier ( { } , vk : : AccessFlagBits : : eShaderRead , VK_QUEUE_FAMILY_IGNORED , VK_QUEUE_FAMILY_IGNORED , * vertexBufferData . buffer , 0 ,
VK_WHOLE_SIZE ) ;
commandBuffer - > pipelineBarrier ( vk : : PipelineStageFlagBits : : eAllCommands , vk : : PipelineStageFlagBits : : eAllCommands , { } , nullptr , bufferMemoryBarrier , nullptr ) ;
bufferMemoryBarrier . buffer = * indexBufferData . buffer ;
commandBuffer - > pipelineBarrier ( vk : : PipelineStageFlagBits : : eAllCommands , vk : : PipelineStageFlagBits : : eAllCommands , { } , nullptr , bufferMemoryBarrier , nullptr ) ;
} ) ;
std : : vector < vk : : DescriptorSetLayoutBinding > bindings ;
bindings . push_back ( vk : : DescriptorSetLayoutBinding ( 0 , vk : : DescriptorType : : eAccelerationStructureNV , 1 , vk : : ShaderStageFlagBits : : eRaygenNV | vk : : ShaderStageFlagBits : : eClosestHitNV ) ) ;
bindings . push_back ( vk : : DescriptorSetLayoutBinding ( 1 , vk : : DescriptorType : : eStorageImage , 1 , vk : : ShaderStageFlagBits : : eRaygenNV ) ) ; // raytracing output
bindings . push_back ( vk : : DescriptorSetLayoutBinding ( 2 , vk : : DescriptorType : : eUniformBuffer , 1 , vk : : ShaderStageFlagBits : : eRaygenNV ) ) ; // camera information
bindings . push_back ( vk : : DescriptorSetLayoutBinding ( 3 , vk : : DescriptorType : : eStorageBuffer , 1 , vk : : ShaderStageFlagBits : : eClosestHitNV ) ) ; // vertex buffer
bindings . push_back ( vk : : DescriptorSetLayoutBinding ( 4 , vk : : DescriptorType : : eStorageBuffer , 1 , vk : : ShaderStageFlagBits : : eClosestHitNV ) ) ; // index buffer
bindings . push_back ( vk : : DescriptorSetLayoutBinding ( 5 , vk : : DescriptorType : : eStorageBuffer , 1 , vk : : ShaderStageFlagBits : : eClosestHitNV ) ) ; // material buffer
2019-12-19 12:59:48 +00:00
bindings . push_back ( vk : : DescriptorSetLayoutBinding ( 6 , vk : : DescriptorType : : eCombinedImageSampler , vk : : su : : checked_cast < uint32_t > ( textures . size ( ) ) , vk : : ShaderStageFlagBits : : eClosestHitNV ) ) ; // textures
2019-07-25 11:52:09 +00:00
std : : vector < vk : : DescriptorPoolSize > descriptorPoolSizes ;
descriptorPoolSizes . reserve ( bindings . size ( ) ) ;
for ( const auto & b : bindings )
{
2019-12-19 12:59:48 +00:00
descriptorPoolSizes . push_back ( vk : : DescriptorPoolSize ( b . descriptorType , vk : : su : : checked_cast < uint32_t > ( swapChainData . images . size ( ) ) * b . descriptorCount ) ) ;
2019-07-25 11:52:09 +00:00
}
2019-12-19 12:59:48 +00:00
vk : : DescriptorPoolCreateInfo descriptorPoolCreateInfo ( vk : : DescriptorPoolCreateFlagBits : : eFreeDescriptorSet , vk : : su : : checked_cast < uint32_t > ( swapChainData . images . size ( ) ) ,
vk : : su : : checked_cast < uint32_t > ( descriptorPoolSizes . size ( ) ) , descriptorPoolSizes . data ( ) ) ;
vk : : UniqueDescriptorPool rayTracingDescriptorPool = device - > createDescriptorPoolUnique ( descriptorPoolCreateInfo ) ;
2019-07-25 11:52:09 +00:00
vk : : UniqueDescriptorSetLayout rayTracingDescriptorSetLayout = device - > createDescriptorSetLayoutUnique ( vk : : DescriptorSetLayoutCreateInfo ( { } , static_cast < uint32_t > ( bindings . size ( ) ) ,
bindings . data ( ) ) ) ;
2019-12-19 12:59:48 +00:00
std : : vector < vk : : DescriptorSetLayout > layouts ;
for ( size_t i = 0 ; i < swapChainData . images . size ( ) ; i + + )
{
layouts . push_back ( * rayTracingDescriptorSetLayout ) ;
}
vk : : DescriptorSetAllocateInfo descriptorSetAllocateInfo ( * rayTracingDescriptorPool , vk : : su : : checked_cast < uint32_t > ( layouts . size ( ) ) , layouts . data ( ) ) ;
std : : vector < vk : : UniqueDescriptorSet > rayTracingDescriptorSets = device - > allocateDescriptorSetsUnique ( descriptorSetAllocateInfo ) ;
2019-07-25 11:52:09 +00:00
// Bind ray tracing specific descriptor sets into pNext of a vk::WriteDescriptorSet
vk : : WriteDescriptorSetAccelerationStructureNV writeDescriptorSetAcceleration ( 1 , & * topLevelAS . acclerationStructure ) ;
2019-12-19 12:59:48 +00:00
std : : vector < vk : : WriteDescriptorSet > accelerationDescriptionSets ;
for ( size_t i = 0 ; i < rayTracingDescriptorSets . size ( ) ; i + + )
{
accelerationDescriptionSets . push_back ( vk : : WriteDescriptorSet ( * rayTracingDescriptorSets [ i ] , 0 , 0 , 1 , bindings [ 0 ] . descriptorType ) ) ;
accelerationDescriptionSets . back ( ) . pNext = & writeDescriptorSetAcceleration ;
}
device - > updateDescriptorSets ( accelerationDescriptionSets , { } ) ;
2019-07-25 11:52:09 +00:00
// Bind all the other buffers and images, starting with dstBinding == 2 (dstBinding == 1 is used by the backBuffer view)
2019-12-19 12:59:48 +00:00
for ( size_t i = 0 ; i < rayTracingDescriptorSets . size ( ) ; i + + )
{
vk : : su : : updateDescriptorSets ( device , rayTracingDescriptorSets [ i ] ,
2019-07-25 11:52:09 +00:00
{
{ bindings [ 2 ] . descriptorType , uniformBufferData . buffer , vk : : UniqueBufferView ( ) } ,
{ bindings [ 3 ] . descriptorType , vertexBufferData . buffer , vk : : UniqueBufferView ( ) } ,
{ bindings [ 4 ] . descriptorType , indexBufferData . buffer , vk : : UniqueBufferView ( ) } ,
{ bindings [ 5 ] . descriptorType , materialBufferData . buffer , vk : : UniqueBufferView ( ) }
} , textures , 2 ) ;
2019-12-19 12:59:48 +00:00
}
2019-07-25 11:52:09 +00:00
// create the ray-tracing shader modules
glslang : : InitializeProcess ( ) ;
vk : : UniqueShaderModule raygenShaderModule = vk : : su : : createShaderModule ( device , vk : : ShaderStageFlagBits : : eRaygenNV , raygenShaderText ) ;
vk : : UniqueShaderModule missShaderModule = vk : : su : : createShaderModule ( device , vk : : ShaderStageFlagBits : : eMissNV , missShaderText ) ;
vk : : UniqueShaderModule shadowMissShaderModule = vk : : su : : createShaderModule ( device , vk : : ShaderStageFlagBits : : eMissNV , shadowMissShaderText ) ;
vk : : UniqueShaderModule closestHitShaderModule = vk : : su : : createShaderModule ( device , vk : : ShaderStageFlagBits : : eClosestHitNV , closestHitShaderText ) ;
glslang : : FinalizeProcess ( ) ;
// create the ray tracing pipeline
std : : vector < vk : : PipelineShaderStageCreateInfo > shaderStages ;
std : : vector < vk : : RayTracingShaderGroupCreateInfoNV > shaderGroups ;
// We use only one ray generation, that will implement the camera model
shaderStages . push_back ( vk : : PipelineShaderStageCreateInfo ( { } , vk : : ShaderStageFlagBits : : eRaygenNV , * raygenShaderModule , " main " ) ) ;
shaderGroups . push_back ( vk : : RayTracingShaderGroupCreateInfoNV ( vk : : RayTracingShaderGroupTypeNV : : eGeneral , 0 , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV ) ) ;
// The first miss shader is used to look-up the environment in case the rays from the camera miss the geometry
shaderStages . push_back ( vk : : PipelineShaderStageCreateInfo ( { } , vk : : ShaderStageFlagBits : : eMissNV , * missShaderModule , " main " ) ) ;
shaderGroups . push_back ( vk : : RayTracingShaderGroupCreateInfoNV ( vk : : RayTracingShaderGroupTypeNV : : eGeneral , 1 , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV ) ) ;
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
shaderStages . push_back ( vk : : PipelineShaderStageCreateInfo ( { } , vk : : ShaderStageFlagBits : : eMissNV , * shadowMissShaderModule , " main " ) ) ;
shaderGroups . push_back ( vk : : RayTracingShaderGroupCreateInfoNV ( vk : : RayTracingShaderGroupTypeNV : : eGeneral , 2 , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV ) ) ;
// The first hit group defines the shaders invoked when a ray shot from the camera hit the geometry. In this case we only specify the closest hit
// shader, and rely on the build-in triangle intersection and pass-through any-hit shader. However, explicit intersection and any hit shaders could be added as well.
shaderStages . push_back ( vk : : PipelineShaderStageCreateInfo ( { } , vk : : ShaderStageFlagBits : : eClosestHitNV , * closestHitShaderModule , " main " ) ) ;
shaderGroups . push_back ( vk : : RayTracingShaderGroupCreateInfoNV ( vk : : RayTracingShaderGroupTypeNV : : eTrianglesHitGroup , VK_SHADER_UNUSED_NV , 3 , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV ) ) ;
// The second hit group defines the shaders invoked when a shadow ray hits the geometry. For simple shadows we do not need any shader in that group: we will rely on
// initializing the payload and update it only in the miss shader
shaderGroups . push_back ( vk : : RayTracingShaderGroupCreateInfoNV ( vk : : RayTracingShaderGroupTypeNV : : eTrianglesHitGroup , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV , VK_SHADER_UNUSED_NV ) ) ;
// Create the layout of the pipeline following the provided descriptor set layout
vk : : UniquePipelineLayout rayTracingPipelineLayout = device - > createPipelineLayoutUnique ( vk : : PipelineLayoutCreateInfo ( { } , 1 , & * rayTracingDescriptorSetLayout ) ) ;
// Assemble the shader stages and recursion depth info into the raytracing pipeline
// The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
// in the ray generation to avoid deep recursion.
uint32_t maxRecursionDepth = 2 ;
vk : : RayTracingPipelineCreateInfoNV rayTracingPipelineCreateInfo ( { } , static_cast < uint32_t > ( shaderStages . size ( ) ) , shaderStages . data ( ) , static_cast < uint32_t > ( shaderGroups . size ( ) ) ,
shaderGroups . data ( ) , maxRecursionDepth , * rayTracingPipelineLayout ) ;
2019-09-26 07:55:15 +00:00
vk : : UniquePipeline rayTracingPipeline = device - > createRayTracingPipelineNVUnique ( nullptr , rayTracingPipelineCreateInfo ) ;
2019-07-25 11:52:09 +00:00
uint32_t shaderGroupHandleSize = physicalDevice . getProperties2 < vk : : PhysicalDeviceProperties2 , vk : : PhysicalDeviceRayTracingPropertiesNV > ( ) . get < vk : : PhysicalDeviceRayTracingPropertiesNV > ( ) . shaderGroupHandleSize ;
assert ( ! ( shaderGroupHandleSize % 16 ) ) ;
uint32_t shaderBindingTableSize = 5 * shaderGroupHandleSize ; // 1x raygen, 2x miss, 2x hitGroup
// with 5 shaders, we need a buffer to hold 5 shaderGroupHandles
std : : vector < uint8_t > shaderHandleStorage ( shaderBindingTableSize ) ;
2019-09-26 07:55:15 +00:00
device - > getRayTracingShaderGroupHandlesNV < uint8_t > ( * rayTracingPipeline , 0 , 5 , shaderHandleStorage ) ;
2019-07-25 11:52:09 +00:00
vk : : su : : BufferData shaderBindingTableBufferData ( physicalDevice , device , shaderBindingTableSize , vk : : BufferUsageFlagBits : : eTransferDst , vk : : MemoryPropertyFlagBits : : eHostVisible ) ;
shaderBindingTableBufferData . upload ( device , shaderHandleStorage ) ;
std : : array < vk : : ClearValue , 2 > clearValues ;
clearValues [ 0 ] . color = vk : : ClearColorValue ( std : : array < float , 4 > ( { 0.2f , 0.2f , 0.2f , 0.2f } ) ) ;
2020-01-28 09:16:10 +00:00
clearValues [ 1 ] . depthStencil = vk : : ClearDepthStencilValue ( 1.0f , 0 ) ;
2019-07-25 11:52:09 +00:00
// Main loop
uint32_t frameIndex = 0 ;
UniformBufferObject uniformBufferObject ;
uniformBufferObject . model = glm : : mat4 ( 1 ) ;
uniformBufferObject . modelIT = glm : : inverseTranspose ( uniformBufferObject . model ) ;
double accumulatedTime { 0.0 } ;
size_t frameCount { 0 } ;
while ( ! glfwWindowShouldClose ( window ) )
{
double startTime = glfwGetTime ( ) ;
glfwPollEvents ( ) ;
vk : : UniqueCommandBuffer const & commandBuffer = perFrameData [ frameIndex ] . commandBuffer ;
int w , h ;
glfwGetWindowSize ( window , & w , & h ) ;
if ( ( w ! = static_cast < int > ( windowExtent . width ) ) | | ( h ! = static_cast < int > ( windowExtent . height ) ) )
{
windowExtent . width = w ;
windowExtent . height = h ;
device - > waitIdle ( ) ;
swapChainData = vk : : su : : SwapChainData ( physicalDevice , device , surface , windowExtent , vk : : ImageUsageFlagBits : : eColorAttachment | vk : : ImageUsageFlagBits : : eStorage , swapChainData . swapChain ,
graphicsAndPresentQueueFamilyIndex . first , graphicsAndPresentQueueFamilyIndex . second ) ;
depthBufferData = vk : : su : : DepthBufferData ( physicalDevice , device , vk : : su : : pickDepthFormat ( physicalDevice ) , windowExtent ) ;
vk : : su : : oneTimeSubmit ( commandBuffer , graphicsQueue ,
[ & ] ( vk : : UniqueCommandBuffer const & commandBuffer )
{
vk : : su : : setImageLayout ( commandBuffer , * depthBufferData . image , depthFormat , vk : : ImageLayout : : eUndefined , vk : : ImageLayout : : eDepthStencilAttachmentOptimal ) ;
} ) ;
framebuffers = vk : : su : : createFramebuffers ( device , renderPass , swapChainData . imageViews , depthBufferData . imageView , windowExtent ) ;
}
// update the uniformBufferObject
assert ( 0 < windowExtent . height ) ;
uniformBufferObject . view = appInfo . cameraManipulator . getMatrix ( ) ;
uniformBufferObject . proj = glm : : perspective ( glm : : radians ( 65.0f ) , windowExtent . width / static_cast < float > ( windowExtent . height ) , 0.1f , 1000.0f ) ;
uniformBufferObject . proj [ 1 ] [ 1 ] * = - 1 ; // Inverting Y for Vulkan
uniformBufferObject . viewInverse = glm : : inverse ( uniformBufferObject . view ) ;
uniformBufferObject . projInverse = glm : : inverse ( uniformBufferObject . proj ) ;
uniformBufferData . upload ( device , uniformBufferObject ) ;
// frame begin
vk : : ResultValue < uint32_t > rv = device - > acquireNextImageKHR ( * swapChainData . swapChain , UINT64_MAX , * perFrameData [ frameIndex ] . presentCompleteSemaphore , nullptr ) ;
assert ( rv . result = = vk : : Result : : eSuccess ) ;
uint32_t backBufferIndex = rv . value ;
2019-10-28 14:36:21 +00:00
while ( vk : : Result : : eTimeout = = device - > waitForFences ( * perFrameData [ frameIndex ] . fence , VK_TRUE , vk : : su : : FenceTimeout ) )
;
device - > resetFences ( * perFrameData [ frameIndex ] . fence ) ;
2019-07-25 11:52:09 +00:00
commandBuffer - > begin ( vk : : CommandBufferBeginInfo ( vk : : CommandBufferUsageFlagBits : : eOneTimeSubmit ) ) ;
if ( appInfo . useRasterRender )
{
commandBuffer - > beginRenderPass ( vk : : RenderPassBeginInfo ( * renderPass , * framebuffers [ backBufferIndex ] , vk : : Rect2D ( vk : : Offset2D ( 0 , 0 ) , windowExtent ) ,
static_cast < uint32_t > ( clearValues . size ( ) ) , clearValues . data ( ) ) , vk : : SubpassContents : : eInline ) ;
commandBuffer - > bindPipeline ( vk : : PipelineBindPoint : : eGraphics , * graphicsPipeline ) ;
commandBuffer - > bindDescriptorSets ( vk : : PipelineBindPoint : : eGraphics , * pipelineLayout , 0 , * descriptorSet , nullptr ) ;
commandBuffer - > setViewport ( 0 , vk : : Viewport ( 0.0f , 0.0f , static_cast < float > ( windowExtent . width ) , static_cast < float > ( windowExtent . height ) , 0.0f , 1.0f ) ) ;
commandBuffer - > setScissor ( 0 , vk : : Rect2D ( vk : : Offset2D ( 0 , 0 ) , windowExtent ) ) ;
commandBuffer - > bindVertexBuffers ( 0 , * vertexBufferData . buffer , { 0 } ) ;
commandBuffer - > bindIndexBuffer ( * indexBufferData . buffer , 0 , vk : : IndexType : : eUint32 ) ;
commandBuffer - > drawIndexed ( vk : : su : : checked_cast < uint32_t > ( indices . size ( ) ) , 1 , 0 , 0 , 0 ) ;
2019-12-19 12:59:48 +00:00
commandBuffer - > endRenderPass ( ) ;
2019-07-25 11:52:09 +00:00
}
else
{
vk : : DescriptorImageInfo imageInfo ( nullptr , * swapChainData . imageViews [ backBufferIndex ] , vk : : ImageLayout : : eGeneral ) ;
2019-12-19 12:59:48 +00:00
device - > updateDescriptorSets ( vk : : WriteDescriptorSet ( * rayTracingDescriptorSets [ backBufferIndex ] , 1 , 0 , 1 , bindings [ 1 ] . descriptorType , & imageInfo ) , { } ) ;
2019-07-25 11:52:09 +00:00
2019-12-19 12:59:48 +00:00
vk : : su : : setImageLayout ( commandBuffer , swapChainData . images [ backBufferIndex ] , surfaceFormat . format , vk : : ImageLayout : : eUndefined , vk : : ImageLayout : : eGeneral ) ;
2019-07-25 11:52:09 +00:00
commandBuffer - > bindPipeline ( vk : : PipelineBindPoint : : eRayTracingNV , * rayTracingPipeline ) ;
2019-12-19 12:59:48 +00:00
commandBuffer - > bindDescriptorSets ( vk : : PipelineBindPoint : : eRayTracingNV , * rayTracingPipelineLayout , 0 , * rayTracingDescriptorSets [ backBufferIndex ] , nullptr ) ;
2019-07-25 11:52:09 +00:00
VkDeviceSize rayGenOffset = 0 ; // starting with raygen
VkDeviceSize missOffset = shaderGroupHandleSize ; // after raygen
VkDeviceSize missStride = shaderGroupHandleSize ;
VkDeviceSize hitGroupOffset = shaderGroupHandleSize + 2 * shaderGroupHandleSize ; // after 1x raygen and 2x miss
VkDeviceSize hitGroupStride = shaderGroupHandleSize ;
commandBuffer - > traceRaysNV ( * shaderBindingTableBufferData . buffer , rayGenOffset , * shaderBindingTableBufferData . buffer , missOffset , missStride , * shaderBindingTableBufferData . buffer ,
2019-09-26 07:55:15 +00:00
hitGroupOffset , hitGroupStride , nullptr , 0 , 0 , windowExtent . width , windowExtent . height , 1 ) ;
2019-07-25 11:52:09 +00:00
2019-12-19 12:59:48 +00:00
vk : : su : : setImageLayout ( commandBuffer , swapChainData . images [ backBufferIndex ] , surfaceFormat . format , vk : : ImageLayout : : eGeneral , vk : : ImageLayout : : ePresentSrcKHR ) ;
}
2019-07-25 11:52:09 +00:00
// frame end
commandBuffer - > end ( ) ;
const vk : : PipelineStageFlags waitDstStageMask = vk : : PipelineStageFlagBits : : eColorAttachmentOutput ;
graphicsQueue . submit ( vk : : SubmitInfo ( 1 , & ( * perFrameData [ frameIndex ] . presentCompleteSemaphore ) , & waitDstStageMask , 1 , & ( * commandBuffer ) , 1 ,
& ( * perFrameData [ frameIndex ] . renderCompleteSemaphore ) ) , * perFrameData [ frameIndex ] . fence ) ;
presentQueue . presentKHR ( vk : : PresentInfoKHR ( 1 , & ( * perFrameData [ frameIndex ] . renderCompleteSemaphore ) , 1 , & ( * swapChainData . swapChain ) , & backBufferIndex ) ) ;
frameIndex = ( frameIndex + 1 ) % IMGUI_VK_QUEUED_FRAMES ;
double endTime = glfwGetTime ( ) ;
accumulatedTime + = endTime - startTime ;
+ + frameCount ;
if ( 1.0 < accumulatedTime )
{
assert ( 0 < frameCount ) ;
std : : ostringstream oss ;
oss < < AppName < < " : " < < vertices . size ( ) < < " Vertices " < < ( appInfo . useRasterRender ? " Rastering " : " RayTracing " ) < < " ( " < < frameCount / accumulatedTime < < " fps) " ;
glfwSetWindowTitle ( window , oss . str ( ) . c_str ( ) ) ;
accumulatedTime = 0.0 ;
frameCount = 0 ;
}
}
// Cleanup
device - > waitIdle ( ) ;
swapChainData . swapChain . reset ( ) ; // need to reset swapChain before destroying the surface !
2019-12-23 07:45:40 +00:00
VULKAN_HPP_DEFAULT_DISPATCHER . vkDestroySurfaceKHR ( * instance , surface , nullptr ) ;
2019-07-25 11:52:09 +00:00
glfwDestroyWindow ( window ) ;
glfwTerminate ( ) ;
}
2020-01-28 09:16:10 +00:00
catch ( vk : : SystemError & err )
2019-07-25 11:52:09 +00:00
{
std : : cout < < " vk::SystemError: " < < err . what ( ) < < std : : endl ;
exit ( - 1 ) ;
}
2020-01-28 09:16:10 +00:00
catch ( std : : runtime_error & err )
2019-07-25 11:52:09 +00:00
{
std : : cout < < " std::runtime_error: " < < err . what ( ) < < std : : endl ;
exit ( - 1 ) ;
}
catch ( . . . )
{
std : : cout < < " unknown error \n " ;
exit ( - 1 ) ;
}
return 0 ;
}