Vulkan-Hpp
RayTracing.cpp
Go to the documentation of this file.
1 // Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // VulkanHpp Samples : RayTracing
16 // Simple sample how to ray trace using Vulkan
17 
18 #if defined( _MSC_VER )
19 # pragma warning( disable : 4201 ) // disable warning C4201: nonstandard extension used: nameless struct/union; needed
20  // to get glm/detail/type_vec?.hpp without warnings
21 #elif defined( __clang__ )
22 # pragma clang diagnostic ignored "-Wmissing-braces"
23 # if ( 10 <= __clang_major__ )
24 # pragma clang diagnostic ignored "-Wdeprecated-volatile" // to keep glm/detail/type_half.inl compiling
25 # endif
26 #elif defined( __GNUC__ )
27 #else
28 // unknow compiler... just ignore the warnings for yourselves ;)
29 #endif
30 
31 #include <vulkan/vulkan.hpp>
32 
33 // clang-format off
34 #include <GLFW/glfw3.h>
35 // clang-format on
36 #include <numeric>
37 #include <random>
38 #include <sstream>
40 
41 #define GLM_FORCE_DEPTH_ZERO_TO_ONE
42 #define GLM_FORCE_RADIANS
43 #define GLM_ENABLE_EXPERIMENTAL
44 #include "../utils/shaders.hpp"
45 #include "../utils/utils.hpp"
46 #include "CameraManipulator.hpp"
47 #include "SPIRV/GlslangToSpv.h"
48 
49 #include <glm/glm.hpp>
50 #include <glm/gtc/matrix_inverse.hpp>
51 #include <glm/gtc/matrix_transform.hpp>
52 
53 static char const * AppName = "RayTracing";
54 static char const * EngineName = "Vulkan.hpp";
55 
57 {
59  glm::mat4x4 const & transform_, uint32_t instanceID_, uint8_t mask_, uint32_t instanceOffset_, uint8_t flags_, uint64_t accelerationStructureHandle_ )
60  : instanceId( instanceID_ ), mask( mask_ ), instanceOffset( instanceOffset_ ), flags( flags_ ), accelerationStructureHandle( accelerationStructureHandle_ )
61  {
62  assert( !( instanceID_ & 0xFF000000 ) && !( instanceOffset_ & 0xFF000000 ) );
63  memcpy( transform, &transform_, 12 * sizeof( float ) );
64  }
65 
66  float transform[12]; // Transform matrix, containing only the top 3 rows
67  uint32_t instanceId : 24; // Instance index
68  uint32_t mask : 8; // Visibility mask
69  uint32_t instanceOffset : 24; // Index of the hit group which will be invoked when a ray hits the instance
70  uint32_t flags : 8; // Instance flags, such as culling
71  uint64_t accelerationStructureHandle; // Opaque handle of the bottom-level acceleration structure
72 };
73 
74 static_assert( sizeof( GeometryInstanceData ) == 64, "GeometryInstanceData structure compiles to incorrect size" );
75 
77 {
78  void clear( vk::Device device )
79  {
81  if ( scratchBufferData )
82  {
83  scratchBufferData->clear( device );
84  }
85  if ( resultBufferData )
86  {
87  resultBufferData->clear( device );
88  }
89  if ( instanceBufferData )
90  {
91  instanceBufferData->clear( device );
92  }
93  }
94 
96  std::unique_ptr<vk::su::BufferData> scratchBufferData;
97  std::unique_ptr<vk::su::BufferData> resultBufferData;
98  std::unique_ptr<vk::su::BufferData> instanceBufferData;
99 };
100 
102  vk::Device const & device,
103  vk::CommandBuffer const & commandBuffer,
104  std::vector<std::pair<vk::AccelerationStructureNV, glm::mat4x4>> const & instances,
105  std::vector<vk::GeometryNV> const & geometries )
106 {
107  assert( instances.empty() ^ geometries.empty() );
108 
109  AccelerationStructureData accelerationStructureData;
110 
111  vk::AccelerationStructureTypeNV accelerationStructureType =
112  instances.empty() ? vk::AccelerationStructureTypeNV::eBottomLevel : vk::AccelerationStructureTypeNV::eTopLevel;
113  vk::AccelerationStructureInfoNV accelerationStructureInfo( accelerationStructureType, {}, vk::su::checked_cast<uint32_t>( instances.size() ), geometries );
114  accelerationStructureData.accelerationStructure =
115  device.createAccelerationStructureNV( vk::AccelerationStructureCreateInfoNV( 0, accelerationStructureInfo ) );
116 
118  accelerationStructureData.accelerationStructure );
119  vk::DeviceSize resultSizeInBytes = device.getAccelerationStructureMemoryRequirementsNV( objectRequirements ).memoryRequirements.size;
120  assert( 0 < resultSizeInBytes );
121  accelerationStructureData.resultBufferData = std::unique_ptr<vk::su::BufferData>(
123 
125  accelerationStructureData.accelerationStructure );
127  accelerationStructureData.accelerationStructure );
128  vk::DeviceSize scratchSizeInBytes = std::max( device.getAccelerationStructureMemoryRequirementsNV( buildScratchRequirements ).memoryRequirements.size,
129  device.getAccelerationStructureMemoryRequirementsNV( updateScratchRequirements ).memoryRequirements.size );
130  assert( 0 < scratchSizeInBytes );
131 
132  accelerationStructureData.scratchBufferData = std::unique_ptr<vk::su::BufferData>(
133  new vk::su::BufferData( physicalDevice, device, scratchSizeInBytes, vk::BufferUsageFlagBits::eRayTracingNV, vk::MemoryPropertyFlagBits::eDeviceLocal ) );
134 
135  if ( !instances.empty() )
136  {
137  accelerationStructureData.instanceBufferData = std::unique_ptr<vk::su::BufferData>(
138  new vk::su::BufferData( physicalDevice, device, instances.size() * sizeof( GeometryInstanceData ), vk::BufferUsageFlagBits::eRayTracingNV ) );
139 
140  std::vector<GeometryInstanceData> geometryInstanceData;
141  for ( size_t i = 0; i < instances.size(); i++ )
142  {
143  uint64_t accelerationStructureHandle = device.getAccelerationStructureHandleNV<uint64_t>( instances[i].first );
144 
145  // For each instance we set its instance index to its index i in the instance vector, and set
146  // its hit group index to 2*i. The hit group index defines which entry of the shader binding
147  // table will contain the hit group to be executed when hitting this instance. We set this
148  // index to 2*i due to the use of 2 types of rays in the scene: the camera rays and the shadow
149  // rays. For each instance, the SBT will then have 2 hit groups
150  geometryInstanceData.emplace_back( GeometryInstanceData( glm::transpose( instances[i].second ),
151  static_cast<uint32_t>( i ),
152  0xFF,
153  static_cast<uint32_t>( 2 * i ),
154  static_cast<uint8_t>( vk::GeometryInstanceFlagBitsNV::eTriangleCullDisable ),
155  accelerationStructureHandle ) );
156  }
157  accelerationStructureData.instanceBufferData->upload( device, geometryInstanceData );
158  }
159 
161  vk::BindAccelerationStructureMemoryInfoNV( accelerationStructureData.accelerationStructure, accelerationStructureData.resultBufferData->deviceMemory ) );
162 
163  commandBuffer.buildAccelerationStructureNV(
164  vk::AccelerationStructureInfoNV( accelerationStructureType, {}, vk::su::checked_cast<uint32_t>( instances.size() ), geometries ),
165  accelerationStructureData.instanceBufferData ? accelerationStructureData.instanceBufferData->buffer : nullptr,
166  0,
167  false,
168  accelerationStructureData.accelerationStructure,
169  nullptr,
170  accelerationStructureData.scratchBufferData->buffer,
171  0 );
172 
175  {},
178  {},
179  {} );
180 
181  return accelerationStructureData;
182 }
183 
185 {
186  void clear( vk::Device device )
187  {
190  device.destroyFence( fence );
193  }
194 
200 };
201 
203 {
204  glm::mat4 model;
205  glm::mat4 view;
206  glm::mat4 proj;
207  glm::mat4 modelIT;
208  glm::mat4 viewInverse;
209  glm::mat4 projInverse;
210 };
211 
212 struct Material
213 {
214  glm::vec3 diffuse = glm::vec3( 0.7f, 0.7f, 0.7f );
215  int textureID = -1;
216 };
217 
218 const size_t MaterialStride = ( ( sizeof( Material ) + 15 ) / 16 ) * 16;
219 
220 struct Vertex
221 {
222  Vertex( glm::vec3 const & p, glm::vec3 const & n, glm::vec2 const & tc, int m = 0 ) : pos( p ), nrm( n ), texCoord( tc ), matID( m ) {}
223 
224  glm::vec3 pos;
225  glm::vec3 nrm;
226  glm::vec2 texCoord;
227  int matID;
228 };
229 
230 const size_t VertexStride = ( ( sizeof( Vertex ) + 15 ) / 16 ) * 16;
231 
232 static const std::vector<Vertex> cubeData = {
233  // pos nrm texcoord matID
234  // front face
235  { Vertex( glm::vec3( -1.0f, -1.0f, 1.0f ), glm::vec3( 0.0f, 0.0f, 1.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
236  { Vertex( glm::vec3( 1.0f, -1.0f, 1.0f ), glm::vec3( 0.0f, 0.0f, 1.0f ), glm::vec2( 1.0f, 0.0f ), 0 ) },
237  { Vertex( glm::vec3( 1.0f, 1.0f, 1.0f ), glm::vec3( 0.0f, 0.0f, 1.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
238  { Vertex( glm::vec3( 1.0f, 1.0f, 1.0f ), glm::vec3( 0.0f, 0.0f, 1.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
239  { Vertex( glm::vec3( -1.0f, 1.0f, 1.0f ), glm::vec3( 0.0f, 0.0f, 1.0f ), glm::vec2( 0.0f, 1.0f ), 0 ) },
240  { Vertex( glm::vec3( -1.0f, -1.0f, 1.0f ), glm::vec3( 0.0f, 0.0f, 1.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
241  // back face
242  { Vertex( glm::vec3( 1.0f, -1.0f, -1.0f ), glm::vec3( 0.0f, 0.0f, -1.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
243  { Vertex( glm::vec3( -1.0f, -1.0f, -1.0f ), glm::vec3( 0.0f, 0.0f, -1.0f ), glm::vec2( 1.0f, 0.0f ), 0 ) },
244  { Vertex( glm::vec3( -1.0f, 1.0f, -1.0f ), glm::vec3( 0.0f, 0.0f, -1.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
245  { Vertex( glm::vec3( -1.0f, 1.0f, -1.0f ), glm::vec3( 0.0f, 0.0f, -1.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
246  { Vertex( glm::vec3( 1.0f, 1.0f, -1.0f ), glm::vec3( 0.0f, 0.0f, -1.0f ), glm::vec2( 0.0f, 1.0f ), 0 ) },
247  { Vertex( glm::vec3( 1.0f, -1.0f, -1.0f ), glm::vec3( 0.0f, 0.0f, -1.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
248  // left face
249  { Vertex( glm::vec3( -1.0f, -1.0f, -1.0f ), glm::vec3( -1.0f, 0.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
250  { Vertex( glm::vec3( -1.0f, -1.0f, 1.0f ), glm::vec3( -1.0f, 0.0f, 0.0f ), glm::vec2( 1.0f, 0.0f ), 0 ) },
251  { Vertex( glm::vec3( -1.0f, 1.0f, 1.0f ), glm::vec3( -1.0f, 0.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
252  { Vertex( glm::vec3( -1.0f, 1.0f, 1.0f ), glm::vec3( -1.0f, 0.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
253  { Vertex( glm::vec3( -1.0f, 1.0f, -1.0f ), glm::vec3( -1.0f, 0.0f, 0.0f ), glm::vec2( 0.0f, 1.0f ), 0 ) },
254  { Vertex( glm::vec3( -1.0f, -1.0f, -1.0f ), glm::vec3( -1.0f, 0.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
255  // right face
256  { Vertex( glm::vec3( 1.0f, -1.0f, 1.0f ), glm::vec3( 1.0f, 0.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
257  { Vertex( glm::vec3( 1.0f, -1.0f, -1.0f ), glm::vec3( 1.0f, 0.0f, 0.0f ), glm::vec2( 1.0f, 0.0f ), 0 ) },
258  { Vertex( glm::vec3( 1.0f, 1.0f, -1.0f ), glm::vec3( 1.0f, 0.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
259  { Vertex( glm::vec3( 1.0f, 1.0f, -1.0f ), glm::vec3( 1.0f, 0.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
260  { Vertex( glm::vec3( 1.0f, 1.0f, 1.0f ), glm::vec3( 1.0f, 0.0f, 0.0f ), glm::vec2( 0.0f, 1.0f ), 0 ) },
261  { Vertex( glm::vec3( 1.0f, -1.0f, 1.0f ), glm::vec3( 1.0f, 0.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
262  // top face
263  { Vertex( glm::vec3( -1.0f, 1.0f, 1.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
264  { Vertex( glm::vec3( 1.0f, 1.0f, 1.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ), glm::vec2( 1.0f, 0.0f ), 0 ) },
265  { Vertex( glm::vec3( 1.0f, 1.0f, -1.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
266  { Vertex( glm::vec3( 1.0f, 1.0f, -1.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
267  { Vertex( glm::vec3( -1.0f, 1.0f, -1.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ), glm::vec2( 0.0f, 1.0f ), 0 ) },
268  { Vertex( glm::vec3( -1.0f, 1.0f, 1.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
269  // bottom face
270  { Vertex( glm::vec3( -1.0f, -1.0f, -1.0f ), glm::vec3( 0.0f, -1.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
271  { Vertex( glm::vec3( 1.0f, -1.0f, -1.0f ), glm::vec3( 0.0f, -1.0f, 0.0f ), glm::vec2( 1.0f, 0.0f ), 0 ) },
272  { Vertex( glm::vec3( 1.0f, -1.0f, 1.0f ), glm::vec3( 0.0f, -1.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
273  { Vertex( glm::vec3( 1.0f, -1.0f, 1.0f ), glm::vec3( 0.0f, -1.0f, 0.0f ), glm::vec2( 1.0f, 1.0f ), 0 ) },
274  { Vertex( glm::vec3( -1.0f, -1.0f, 1.0f ), glm::vec3( 0.0f, -1.0f, 0.0f ), glm::vec2( 0.0f, 1.0f ), 0 ) },
275  { Vertex( glm::vec3( -1.0f, -1.0f, -1.0f ), glm::vec3( 0.0f, -1.0f, 0.0f ), glm::vec2( 0.0f, 0.0f ), 0 ) },
276 };
277 
278 static std::string vertexShaderText = R"(
279 #version 450
280 
281 #extension GL_ARB_separate_shader_objects : enable
282 
283 layout(binding = 0) uniform UniformBufferObject
284 {
285  mat4 model;
286  mat4 view;
287  mat4 proj;
288  mat4 modelIT;
289 } ubo;
290 
291 layout(location = 0) in vec3 inPosition;
292 layout(location = 1) in vec3 inNormal;
293 layout(location = 2) in vec2 inTexCoord;
294 layout(location = 3) in int inMatID;
295 
296 layout(location = 0) flat out int outMatID;
297 layout(location = 1) out vec2 outTexCoord;
298 layout(location = 2) out vec3 outNormal;
299 
300 out gl_PerVertex
301 {
302  vec4 gl_Position;
303 };
304 
305 void main()
306 {
307  gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
308  outMatID = inMatID;
309  outTexCoord = inTexCoord;
310  outNormal = vec3(ubo.modelIT * vec4(inNormal, 0.0));
311 }
312 )";
313 
314 static std::string fragmentShaderText = R"(
315 #version 450
316 
317 #extension GL_ARB_separate_shader_objects : enable
318 #extension GL_EXT_nonuniform_qualifier : enable
319 
320 layout(location = 0) flat in int matIndex;
321 layout(location = 1) in vec2 texCoord;
322 layout(location = 2) in vec3 normal;
323 
324 struct Material
325 {
326  vec3 diffuse;
327  int textureID;
328 };
329 const int sizeofMat = 1;
330 
331 layout(binding = 1) buffer MaterialBufferObject { vec4[] m; } materials;
332 layout(binding = 2) uniform sampler2D[] textureSamplers;
333 
334 Material unpackMaterial()
335 {
336  Material m;
337  vec4 d0 = materials.m[sizeofMat * matIndex + 0];
338 
339  m.diffuse = d0.xyz;
340  m.textureID = floatBitsToInt(d0.w);
341 
342  return m;
343 }
344 
345 layout(location = 0) out vec4 outColor;
346 
347 void main()
348 {
349  vec3 lightVector = normalize(vec3(5, 4, 3));
350 
351  float dot_product = max(dot(lightVector, normalize(normal)), 0.2);
352 
353  Material m = unpackMaterial();
354  vec3 c = m.diffuse;
355  if (0 <= m.textureID)
356  {
357  c *= texture(textureSamplers[m.textureID], texCoord).xyz;
358  }
359  c *= dot_product;
360 
361  outColor = vec4(c, 1);
362 }
363 )";
364 
365 static std::string raygenShaderText = R"(
366 #version 460
367 
368 #extension GL_NV_ray_tracing : require
369 
370 layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
371 layout(binding = 1, set = 0, rgba8) uniform image2D image;
372 
373 layout(binding=2, set = 0) uniform UniformBufferObject
374 {
375  mat4 model;
376  mat4 view;
377  mat4 proj;
378  mat4 modelIT;
379  mat4 viewInverse;
380  mat4 projInverse;
381 } cam;
382 
383 layout(location = 0) rayPayloadNV vec3 hitValue;
384 
385 void main()
386 {
387  const vec2 pixelCenter = vec2(gl_LaunchIDNV.xy) + vec2(0.5);
388  const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeNV.xy);
389  vec2 d = inUV * 2.0 - 1.0;
390 
391  vec4 origin = cam.viewInverse*vec4(0,0,0,1);
392  vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1) ;
393  vec4 direction = cam.viewInverse*vec4(normalize(target.xyz), 0) ;
394 
395  uint rayFlags = gl_RayFlagsOpaqueNV;
396  uint cullMask = 0xff;
397  float tmin = 0.001;
398  float tmax = 10000.0;
399 
400  traceNV(topLevelAS, rayFlags, cullMask, 0 /*sbtRecordOffset*/, 0 /*sbtRecordStride*/, 0 /*missIndex*/, origin.xyz, tmin, direction.xyz, tmax, 0 /*payload*/);
401  imageStore(image, ivec2(gl_LaunchIDNV.xy), vec4(hitValue, 0.0));
402 }
403 )";
404 
405 static std::string missShaderText = R"(
406 #version 460
407 
408 #extension GL_NV_ray_tracing : require
409 
410 layout(location = 0) rayPayloadInNV vec3 hitValue;
411 
412 void main()
413 {
414  hitValue = vec3(0.0, 0.1, 0.3);
415 }
416 )";
417 
418 static std::string shadowMissShaderText = R"(
419 #version 460
420 
421 #extension GL_NV_ray_tracing : require
422 
423 layout(location = 2) rayPayloadInNV bool isShadowed;
424 
425 void main()
426 {
427  isShadowed = false;
428 })";
429 
430 static std::string closestHitShaderText = R"(
431 #version 460
432 
433 #extension GL_NV_ray_tracing : require
434 #extension GL_EXT_nonuniform_qualifier : enable
435 
436 layout(location = 0) rayPayloadInNV vec3 hitValue;
437 layout(location = 2) rayPayloadNV bool isShadowed;
438 
439 hitAttributeNV vec3 attribs;
440 layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
441 
442 layout(binding = 3, set = 0) buffer Vertices { vec4 v[]; } vertices;
443 layout(binding = 4, set = 0) buffer Indices { uint i[]; } indices;
444 
445 layout(binding = 5, set = 0) buffer MatColorBufferObject { vec4[] m; } materials;
446 layout(binding = 6, set = 0) uniform sampler2D[] textureSamplers;
447 
448 struct Vertex
449 {
450  vec3 pos;
451  vec3 nrm;
452  vec2 texCoord;
453  int matIndex;
454 };
455 // Number of vec4 values used to represent a vertex
456 uint vertexSize = 3;
457 
458 Vertex unpackVertex(uint index)
459 {
460  Vertex v;
461 
462  vec4 d0 = vertices.v[vertexSize * index + 0];
463  vec4 d1 = vertices.v[vertexSize * index + 1];
464  vec4 d2 = vertices.v[vertexSize * index + 2];
465 
466  v.pos = d0.xyz;
467  v.nrm = vec3(d0.w, d1.xy);
468  v.texCoord = d1.zw;
469  v.matIndex = floatBitsToInt(d2.x);
470  return v;
471 }
472 
473 struct Material
474 {
475  vec3 diffuse;
476  int textureID;
477 };
478 // Number of vec4 values used to represent a material
479 const int sizeofMat = 1;
480 
481 Material unpackMaterial(int matIndex)
482 {
483  Material m;
484  vec4 d0 = materials.m[sizeofMat * matIndex + 0];
485 
486  m.diffuse = d0.xyz;
487  m.textureID = floatBitsToInt(d0.w);
488  return m;
489 }
490 
491 void main()
492 {
493  ivec3 ind = ivec3(indices.i[3 * gl_PrimitiveID], indices.i[3 * gl_PrimitiveID + 1], indices.i[3 * gl_PrimitiveID + 2]);
494 
495  Vertex v0 = unpackVertex(ind.x);
496  Vertex v1 = unpackVertex(ind.y);
497  Vertex v2 = unpackVertex(ind.z);
498 
499  const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
500 
501  vec3 normal = normalize(v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z);
502 
503  vec3 lightVector = normalize(vec3(5, 4, 3));
504 
505  float dot_product = max(dot(lightVector, normal), 0.2);
506 
507  Material mat = unpackMaterial(v1.matIndex);
508 
509  vec3 c = dot_product * mat.diffuse;
510  if (0 <= mat.textureID)
511  {
512  vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
513  c *= texture(textureSamplers[mat.textureID], texCoord).xyz;
514  }
515  float tmin = 0.001;
516  float tmax = 100.0;
517  vec3 origin = gl_WorldRayOriginNV + gl_WorldRayDirectionNV * gl_HitTNV;
518  isShadowed = true;
519  traceNV(topLevelAS, gl_RayFlagsTerminateOnFirstHitNV|gl_RayFlagsOpaqueNV|gl_RayFlagsSkipClosestHitShaderNV, 0xFF, 1 /* sbtRecordOffset */, 0 /* sbtRecordStride */, 1 /* missIndex */, origin,
520  tmin, lightVector, tmax, 2 /*payload location*/);
521  hitValue = c;
522  if (isShadowed)
523  {
524  hitValue *= 0.3f;
525  }
526 }
527 )";
528 
529 #ifndef IMGUI_VK_QUEUED_FRAMES
530 # define IMGUI_VK_QUEUED_FRAMES 2
531 #endif // !IMGUI_VK_QUEUED_FRAMES
532 
533 struct AppInfo
534 {
536  bool useRasterRender = false;
537 };
538 
539 static void check_vk_result( VkResult err )
540 {
541  if ( err != 0 )
542  {
543  std::cerr << AppName << ": Vulkan error " << vk::to_string( static_cast<vk::Result>( err ) );
544  if ( err < 0 )
545  {
546  abort();
547  }
548  }
549 }
550 
551 static void cursorPosCallback( GLFWwindow * window, double mouseX, double mouseY )
552 {
554  ( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT ) == GLFW_PRESS ) ? vk::su::CameraManipulator::MouseButton::Left
555  : ( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) ? vk::su::CameraManipulator::MouseButton::Middle
556  : ( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) ? vk::su::CameraManipulator::MouseButton::Right
559  {
561  if ( glfwGetKey( window, GLFW_KEY_LEFT_ALT ) == GLFW_PRESS )
562  {
564  }
565  if ( glfwGetKey( window, GLFW_KEY_LEFT_CONTROL ) == GLFW_PRESS )
566  {
568  }
569  if ( glfwGetKey( window, GLFW_KEY_LEFT_SHIFT ) == GLFW_PRESS )
570  {
572  }
573 
574  vk::su::CameraManipulator & cameraManipulator = reinterpret_cast<AppInfo *>( glfwGetWindowUserPointer( window ) )->cameraManipulator;
575  cameraManipulator.mouseMove( glm::ivec2( static_cast<int>( mouseX ), static_cast<int>( mouseY ) ), mouseButton, modifiers );
576  }
577 }
578 
579 static void errorCallback( int error, const char * description )
580 {
581  fprintf( stderr, "GLFW Error %d: %s\n", error, description );
582 }
583 
584 static void framebufferSizeCallback( GLFWwindow * window, int w, int h )
585 {
586  vk::su::CameraManipulator & cameraManipulator = reinterpret_cast<AppInfo *>( glfwGetWindowUserPointer( window ) )->cameraManipulator;
587  cameraManipulator.setWindowSize( glm::ivec2( w, h ) );
588 }
589 
590 static void keyCallback( GLFWwindow * window, int key, int /*scancode*/, int action, int /*mods*/ )
591 {
592  if ( action == GLFW_PRESS )
593  {
594  switch ( key )
595  {
596  case GLFW_KEY_ESCAPE:
597  case 'Q': glfwSetWindowShouldClose( window, 1 ); break;
598  case 'R':
599  {
600  AppInfo * appInfo = reinterpret_cast<AppInfo *>( glfwGetWindowUserPointer( window ) );
601  appInfo->useRasterRender = !appInfo->useRasterRender;
602  }
603  break;
604  }
605  }
606 }
607 
608 static void mouseButtonCallback( GLFWwindow * window, int /*button*/, int /*action*/, int /*mods*/ )
609 {
610  double xpos, ypos;
611  glfwGetCursorPos( window, &xpos, &ypos );
612 
613  vk::su::CameraManipulator & cameraManipulator = reinterpret_cast<AppInfo *>( glfwGetWindowUserPointer( window ) )->cameraManipulator;
614  cameraManipulator.setMousePosition( glm::ivec2( static_cast<int>( xpos ), static_cast<int>( ypos ) ) );
615 }
616 
617 static void scrollCallback( GLFWwindow * window, double /*xoffset*/, double yoffset )
618 {
619  vk::su::CameraManipulator & cameraManipulator = reinterpret_cast<AppInfo *>( glfwGetWindowUserPointer( window ) )->cameraManipulator;
620  cameraManipulator.wheel( static_cast<int>( yoffset ) );
621 }
622 
623 // random data and functions
624 static std::random_device randomDevice;
625 static std::mt19937 randomGenerator( randomDevice() );
626 
627 template <typename T>
628 T random( T minValue = std::numeric_limits<T>::min(), T maxValue = std::numeric_limits<T>::max() )
629 {
630  static_assert( std::numeric_limits<T>::is_integer, "Type T needs to be an integral type!\n" );
631  std::uniform_int_distribution<> randomDistribution( minValue, maxValue );
632 
633  return static_cast<T>( randomDistribution( randomGenerator ) );
634 }
635 
636 glm::vec3 randomVec3( float minValue, float maxValue )
637 {
638  std::uniform_real_distribution<float> randomDistribution( minValue, maxValue );
639 
640  return glm::vec3( randomDistribution( randomGenerator ), randomDistribution( randomGenerator ), randomDistribution( randomGenerator ) );
641 }
642 
643 uint32_t roundUp( uint32_t value, uint32_t alignment )
644 {
645  return ( ( value + alignment - 1 ) / alignment ) * alignment;
646 }
647 
648 int main( int /*argc*/, char ** /*argv*/ )
649 {
650  // number of cubes in x-, y-, and z-direction
651  const size_t xMax = 10;
652  const size_t yMax = 10;
653  const size_t zMax = 10;
654 
655  AppInfo appInfo;
656 
657  try
658  {
659  // Setup glfw
660  glfwSetErrorCallback( errorCallback );
661  if ( !glfwInit() )
662  {
663  std::cerr << AppName << ": can't initialize glfw!\n";
664  return 1;
665  }
666  if ( !glfwVulkanSupported() )
667  {
668  std::cerr << AppName << ": Vulkan not supported!\n";
669  return 1;
670  }
671 
672  // create a window using glfw
673  glfwWindowHint( GLFW_CLIENT_API, GLFW_NO_API );
674  vk::Extent2D windowExtent( 1280, 720 );
675  GLFWwindow * window = glfwCreateWindow( windowExtent.width, windowExtent.height, AppName, nullptr, nullptr );
676 
677  // install some callbacks
678  glfwSetCursorPosCallback( window, cursorPosCallback );
679  glfwSetFramebufferSizeCallback( window, framebufferSizeCallback );
680  glfwSetKeyCallback( window, keyCallback );
681  glfwSetMouseButtonCallback( window, mouseButtonCallback );
682  glfwSetScrollCallback( window, scrollCallback );
683 
684  // Setup camera and make it available as the userPointer in the glfw window
685  appInfo.cameraManipulator.setWindowSize( glm::u32vec2( windowExtent.width, windowExtent.height ) );
686  glm::vec3 diagonal = 3.0f * glm::vec3( static_cast<float>( xMax ), static_cast<float>( yMax ), static_cast<float>( zMax ) );
687  appInfo.cameraManipulator.setLookat( 1.5f * diagonal, 0.5f * diagonal, glm::vec3( 0, 1, 0 ) );
688  glfwSetWindowUserPointer( window, &appInfo );
689 
690  // Create Vulkan Instance with needed extensions
691  uint32_t glfwExtensionsCount;
692  const char ** glfwExtensions = glfwGetRequiredInstanceExtensions( &glfwExtensionsCount );
693  std::vector<std::string> instanceExtensions;
694  instanceExtensions.reserve( glfwExtensionsCount + 1 );
695  for ( uint32_t i = 0; i < glfwExtensionsCount; i++ )
696  {
697  instanceExtensions.push_back( glfwExtensions[i] );
698  }
699  instanceExtensions.push_back( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME );
700 
701  vk::Instance instance = vk::su::createInstance( AppName, EngineName, {}, instanceExtensions );
702 #if !defined( NDEBUG )
704 #endif
705 
706  vk::PhysicalDevice physicalDevice = nullptr;
707  std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
708  for ( auto pd : physicalDevices )
709  {
710  std::vector<vk::ExtensionProperties> ep = pd.enumerateDeviceExtensionProperties();
711  if ( std::any_of( ep.cbegin(),
712  ep.cend(),
713  []( vk::ExtensionProperties const & prop ) { return strcmp( prop.extensionName, VK_NV_RAY_TRACING_EXTENSION_NAME ) == 0; } ) )
714  {
715  physicalDevice = pd;
716  break;
717  }
718  }
719  if ( !physicalDevice )
720  {
721  std::cerr << AppName << ": can't find a PhysicalDevice supporting extension <" << VK_NV_RAY_TRACING_EXTENSION_NAME << ">" << std::endl;
722  return 1;
723  }
724 
725  // Create Window Surface (using glfw)
726  vk::SurfaceKHR surface;
727  VkResult err = glfwCreateWindowSurface( static_cast<VkInstance>( instance ), window, nullptr, reinterpret_cast<VkSurfaceKHR *>( &surface ) );
728  check_vk_result( err );
729 
730  std::pair<uint32_t, uint32_t> graphicsAndPresentQueueFamilyIndex = vk::su::findGraphicsAndPresentQueueFamilyIndex( physicalDevice, surface );
731 
732  // Create a Device with ray tracing support (besides some other extensions needed) and needed features
734  vk::Device device = vk::su::createDevice( physicalDevice,
735  graphicsAndPresentQueueFamilyIndex.first,
736  { VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
737  VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
738  VK_KHR_MAINTENANCE_3_EXTENSION_NAME,
739  VK_KHR_SWAPCHAIN_EXTENSION_NAME,
740  VK_NV_RAY_TRACING_EXTENSION_NAME },
741  &supportedFeatures.get<vk::PhysicalDeviceFeatures2>().features,
742  &supportedFeatures.get<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT>() );
743 
744  // setup stuff per frame
745  std::array<PerFrameData, IMGUI_VK_QUEUED_FRAMES> perFrameData;
746  for ( int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++ )
747  {
748  perFrameData[i].commandPool = device.createCommandPool( vk::CommandPoolCreateInfo( {}, graphicsAndPresentQueueFamilyIndex.first ) );
749  perFrameData[i].commandBuffer =
750  device.allocateCommandBuffers( vk::CommandBufferAllocateInfo( perFrameData[i].commandPool, vk::CommandBufferLevel::ePrimary, 1 ) ).front();
751  perFrameData[i].fence = device.createFence( vk::FenceCreateInfo( vk::FenceCreateFlagBits::eSignaled ) );
752  perFrameData[i].presentCompleteSemaphore = device.createSemaphore( vk::SemaphoreCreateInfo() );
753  perFrameData[i].renderCompleteSemaphore = device.createSemaphore( vk::SemaphoreCreateInfo() );
754  }
755 
756  vk::Queue graphicsQueue = device.getQueue( graphicsAndPresentQueueFamilyIndex.first, 0 );
757  vk::Queue presentQueue = device.getQueue( graphicsAndPresentQueueFamilyIndex.second, 0 );
758 
759  // create a descriptor pool with a number of available descriptors
760  std::vector<vk::DescriptorPoolSize> poolSizes = {
764  };
765  vk::DescriptorPool descriptorPool = vk::su::createDescriptorPool( device, poolSizes );
766 
767  // setup swap chain, render pass, depth buffer and the frame buffers
768  vk::su::SwapChainData swapChainData( physicalDevice,
769  device,
770  surface,
771  windowExtent,
773  nullptr,
774  graphicsAndPresentQueueFamilyIndex.first,
775  graphicsAndPresentQueueFamilyIndex.second );
776  vk::SurfaceFormatKHR surfaceFormat = vk::su::pickSurfaceFormat( physicalDevice.getSurfaceFormatsKHR( surface ) );
777  vk::Format depthFormat = vk::su::pickDepthFormat( physicalDevice );
778 
779  // setup a render pass
780  vk::RenderPass renderPass = vk::su::createRenderPass( device, surfaceFormat.format, depthFormat );
781 
782  vk::su::DepthBufferData depthBufferData( physicalDevice, device, depthFormat, windowExtent );
783  std::vector<vk::Framebuffer> framebuffers =
784  vk::su::createFramebuffers( device, renderPass, swapChainData.imageViews, depthBufferData.imageView, windowExtent );
785 
786  bool samplerAnisotropy = !!supportedFeatures.get<vk::PhysicalDeviceFeatures2>().features.samplerAnisotropy;
787 
788  // create some simple checkerboard textures, randomly sized and colored
789  const size_t textureCount = 10;
790  std::vector<vk::su::TextureData> textures;
791  textures.reserve( textureCount );
792  for ( size_t i = 0; i < textureCount; i++ )
793  {
794  textures.emplace_back( physicalDevice,
795  device,
796  vk::Extent2D( random<uint32_t>( 2, 8 ) * 16, random<uint32_t>( 2, 8 ) * 16 ),
799  samplerAnisotropy,
800  true );
801  }
802  vk::su::oneTimeSubmit( device,
803  perFrameData[0].commandPool,
804  graphicsQueue,
805  [&]( vk::CommandBuffer const & commandBuffer )
806  {
807  for ( auto & t : textures )
808  {
809  t.setImage( device,
810  commandBuffer,
811  vk::su::CheckerboardImageGenerator( { random<uint8_t>(), random<uint8_t>(), random<uint8_t>() },
812  { random<uint8_t>(), random<uint8_t>(), random<uint8_t>() } ) );
813  }
814  } );
815 
816  // create some materials with a random diffuse color, referencing one of the above textures
817  const size_t materialCount = 10;
818  assert( materialCount == textureCount );
819  std::vector<Material> materials( materialCount );
820  for ( size_t i = 0; i < materialCount; i++ )
821  {
822  materials[i].diffuse = randomVec3( 0.0f, 1.0f );
823  materials[i].textureID = vk::su::checked_cast<uint32_t>( i );
824  }
825  vk::su::BufferData materialBufferData( physicalDevice, device, materialCount * MaterialStride, vk::BufferUsageFlagBits::eStorageBuffer );
826  materialBufferData.upload( device, materials, MaterialStride );
827 
828  // create a a 3D-array of cubes, randomly jittered, using a random material
829  std::vector<Vertex> vertices;
830  vertices.reserve( xMax * yMax * zMax * cubeData.size() );
831  for ( size_t x = 0; x < xMax; x++ )
832  {
833  for ( size_t y = 0; y < yMax; y++ )
834  {
835  for ( size_t z = 0; z < zMax; z++ )
836  {
837  int m = random<int>( 0, materialCount - 1 );
838  glm::vec3 jitter = randomVec3( 0.0f, 0.6f );
839  for ( auto const & v : cubeData )
840  {
841  vertices.push_back( v );
842  vertices.back().pos += 3.0f * glm::vec3( static_cast<float>( x ), static_cast<float>( y ), static_cast<float>( z ) ) + jitter;
843  vertices.back().matID = static_cast<int>( m );
844  }
845  }
846  }
847  }
848 
849  // create an 1-1 index buffer
850  std::vector<unsigned int> indices( vertices.size() );
851  std::iota( indices.begin(), indices.end(), 0 );
852 
853  // there's just one vertex- and one index-buffer, but with more complex scene loaders there might be more!
854  vk::su::BufferData vertexBufferData( physicalDevice,
855  device,
856  vertices.size() * VertexStride,
860  vertexBufferData.upload( physicalDevice, device, perFrameData[0].commandPool, graphicsQueue, vertices, VertexStride );
861 
862  vk::su::BufferData indexBufferData( physicalDevice,
863  device,
864  indices.size() * sizeof( uint32_t ),
867  indexBufferData.upload( physicalDevice, device, perFrameData[0].commandPool, graphicsQueue, indices, sizeof( uint32_t ) );
868 
869  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 ) );
870 
872  device,
875  { vk::DescriptorType::eCombinedImageSampler, static_cast<uint32_t>( textures.size() ), vk::ShaderStageFlagBits::eFragment } } );
876  vk::PipelineLayout pipelineLayout = device.createPipelineLayout( vk::PipelineLayoutCreateInfo( {}, descriptorSetLayout ) );
877 
878  glslang::InitializeProcess();
881  glslang::FinalizeProcess();
882 
883  vk::Pipeline graphicsPipeline =
885  {},
886  std::make_pair( vertexShaderModule, nullptr ),
887  std::make_pair( fragmentShaderModule, nullptr ),
888  VertexStride,
889  { { vk::Format::eR32G32B32Sfloat, vk::su::checked_cast<uint32_t>( offsetof( Vertex, pos ) ) },
890  { vk::Format::eR32G32B32Sfloat, vk::su::checked_cast<uint32_t>( offsetof( Vertex, nrm ) ) },
891  { vk::Format::eR32G32Sfloat, vk::su::checked_cast<uint32_t>( offsetof( Vertex, texCoord ) ) },
892  { vk::Format::eR32Sint, vk::su::checked_cast<uint32_t>( offsetof( Vertex, matID ) ) } },
894  true,
895  pipelineLayout,
896  renderPass );
897 
898  vk::su::BufferData uniformBufferData( physicalDevice, device, sizeof( UniformBufferObject ), vk::BufferUsageFlagBits::eUniformBuffer );
899 
900  vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo( descriptorPool, descriptorSetLayout );
901  vk::DescriptorSet descriptorSet = device.allocateDescriptorSets( descriptorSetAllocateInfo ).front();
903  descriptorSet,
904  { { vk::DescriptorType::eUniformBuffer, uniformBufferData.buffer, VK_WHOLE_SIZE, {} },
905  { vk::DescriptorType::eStorageBuffer, materialBufferData.buffer, VK_WHOLE_SIZE, {} } },
906  textures );
907 
908  // RayTracing specific stuff
909 
910  // create acceleration structures: one top-level, and just one bottom-level
911  AccelerationStructureData topLevelAS, bottomLevelAS;
913  device,
914  perFrameData[0].commandPool,
915  graphicsQueue,
916  [&]( vk::CommandBuffer const & commandBuffer )
917  {
918  vk::GeometryDataNV geometryDataNV( vk::GeometryTrianglesNV( vertexBufferData.buffer,
919  0,
920  vk::su::checked_cast<uint32_t>( vertices.size() ),
921  VertexStride,
923  indexBufferData.buffer,
924  0,
925  vk::su::checked_cast<uint32_t>( indices.size() ),
927  {} );
928  bottomLevelAS =
929  createAccelerationStructureData( physicalDevice, device, commandBuffer, {}, { vk::GeometryNV( vk::GeometryTypeNV::eTriangles, geometryDataNV ) } );
930 
931  topLevelAS = createAccelerationStructureData(
932  physicalDevice, device, commandBuffer, { std::make_pair( bottomLevelAS.accelerationStructure, transform ) }, std::vector<vk::GeometryNV>() );
933  } );
934 
935  // create raytracing descriptor set
937  device,
938  perFrameData[0].commandPool,
939  graphicsQueue,
940  [&]( vk::CommandBuffer const & commandBuffer )
941  {
942  vk::BufferMemoryBarrier bufferMemoryBarrier(
944  commandBuffer.pipelineBarrier(
946 
947  bufferMemoryBarrier.buffer = indexBufferData.buffer;
948  commandBuffer.pipelineBarrier(
950  } );
951 
952  std::vector<vk::DescriptorSetLayoutBinding> bindings;
954  bindings.emplace_back( 1, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eRaygenNV ); // raytracing output
955  bindings.emplace_back( 2, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eRaygenNV ); // camera information
956  bindings.emplace_back( 3, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eClosestHitNV ); // vertex buffer
957  bindings.emplace_back( 4, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eClosestHitNV ); // index buffer
958  bindings.emplace_back( 5, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eClosestHitNV ); // material buffer
959  bindings.emplace_back( 6,
961  vk::su::checked_cast<uint32_t>( textures.size() ),
963 
964  std::vector<vk::DescriptorPoolSize> descriptorPoolSizes;
965  descriptorPoolSizes.reserve( bindings.size() );
966  for ( const auto & b : bindings )
967  {
968  descriptorPoolSizes.emplace_back( b.descriptorType, vk::su::checked_cast<uint32_t>( swapChainData.images.size() ) * b.descriptorCount );
969  }
970  vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo(
971  vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, vk::su::checked_cast<uint32_t>( swapChainData.images.size() ), descriptorPoolSizes );
972  vk::DescriptorPool rayTracingDescriptorPool = device.createDescriptorPool( descriptorPoolCreateInfo );
973  vk::DescriptorSetLayout rayTracingDescriptorSetLayout = device.createDescriptorSetLayout( vk::DescriptorSetLayoutCreateInfo( {}, bindings ) );
974  std::vector<vk::DescriptorSetLayout> layouts;
975  for ( size_t i = 0; i < swapChainData.images.size(); i++ )
976  {
977  layouts.push_back( rayTracingDescriptorSetLayout );
978  }
979  descriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo( rayTracingDescriptorPool, layouts );
980  std::vector<vk::DescriptorSet> rayTracingDescriptorSets = device.allocateDescriptorSets( descriptorSetAllocateInfo );
981 
982  // Bind ray tracing specific descriptor sets into pNext of a vk::WriteDescriptorSet
983  vk::WriteDescriptorSetAccelerationStructureNV writeDescriptorSetAcceleration( 1, &topLevelAS.accelerationStructure );
984  std::vector<vk::WriteDescriptorSet> accelerationDescriptionSets;
985  for ( size_t i = 0; i < rayTracingDescriptorSets.size(); i++ )
986  {
987  accelerationDescriptionSets.emplace_back(
988  rayTracingDescriptorSets[i], 0, 0, 1, bindings[0].descriptorType, nullptr, nullptr, nullptr, &writeDescriptorSetAcceleration );
989  }
990  device.updateDescriptorSets( accelerationDescriptionSets, nullptr );
991 
992  // Bind all the other buffers and images, starting with dstBinding == 2 (dstBinding == 1 is used by the backBuffer
993  // view)
994  for ( size_t i = 0; i < rayTracingDescriptorSets.size(); i++ )
995  {
997  rayTracingDescriptorSets[i],
998  { { bindings[2].descriptorType, uniformBufferData.buffer, VK_WHOLE_SIZE, {} },
999  { bindings[3].descriptorType, vertexBufferData.buffer, VK_WHOLE_SIZE, {} },
1000  { bindings[4].descriptorType, indexBufferData.buffer, VK_WHOLE_SIZE, {} },
1001  { bindings[5].descriptorType, materialBufferData.buffer, VK_WHOLE_SIZE, {} } },
1002  textures,
1003  2 );
1004  }
1005 
1006  // create the ray-tracing shader modules
1007  glslang::InitializeProcess();
1008  vk::ShaderModule raygenShaderModule = vk::su::createShaderModule( device, vk::ShaderStageFlagBits::eRaygenNV, raygenShaderText );
1009  vk::ShaderModule missShaderModule = vk::su::createShaderModule( device, vk::ShaderStageFlagBits::eMissNV, missShaderText );
1010  vk::ShaderModule shadowMissShaderModule = vk::su::createShaderModule( device, vk::ShaderStageFlagBits::eMissNV, shadowMissShaderText );
1011  vk::ShaderModule closestHitShaderModule = vk::su::createShaderModule( device, vk::ShaderStageFlagBits::eClosestHitNV, closestHitShaderText );
1012  glslang::FinalizeProcess();
1013 
1014  // create the ray tracing pipeline
1015  std::vector<vk::PipelineShaderStageCreateInfo> shaderStages;
1016  std::vector<vk::RayTracingShaderGroupCreateInfoNV> shaderGroups;
1017 
1018  // We use only one ray generation, that will implement the camera model
1019  shaderStages.emplace_back( vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eRaygenNV, raygenShaderModule, "main" );
1020  shaderGroups.emplace_back( vk::RayTracingShaderGroupTypeNV::eGeneral, 0, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV );
1021 
1022  // The first miss shader is used to look-up the environment in case the rays from the camera miss the geometry
1023  shaderStages.emplace_back( vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eMissNV, missShaderModule, "main" );
1024  shaderGroups.emplace_back( vk::RayTracingShaderGroupTypeNV::eGeneral, 1, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV );
1025 
1026  // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion
1027  // has been found
1028  shaderStages.emplace_back( vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eMissNV, shadowMissShaderModule, "main" );
1029  shaderGroups.emplace_back( vk::RayTracingShaderGroupTypeNV::eGeneral, 2, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV );
1030 
1031  // The first hit group defines the shaders invoked when a ray shot from the camera hit the geometry. In this case we
1032  // only specify the closest hit shader, and rely on the build-in triangle intersection and pass-through any-hit
1033  // shader. However, explicit intersection and any hit shaders could be added as well.
1034  shaderStages.emplace_back( vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eClosestHitNV, closestHitShaderModule, "main" );
1035  shaderGroups.emplace_back( vk::RayTracingShaderGroupTypeNV::eTrianglesHitGroup, VK_SHADER_UNUSED_NV, 3, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV );
1036 
1037  // The second hit group defines the shaders invoked when a shadow ray hits the geometry. For simple shadows we do
1038  // not need any shader in that group: we will rely on initializing the payload and update it only in the miss shader
1039  shaderGroups.emplace_back(
1040  vk::RayTracingShaderGroupTypeNV::eTrianglesHitGroup, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV, VK_SHADER_UNUSED_NV );
1041 
1042  // Create the layout of the pipeline following the provided descriptor set layout
1043  vk::PipelineLayout rayTracingPipelineLayout = device.createPipelineLayout( vk::PipelineLayoutCreateInfo( {}, rayTracingDescriptorSetLayout ) );
1044 
1045  // Assemble the shader stages and recursion depth info into the raytracing pipeline
1046  // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
1047  // hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
1048  // as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
1049  // in the ray generation to avoid deep recursion.
1050  uint32_t maxRecursionDepth = 2;
1051  vk::RayTracingPipelineCreateInfoNV rayTracingPipelineCreateInfo( {}, shaderStages, shaderGroups, maxRecursionDepth, rayTracingPipelineLayout );
1052  vk::Pipeline rayTracingPipeline;
1053  vk::ResultValue<vk::Pipeline> rvPipeline = device.createRayTracingPipelineNV( nullptr, rayTracingPipelineCreateInfo );
1054  switch ( rvPipeline.result )
1055  {
1056  case vk::Result::eSuccess: rayTracingPipeline = rvPipeline.value; break;
1058  // something meaningfull here
1059  break;
1060  default: assert( false ); // should never happen
1061  }
1062 
1065  uint32_t shaderGroupBaseAlignment = propertiesChain.get<vk::PhysicalDeviceRayTracingPropertiesNV>().shaderGroupBaseAlignment;
1066  uint32_t shaderGroupHandleSize = propertiesChain.get<vk::PhysicalDeviceRayTracingPropertiesNV>().shaderGroupHandleSize;
1067 
1068  uint32_t raygenShaderBindingOffset = 0; // starting with raygen
1069  uint32_t raygenShaderTableSize = shaderGroupHandleSize; // one raygen shader
1070  uint32_t missShaderBindingOffset = raygenShaderBindingOffset + roundUp( raygenShaderTableSize, shaderGroupBaseAlignment );
1071  uint32_t missShaderBindingStride = shaderGroupHandleSize;
1072  uint32_t missShaderTableSize = 2 * missShaderBindingStride; // two raygen shaders
1073  uint32_t hitShaderBindingOffset = missShaderBindingOffset + roundUp( missShaderTableSize, shaderGroupBaseAlignment );
1074  uint32_t hitShaderBindingStride = shaderGroupHandleSize;
1075  uint32_t hitShaderTableSize = 2 * hitShaderBindingStride; // two hit shaders
1076 
1077  uint32_t shaderBindingTableSize = hitShaderBindingOffset + hitShaderTableSize;
1078  std::vector<uint8_t> shaderHandleStorage( shaderBindingTableSize );
1079  (void)device.getRayTracingShaderGroupHandlesNV( rayTracingPipeline, 0, 1, raygenShaderTableSize, &shaderHandleStorage[raygenShaderBindingOffset] );
1080  (void)device.getRayTracingShaderGroupHandlesNV( rayTracingPipeline, 1, 2, missShaderTableSize, &shaderHandleStorage[missShaderBindingOffset] );
1081  (void)device.getRayTracingShaderGroupHandlesNV( rayTracingPipeline, 3, 2, hitShaderTableSize, &shaderHandleStorage[hitShaderBindingOffset] );
1082 
1083  vk::su::BufferData shaderBindingTableBufferData(
1084  physicalDevice, device, shaderBindingTableSize, vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eHostVisible );
1085  shaderBindingTableBufferData.upload( device, shaderHandleStorage );
1086 
1087  std::array<vk::ClearValue, 2> clearValues;
1088  clearValues[0].color = vk::ClearColorValue( 0.2f, 0.2f, 0.2f, 0.2f );
1089  clearValues[1].depthStencil = vk::ClearDepthStencilValue( 1.0f, 0 );
1090 
1091  // Main loop
1092  uint32_t frameIndex = 0;
1093  UniformBufferObject uniformBufferObject;
1094  uniformBufferObject.model = glm::mat4( 1 );
1095  uniformBufferObject.modelIT = glm::inverseTranspose( uniformBufferObject.model );
1096 
1097  double accumulatedTime{ 0.0 };
1098  size_t frameCount{ 0 };
1099  while ( !glfwWindowShouldClose( window ) )
1100  {
1101  double startTime = glfwGetTime();
1102  glfwPollEvents();
1103 
1104  int w, h;
1105  glfwGetWindowSize( window, &w, &h );
1106  if ( ( w != static_cast<int>( windowExtent.width ) ) || ( h != static_cast<int>( windowExtent.height ) ) )
1107  {
1108  windowExtent.width = w;
1109  windowExtent.height = h;
1110  device.waitIdle();
1111  swapChainData = vk::su::SwapChainData( physicalDevice,
1112  device,
1113  surface,
1114  windowExtent,
1116  swapChainData.swapChain,
1117  graphicsAndPresentQueueFamilyIndex.first,
1118  graphicsAndPresentQueueFamilyIndex.second );
1119  depthBufferData = vk::su::DepthBufferData( physicalDevice, device, vk::su::pickDepthFormat( physicalDevice ), windowExtent );
1120 
1122  device,
1123  perFrameData[frameIndex].commandPool,
1124  graphicsQueue,
1125  [&]( vk::CommandBuffer const & commandBuffer )
1126  {
1128  commandBuffer, depthBufferData.image, depthFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal );
1129  } );
1130 
1131  framebuffers = vk::su::createFramebuffers( device, renderPass, swapChainData.imageViews, depthBufferData.imageView, windowExtent );
1132  }
1133 
1134  // update the uniformBufferObject
1135  assert( 0 < windowExtent.height );
1136  uniformBufferObject.view = appInfo.cameraManipulator.getMatrix();
1137  uniformBufferObject.proj = glm::perspective( glm::radians( 65.0f ), windowExtent.width / static_cast<float>( windowExtent.height ), 0.1f, 1000.0f );
1138  uniformBufferObject.proj[1][1] *= -1; // Inverting Y for Vulkan
1139  uniformBufferObject.viewInverse = glm::inverse( uniformBufferObject.view );
1140  uniformBufferObject.projInverse = glm::inverse( uniformBufferObject.proj );
1141  uniformBufferData.upload( device, uniformBufferObject );
1142 
1143  // frame begin
1145  device.acquireNextImageKHR( swapChainData.swapChain, UINT64_MAX, perFrameData[frameIndex].presentCompleteSemaphore, nullptr );
1146  assert( rv.result == vk::Result::eSuccess );
1147  uint32_t backBufferIndex = rv.value;
1148 
1149  while ( vk::Result::eTimeout == device.waitForFences( perFrameData[frameIndex].fence, VK_TRUE, vk::su::FenceTimeout ) )
1150  ;
1151  device.resetFences( perFrameData[frameIndex].fence );
1152 
1153  // reset the command buffer by resetting the complete command pool of this frame
1154  device.resetCommandPool( perFrameData[frameIndex].commandPool );
1155 
1156  vk::CommandBuffer const & commandBuffer = perFrameData[frameIndex].commandBuffer;
1157 
1159 
1160  if ( appInfo.useRasterRender )
1161  {
1162  commandBuffer.beginRenderPass(
1163  vk::RenderPassBeginInfo( renderPass, framebuffers[backBufferIndex], vk::Rect2D( vk::Offset2D( 0, 0 ), windowExtent ), clearValues ),
1165 
1166  commandBuffer.bindPipeline( vk::PipelineBindPoint::eGraphics, graphicsPipeline );
1167  commandBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr );
1168 
1169  commandBuffer.setViewport(
1170  0, vk::Viewport( 0.0f, 0.0f, static_cast<float>( windowExtent.width ), static_cast<float>( windowExtent.height ), 0.0f, 1.0f ) );
1171  commandBuffer.setScissor( 0, vk::Rect2D( vk::Offset2D( 0, 0 ), windowExtent ) );
1172 
1173  commandBuffer.bindVertexBuffers( 0, vertexBufferData.buffer, { 0 } );
1174  commandBuffer.bindIndexBuffer( indexBufferData.buffer, 0, vk::IndexType::eUint32 );
1175  commandBuffer.drawIndexed( vk::su::checked_cast<uint32_t>( indices.size() ), 1, 0, 0, 0 );
1176 
1177  commandBuffer.endRenderPass();
1178  }
1179  else
1180  {
1181  vk::DescriptorImageInfo imageInfo( nullptr, swapChainData.imageViews[backBufferIndex], vk::ImageLayout::eGeneral );
1182  vk::WriteDescriptorSet writeDescriptorSet( rayTracingDescriptorSets[backBufferIndex], 1, 0, bindings[1].descriptorType, imageInfo );
1183  device.updateDescriptorSets( writeDescriptorSet, nullptr );
1184 
1186  commandBuffer, swapChainData.images[backBufferIndex], surfaceFormat.format, vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral );
1187 
1188  commandBuffer.bindPipeline( vk::PipelineBindPoint::eRayTracingNV, rayTracingPipeline );
1189 
1190  commandBuffer.bindDescriptorSets(
1191  vk::PipelineBindPoint::eRayTracingNV, rayTracingPipelineLayout, 0, rayTracingDescriptorSets[backBufferIndex], nullptr );
1192 
1193  commandBuffer.traceRaysNV( shaderBindingTableBufferData.buffer,
1194  raygenShaderBindingOffset,
1195  shaderBindingTableBufferData.buffer,
1196  missShaderBindingOffset,
1197  missShaderBindingStride,
1198  shaderBindingTableBufferData.buffer,
1199  hitShaderBindingOffset,
1200  hitShaderBindingStride,
1201  nullptr,
1202  0,
1203  0,
1204  windowExtent.width,
1205  windowExtent.height,
1206  1 );
1207 
1209  commandBuffer, swapChainData.images[backBufferIndex], surfaceFormat.format, vk::ImageLayout::eGeneral, vk::ImageLayout::ePresentSrcKHR );
1210  }
1211 
1212  // frame end
1213  commandBuffer.end();
1215  graphicsQueue.submit( vk::SubmitInfo( 1,
1216  &( perFrameData[frameIndex].presentCompleteSemaphore ),
1217  &waitDstStageMask,
1218  1,
1219  &commandBuffer,
1220  1,
1221  &( perFrameData[frameIndex].renderCompleteSemaphore ) ),
1222  perFrameData[frameIndex].fence );
1223  vk::Result result =
1224  presentQueue.presentKHR( vk::PresentInfoKHR( perFrameData[frameIndex].renderCompleteSemaphore, swapChainData.swapChain, backBufferIndex ) );
1225  switch ( result )
1226  {
1227  case vk::Result::eSuccess: break;
1228  case vk::Result::eSuboptimalKHR: std::cout << "vk::Queue::presentKHR returned vk::Result::eSuboptimalKHR !\n"; break;
1229  default: assert( false ); // an unexpected result is returned !
1230  }
1231  frameIndex = ( frameIndex + 1 ) % IMGUI_VK_QUEUED_FRAMES;
1232 
1233  double endTime = glfwGetTime();
1234  accumulatedTime += endTime - startTime;
1235  ++frameCount;
1236  if ( 1.0 < accumulatedTime )
1237  {
1238  assert( 0 < frameCount );
1239 
1240  std::ostringstream oss;
1241  oss << AppName << ": " << vertices.size() << " Vertices " << ( appInfo.useRasterRender ? "Rastering" : "RayTracing" ) << " ( "
1242  << frameCount / accumulatedTime << " fps)";
1243  glfwSetWindowTitle( window, oss.str().c_str() );
1244 
1245  accumulatedTime = 0.0;
1246  frameCount = 0;
1247  }
1248  }
1249 
1250  // Cleanup
1251  device.waitIdle();
1252 
1253  shaderBindingTableBufferData.clear( device );
1254  device.destroyPipeline( rayTracingPipeline );
1255  device.destroyPipelineLayout( rayTracingPipelineLayout );
1256  device.destroyShaderModule( closestHitShaderModule );
1257  device.destroyShaderModule( shadowMissShaderModule );
1258  device.destroyShaderModule( missShaderModule );
1259  device.destroyShaderModule( raygenShaderModule );
1260  device.freeDescriptorSets( rayTracingDescriptorPool, rayTracingDescriptorSets );
1261  device.destroyDescriptorSetLayout( rayTracingDescriptorSetLayout );
1262  device.destroyDescriptorPool( rayTracingDescriptorPool );
1263  topLevelAS.clear( device );
1264  bottomLevelAS.clear( device );
1265  device.freeDescriptorSets( descriptorPool, descriptorSet );
1266  uniformBufferData.clear( device );
1267  device.destroyPipeline( graphicsPipeline );
1268  device.destroyShaderModule( fragmentShaderModule );
1269  device.destroyShaderModule( vertexShaderModule );
1270  device.destroyPipelineLayout( pipelineLayout );
1271  device.destroyDescriptorSetLayout( descriptorSetLayout );
1272  indexBufferData.clear( device );
1273  vertexBufferData.clear( device );
1274  materialBufferData.clear( device );
1275  for ( auto & texture : textures )
1276  {
1277  texture.clear( device );
1278  }
1279  for ( auto framebuffer : framebuffers )
1280  {
1281  device.destroyFramebuffer( framebuffer );
1282  }
1283  depthBufferData.clear( device );
1284  device.destroyRenderPass( renderPass );
1285  swapChainData.clear( device );
1286  device.destroyDescriptorPool( descriptorPool );
1287  for ( int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++ )
1288  {
1289  perFrameData[i].clear( device );
1290  }
1291  device.destroy();
1292  instance.destroySurfaceKHR( surface );
1293 #if !defined( NDEBUG )
1294  instance.destroyDebugUtilsMessengerEXT( debugUtilsMessenger );
1295 #endif
1296  instance.destroy();
1297 
1298  glfwDestroyWindow( window );
1299  glfwTerminate();
1300  }
1301  catch ( vk::SystemError & err )
1302  {
1303  std::cout << "vk::SystemError: " << err.what() << std::endl;
1304  exit( -1 );
1305  }
1306  catch ( std::exception & err )
1307  {
1308  std::cout << "std::exception: " << err.what() << std::endl;
1309  exit( -1 );
1310  }
1311  catch ( ... )
1312  {
1313  std::cout << "unknown error\n";
1314  exit( -1 );
1315  }
1316  return 0;
1317 }
const std::string vertexShaderText
const std::string fragmentShaderText
glm::vec3 randomVec3(float minValue, float maxValue)
Definition: RayTracing.cpp:636
#define IMGUI_VK_QUEUED_FRAMES
Definition: RayTracing.cpp:530
int main(int, char **)
Definition: RayTracing.cpp:648
AccelerationStructureData createAccelerationStructureData(vk::PhysicalDevice const &physicalDevice, vk::Device const &device, vk::CommandBuffer const &commandBuffer, std::vector< std::pair< vk::AccelerationStructureNV, glm::mat4x4 >> const &instances, std::vector< vk::GeometryNV > const &geometries)
Definition: RayTracing.cpp:101
T random(T minValue=std::numeric_limits< T >::min(), T maxValue=std::numeric_limits< T >::max())
Definition: RayTracing.cpp:628
const size_t VertexStride
Definition: RayTracing.cpp:230
uint32_t roundUp(uint32_t value, uint32_t alignment)
Definition: RayTracing.cpp:643
const size_t MaterialStride
Definition: RayTracing.cpp:218
void cout(vk::SurfaceCapabilitiesKHR const &surfaceCapabilities)
void traceRaysNV(vk::Buffer raygenShaderBindingTableBuffer, vk::DeviceSize raygenShaderBindingOffset, vk::Buffer missShaderBindingTableBuffer, vk::DeviceSize missShaderBindingOffset, vk::DeviceSize missShaderBindingStride, vk::Buffer hitShaderBindingTableBuffer, vk::DeviceSize hitShaderBindingOffset, vk::DeviceSize hitShaderBindingStride, vk::Buffer callableShaderBindingTableBuffer, vk::DeviceSize callableShaderBindingOffset, vk::DeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS ResultValueType< void >::type end(Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const
void bindDescriptorSets(vk::PipelineBindPoint pipelineBindPoint, vk::PipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const vk::DescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void buildAccelerationStructureNV(const vk::AccelerationStructureInfoNV *pInfo, vk::Buffer instanceData, vk::DeviceSize instanceOffset, vk::Bool32 update, vk::AccelerationStructureNV dst, vk::AccelerationStructureNV src, vk::Buffer scratch, vk::DeviceSize scratchOffset, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void beginRenderPass(const vk::RenderPassBeginInfo *pRenderPassBegin, vk::SubpassContents contents, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void setScissor(uint32_t firstScissor, uint32_t scissorCount, const vk::Rect2D *pScissors, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result begin(const vk::CommandBufferBeginInfo *pBeginInfo, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void bindIndexBuffer(vk::Buffer buffer, vk::DeviceSize offset, vk::IndexType indexType, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, const vk::Buffer *pBuffers, const vk::DeviceSize *pOffsets, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void bindPipeline(vk::PipelineBindPoint pipelineBindPoint, vk::Pipeline pipeline, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void endRenderPass(Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void setViewport(uint32_t firstViewport, uint32_t viewportCount, const vk::Viewport *pViewports, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void pipelineBarrier(vk::PipelineStageFlags srcStageMask, vk::PipelineStageFlags dstStageMask, vk::DependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const vk::MemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const vk::BufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const vk::ImageMemoryBarrier *pImageMemoryBarriers, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void destroyAccelerationStructureNV(vk::AccelerationStructureNV accelerationStructure, const vk::AllocationCallbacks *pAllocator, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void destroySemaphore(vk::Semaphore semaphore, const vk::AllocationCallbacks *pAllocator, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void getAccelerationStructureMemoryRequirementsNV(const vk::AccelerationStructureMemoryRequirementsInfoNV *pInfo, vk::MemoryRequirements2KHR *pMemoryRequirements, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void freeCommandBuffers(vk::CommandPool commandPool, uint32_t commandBufferCount, const vk::CommandBuffer *pCommandBuffers, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result createAccelerationStructureNV(const vk::AccelerationStructureCreateInfoNV *pCreateInfo, const vk::AllocationCallbacks *pAllocator, vk::AccelerationStructureNV *pAccelerationStructure, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void destroyCommandPool(vk::CommandPool commandPool, const vk::AllocationCallbacks *pAllocator, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result getAccelerationStructureHandleNV(vk::AccelerationStructureNV accelerationStructure, size_t dataSize, void *pData, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void destroyFence(vk::Fence fence, const vk::AllocationCallbacks *pAllocator, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result bindAccelerationStructureMemoryNV(uint32_t bindInfoCount, const vk::BindAccelerationStructureMemoryInfoNV *pBindInfos, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result createDebugUtilsMessengerEXT(const vk::DebugUtilsMessengerCreateInfoEXT *pCreateInfo, const vk::AllocationCallbacks *pAllocator, vk::DebugUtilsMessengerEXT *pMessenger, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void destroy(const vk::AllocationCallbacks *pAllocator, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result enumeratePhysicalDevices(uint32_t *pPhysicalDeviceCount, vk::PhysicalDevice *pPhysicalDevices, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void destroySurfaceKHR(vk::SurfaceKHR surface, const vk::AllocationCallbacks *pAllocator, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void destroyDebugUtilsMessengerEXT(vk::DebugUtilsMessengerEXT messenger, const vk::AllocationCallbacks *pAllocator, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result getSurfaceFormatsKHR(vk::SurfaceKHR surface, uint32_t *pSurfaceFormatCount, vk::SurfaceFormatKHR *pSurfaceFormats, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void getProperties2(vk::PhysicalDeviceProperties2 *pProperties, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
void getFeatures2(vk::PhysicalDeviceFeatures2 *pFeatures, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result presentKHR(const vk::PresentInfoKHR *pPresentInfo, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
VULKAN_HPP_NODISCARD Result submit(uint32_t submitCount, const vk::SubmitInfo *pSubmits, vk::Fence fence, Dispatch const &d VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) const VULKAN_HPP_NOEXCEPT
T & get() VULKAN_HPP_NOEXCEPT
Definition: vulkan.hpp:699
virtual const char * what() const VULKAN_HPP_NOEXCEPT
Definition: vulkan.hpp:6206
Action mouseMove(glm::ivec2 const &position, MouseButton mouseButton, ModifierFlags &modifiers)
void setMousePosition(glm::ivec2 const &position)
glm::mat4 const & getMatrix() const
void setLookat(const glm::vec3 &cameraPosition, const glm::vec3 &centerPosition, const glm::vec3 &upVector)
void setWindowSize(glm::ivec2 const &size)
std::vector< vk::Framebuffer > createFramebuffers(vk::Device const &device, vk::RenderPass &renderPass, std::vector< vk::ImageView > const &imageViews, vk::ImageView const &depthImageView, vk::Extent2D const &extent)
Definition: utils.cpp:111
vk::DebugUtilsMessengerCreateInfoEXT makeDebugUtilsMessengerCreateInfoEXT()
Definition: utils.cpp:1025
vk::ShaderModule createShaderModule(vk::Device const &device, vk::ShaderStageFlagBits shaderStage, std::string const &shaderText)
Definition: shaders.cpp:88
vk::RenderPass createRenderPass(vk::Device const &device, vk::Format colorFormat, vk::Format depthFormat, vk::AttachmentLoadOp loadOp, vk::ImageLayout colorFinalLayout)
Definition: utils.cpp:314
vk::Pipeline createGraphicsPipeline(vk::Device const &device, vk::PipelineCache const &pipelineCache, std::pair< vk::ShaderModule, vk::SpecializationInfo const * > const &vertexShaderData, std::pair< vk::ShaderModule, vk::SpecializationInfo const * > const &fragmentShaderData, uint32_t vertexStride, std::vector< std::pair< vk::Format, uint32_t >> const &vertexInputAttributeFormatOffset, vk::FrontFace frontFace, bool depthBuffered, vk::PipelineLayout const &pipelineLayout, vk::RenderPass const &renderPass)
Definition: utils.cpp:133
void setImageLayout(vk::CommandBuffer const &commandBuffer, vk::Image image, vk::Format format, vk::ImageLayout oldImageLayout, vk::ImageLayout newImageLayout)
Definition: utils.cpp:574
vk::Instance createInstance(std::string const &appName, std::string const &engineName, std::vector< std::string > const &layers, std::vector< std::string > const &extensions, uint32_t apiVersion)
Definition: utils.cpp:279
const uint64_t FenceTimeout
Definition: utils.hpp:31
vk::Device createDevice(vk::PhysicalDevice const &physicalDevice, uint32_t queueFamilyIndex, std::vector< std::string > const &extensions, vk::PhysicalDeviceFeatures const *physicalDeviceFeatures, void const *pNext)
Definition: utils.cpp:86
void oneTimeSubmit(vk::Device const &device, vk::CommandPool const &commandPool, vk::Queue const &queue, Func const &func)
Definition: utils.hpp:34
vk::DescriptorSetLayout createDescriptorSetLayout(vk::Device const &device, std::vector< std::tuple< vk::DescriptorType, uint32_t, vk::ShaderStageFlags >> const &bindingData, vk::DescriptorSetLayoutCreateFlags flags)
Definition: utils.cpp:73
std::pair< uint32_t, uint32_t > findGraphicsAndPresentQueueFamilyIndex(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR const &surface)
Definition: utils.cpp:420
void updateDescriptorSets(vk::Device const &device, vk::DescriptorSet const &descriptorSet, std::vector< std::tuple< vk::DescriptorType, vk::Buffer const &, vk::DeviceSize, vk::BufferView const & >> const &bufferData, vk::su::TextureData const &textureData, uint32_t bindingOffset)
Definition: utils.cpp:660
vk::DescriptorPool createDescriptorPool(vk::Device const &device, std::vector< vk::DescriptorPoolSize > const &poolSizes)
Definition: utils.cpp:62
vk::Format pickDepthFormat(vk::PhysicalDevice const &physicalDevice)
Definition: utils.cpp:505
vk::SurfaceFormatKHR pickSurfaceFormat(std::vector< vk::SurfaceFormatKHR > const &formats)
Definition: utils.cpp:539
AccelerationStructureTypeKHR
@ eDepthStencilAttachmentOptimal
VULKAN_HPP_INLINE std::string to_string(FormatFeatureFlags value)
Flags< FormatFeatureFlagBits > FormatFeatureFlags
uint64_t DeviceSize
Definition: vulkan.hpp:6122
@ ePipelineCompileRequiredEXT
std::unique_ptr< vk::su::BufferData > resultBufferData
Definition: RayTracing.cpp:97
void clear(vk::Device device)
Definition: RayTracing.cpp:78
vk::AccelerationStructureNV accelerationStructure
Definition: RayTracing.cpp:95
std::unique_ptr< vk::su::BufferData > instanceBufferData
Definition: RayTracing.cpp:98
std::unique_ptr< vk::su::BufferData > scratchBufferData
Definition: RayTracing.cpp:96
vk::su::CameraManipulator cameraManipulator
Definition: RayTracing.cpp:535
bool useRasterRender
Definition: RayTracing.cpp:536
uint64_t accelerationStructureHandle
Definition: RayTracing.cpp:71
GeometryInstanceData(glm::mat4x4 const &transform_, uint32_t instanceID_, uint8_t mask_, uint32_t instanceOffset_, uint8_t flags_, uint64_t accelerationStructureHandle_)
Definition: RayTracing.cpp:58
glm::vec3 diffuse
Definition: RayTracing.cpp:214
int textureID
Definition: RayTracing.cpp:215
vk::Semaphore renderCompleteSemaphore
Definition: RayTracing.cpp:199
vk::CommandBuffer commandBuffer
Definition: RayTracing.cpp:196
vk::Fence fence
Definition: RayTracing.cpp:197
vk::Semaphore presentCompleteSemaphore
Definition: RayTracing.cpp:198
vk::CommandPool commandPool
Definition: RayTracing.cpp:195
void clear(vk::Device device)
Definition: RayTracing.cpp:186
glm::vec2 texCoord
Definition: RayTracing.cpp:226
glm::vec3 pos
Definition: RayTracing.cpp:224
Vertex(glm::vec3 const &p, glm::vec3 const &n, glm::vec2 const &tc, int m=0)
Definition: RayTracing.cpp:222
int matID
Definition: RayTracing.cpp:227
glm::vec3 nrm
Definition: RayTracing.cpp:225
vk::PhysicalDeviceFeatures features
void clear(vk::Device const &device)
Definition: utils.hpp:102
void upload(vk::Device const &device, DataType const &data) const
Definition: utils.hpp:109
vk::Buffer buffer
Definition: utils.hpp:159
vk::ImageView imageView
Definition: utils.hpp:191
void clear(vk::Device const &device)
Definition: utils.hpp:181
vk::Image image
Definition: utils.hpp:189
vk::SwapchainKHR swapChain
Definition: utils.hpp:231
std::vector< vk::ImageView > imageViews
Definition: utils.hpp:233
void clear(vk::Device const &device)
Definition: utils.hpp:219
std::vector< vk::Image > images
Definition: utils.hpp:232
uint64_t VkSurfaceKHR
Definition: vulkan_core.h:7513
#define VK_TRUE
Definition: vulkan_core.h:131
#define VK_NV_RAY_TRACING_EXTENSION_NAME
struct VkInstance_T * VkInstance
Definition: vulkan_core.h:101
#define VK_SHADER_UNUSED_NV
#define VK_WHOLE_SIZE
Definition: vulkan_core.h:132
#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
Definition: vulkan_core.h:8848
VkResult
Definition: vulkan_core.h:140
#define VK_QUEUE_FAMILY_IGNORED
Definition: vulkan_core.h:127