diff --git a/README.md b/README.md
index 9acb336d..cc78f441 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ A comprehensive collection of open source C++ examples for [VulkanĀ®](https://ww
+ [Compute Shader](#ComputeShader)
+ [Geometry Shader](#GeometryShader)
+ [Tessellation Shader](#TessellationShader)
+ + [Ray tracing](#Raytracing)
+ [Headless](#Headless)
+ [User Interface](#UserInterface)
+ [Effects](#Effects)
@@ -287,6 +288,20 @@ Renders a terrain using tessellation shaders for height displacement (based on a
Uses curved PN-triangles ([paper](http://alex.vlachos.com/graphics/CurvedPNTriangles.pdf)) for adding details to a low-polygon model.
+### Ray Tracing (VK_KHR_ray_tracing)
+
+#### [01 - Basic ray tracing](examples/raytracingbasic)
+
+Basic example for doing hardware accelerated ray tracing using the ```VK_KHR_ray_tracing``` extension. Shows how to setup acceleration structures, ray tracing pipelines and the shaders needed to do the actual ray tracing.
+
+#### [02 - Ray traced shadows](examples/raytracingshadows)
+
+Adds ray traced shadows casting using the new ray tracing extensions to a more complex scene. Shows how to add multiple hit and miss shaders and how to modify existing shaders to add shadow calculations.
+
+#### [03 - Ray traced reflections](examples/raytracingreflections)
+
+Renders a complex scene with reflective surfaces using the new ray tracing extensions. Shows how to do recursion inside of the ray tracing shaders for implementing real time reflections.
+
### Headless
Examples that run one-time tasks and don't make use of visual output (no window system integration). These can be run in environments where no user interface is available ([blog entry](https://www.saschawillems.de/tutorials/vulkan/headless_examples)).
@@ -363,18 +378,6 @@ An updated version using ```VK_EXT_debug_utils``` along with an in-depth tutoria
Shows how to render a scene using a negative viewport height, making the Vulkan render setup more similar to other APIs like OpenGL. Also has several options for changing relevant pipeline state, and displaying meshes with OpenGL or Vulkan style coordinates. Details can be found in [this tutorial](https://www.saschawillems.de/tutorials/vulkan/flipping-viewport).
-#### [08 - Basic ray tracing with VK_NV_ray_tracing](examples/nv_ray_tracing_basic)
-
-Basic example for doing ray tracing using the new Nvidia RTX extensions. Shows how to setup acceleration structures, ray tracing pipelines and the shaders needed to do the actual ray tracing.
-
-#### [09 - Ray traced shadows with VK_NV_ray_tracing](examples/nv_ray_tracing_shadows)
-
-Adds ray traced shadows casting using the new Nvidia RTX extensions to a more complex scene. Shows how to add multiple hit and miss shaders and how to modify existing shaders to add shadow calculations.
-
-#### [10 - Ray traced reflections with VK_NV_ray_tracing](examples/nv_ray_tracing_reflections)
-
-Renders a complex scene with reflective surfaces using the new Nvidia RTX extensions. Shows how to do recursion inside of the ray tracing shaders for implementing real time reflections.
-
### Misc
#### [01 - Vulkan Gears](examples/gears/)
diff --git a/android/examples/base/CMakeLists.txt b/android/examples/base/CMakeLists.txt
index 319a4911..e2dc6c42 100644
--- a/android/examples/base/CMakeLists.txt
+++ b/android/examples/base/CMakeLists.txt
@@ -3,6 +3,7 @@ file(GLOB BASE_SRC "../../../base/*.cpp" "../../../external/imgui/*.cpp")
add_library(libbase SHARED ${BASE_SRC})
include_directories(${BASE_DIR})
+include_directories(../../../external)
include_directories(../../../external/glm)
include_directories(../../../external/gli)
include_directories(../../../external/imgui)
diff --git a/android/examples/base/liblibktx.a b/android/examples/base/liblibktx.a
new file mode 100644
index 00000000..fa1df34b
Binary files /dev/null and b/android/examples/base/liblibktx.a differ
diff --git a/android/examples/raytracingbasic/CMakeLists.txt b/android/examples/raytracingbasic/CMakeLists.txt
new file mode 100644
index 00000000..b54ee8ce
--- /dev/null
+++ b/android/examples/raytracingbasic/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
+
+set(NAME raytracingbasic)
+
+set(SRC_DIR ../../../examples/${NAME})
+set(BASE_DIR ../../../base)
+set(EXTERNAL_DIR ../../../external)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DVK_USE_PLATFORM_ANDROID_KHR -DVK_NO_PROTOTYPES")
+
+file(GLOB EXAMPLE_SRC "${SRC_DIR}/*.cpp")
+
+add_library(native-lib SHARED ${EXAMPLE_SRC})
+
+add_library(native-app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
+
+add_subdirectory(../base ${CMAKE_SOURCE_DIR}/../base)
+
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
+
+include_directories(${BASE_DIR})
+include_directories(${EXTERNAL_DIR})
+include_directories(${EXTERNAL_DIR}/glm)
+include_directories(${EXTERNAL_DIR}/imgui)
+include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
+
+target_link_libraries(
+ native-lib
+ native-app-glue
+ libbase
+ android
+ log
+ z
+)
diff --git a/android/examples/raytracingbasic/build.gradle b/android/examples/raytracingbasic/build.gradle
new file mode 100644
index 00000000..f87ab743
--- /dev/null
+++ b/android/examples/raytracingbasic/build.gradle
@@ -0,0 +1,60 @@
+apply plugin: 'com.android.application'
+apply from: '../gradle/outputfilename.gradle'
+
+android {
+ compileSdkVersion 26
+ defaultConfig {
+ applicationId "de.saschawillems.vulkanRaytracingbasic"
+ minSdkVersion 19
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+ ndk {
+ abiFilters "armeabi-v7a"
+ }
+ externalNativeBuild {
+ cmake {
+ cppFlags "-std=c++14"
+ arguments "-DANDROID_STL=c++_shared", '-DANDROID_TOOLCHAIN=clang'
+ }
+ }
+ }
+ sourceSets {
+ main.assets.srcDirs = ['assets']
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ path "CMakeLists.txt"
+ }
+ }
+}
+
+task copyTask {
+ copy {
+ from '../../common/res/drawable'
+ into "src/main/res/drawable"
+ include 'icon.png'
+ }
+
+ copy {
+ from '../../../data/shaders/glsl/base'
+ into 'assets/shaders/glsl/base'
+ include '*.spv'
+ }
+
+ copy {
+ from '../../../data/shaders/glsl/raytracingbasic'
+ into 'assets/shaders/glsl/raytracingbasic'
+ include '*.*'
+ }
+
+
+}
+
+preBuild.dependsOn copyTask
\ No newline at end of file
diff --git a/android/examples/raytracingbasic/src/main/AndroidManifest.xml b/android/examples/raytracingbasic/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..067fafed
--- /dev/null
+++ b/android/examples/raytracingbasic/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/examples/raytracingbasic/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java b/android/examples/raytracingbasic/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java
new file mode 100644
index 00000000..12e14fc6
--- /dev/null
+++ b/android/examples/raytracingbasic/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 by Sascha Willems - www.saschawillems.de
+ *
+ * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+ */
+package de.saschawillems.vulkanSample;
+
+import android.app.AlertDialog;
+import android.app.NativeActivity;
+import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+
+import java.util.concurrent.Semaphore;
+
+public class VulkanActivity extends NativeActivity {
+
+ static {
+ // Load native library
+ System.loadLibrary("native-lib");
+ }
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ // Use a semaphore to create a modal dialog
+
+ private final Semaphore semaphore = new Semaphore(0, true);
+
+ public void showAlert(final String message)
+ {
+ final VulkanActivity activity = this;
+
+ ApplicationInfo applicationInfo = activity.getApplicationInfo();
+ final String applicationName = applicationInfo.nonLocalizedLabel.toString();
+
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity, android.R.style.Theme_Material_Dialog_Alert);
+ builder.setTitle(applicationName);
+ builder.setMessage(message);
+ builder.setPositiveButton("Close", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ semaphore.release();
+ }
+ });
+ builder.setCancelable(false);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+ });
+ try {
+ semaphore.acquire();
+ }
+ catch (InterruptedException e) { }
+ }
+}
diff --git a/android/examples/raytracingreflections/CMakeLists.txt b/android/examples/raytracingreflections/CMakeLists.txt
new file mode 100644
index 00000000..4acffbd2
--- /dev/null
+++ b/android/examples/raytracingreflections/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
+
+set(NAME raytracingreflections)
+
+set(SRC_DIR ../../../examples/${NAME})
+set(BASE_DIR ../../../base)
+set(EXTERNAL_DIR ../../../external)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DVK_USE_PLATFORM_ANDROID_KHR -DVK_NO_PROTOTYPES")
+
+file(GLOB EXAMPLE_SRC "${SRC_DIR}/*.cpp")
+
+add_library(native-lib SHARED ${EXAMPLE_SRC})
+
+add_library(native-app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
+
+add_subdirectory(../base ${CMAKE_SOURCE_DIR}/../base)
+
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
+
+include_directories(${BASE_DIR})
+include_directories(${EXTERNAL_DIR})
+include_directories(${EXTERNAL_DIR}/glm)
+include_directories(${EXTERNAL_DIR}/imgui)
+include_directories(${EXTERNAL_DIR}/tinygltf)
+include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
+
+target_link_libraries(
+ native-lib
+ native-app-glue
+ libbase
+ android
+ log
+ z
+)
diff --git a/android/examples/raytracingreflections/build.gradle b/android/examples/raytracingreflections/build.gradle
new file mode 100644
index 00000000..8959799c
--- /dev/null
+++ b/android/examples/raytracingreflections/build.gradle
@@ -0,0 +1,65 @@
+apply plugin: 'com.android.application'
+apply from: '../gradle/outputfilename.gradle'
+
+android {
+ compileSdkVersion 26
+ defaultConfig {
+ applicationId "de.saschawillems.vulkanRaytracingreflections"
+ minSdkVersion 19
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+ ndk {
+ abiFilters "armeabi-v7a"
+ }
+ externalNativeBuild {
+ cmake {
+ cppFlags "-std=c++14"
+ arguments "-DANDROID_STL=c++_shared", '-DANDROID_TOOLCHAIN=clang'
+ }
+ }
+ }
+ sourceSets {
+ main.assets.srcDirs = ['assets']
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ path "CMakeLists.txt"
+ }
+ }
+}
+
+task copyTask {
+ copy {
+ from '../../common/res/drawable'
+ into "src/main/res/drawable"
+ include 'icon.png'
+ }
+
+ copy {
+ from '../../../data/shaders/glsl/base'
+ into 'assets/shaders/glsl/base'
+ include '*.spv'
+ }
+
+ copy {
+ from '../../../data/shaders/glsl/raytracingbasic'
+ into 'assets/shaders/glsl/raytracingbasic'
+ include '*.*'
+ }
+
+ copy {
+ from '../../../data/models'
+ into 'assets/models'
+ include 'reflection_scene.gltf'
+ }
+
+}
+
+preBuild.dependsOn copyTask
\ No newline at end of file
diff --git a/android/examples/raytracingreflections/src/main/AndroidManifest.xml b/android/examples/raytracingreflections/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..bb637068
--- /dev/null
+++ b/android/examples/raytracingreflections/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/examples/raytracingreflections/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java b/android/examples/raytracingreflections/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java
new file mode 100644
index 00000000..12e14fc6
--- /dev/null
+++ b/android/examples/raytracingreflections/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 by Sascha Willems - www.saschawillems.de
+ *
+ * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+ */
+package de.saschawillems.vulkanSample;
+
+import android.app.AlertDialog;
+import android.app.NativeActivity;
+import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+
+import java.util.concurrent.Semaphore;
+
+public class VulkanActivity extends NativeActivity {
+
+ static {
+ // Load native library
+ System.loadLibrary("native-lib");
+ }
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ // Use a semaphore to create a modal dialog
+
+ private final Semaphore semaphore = new Semaphore(0, true);
+
+ public void showAlert(final String message)
+ {
+ final VulkanActivity activity = this;
+
+ ApplicationInfo applicationInfo = activity.getApplicationInfo();
+ final String applicationName = applicationInfo.nonLocalizedLabel.toString();
+
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity, android.R.style.Theme_Material_Dialog_Alert);
+ builder.setTitle(applicationName);
+ builder.setMessage(message);
+ builder.setPositiveButton("Close", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ semaphore.release();
+ }
+ });
+ builder.setCancelable(false);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+ });
+ try {
+ semaphore.acquire();
+ }
+ catch (InterruptedException e) { }
+ }
+}
diff --git a/android/examples/raytracingshadows/CMakeLists.txt b/android/examples/raytracingshadows/CMakeLists.txt
new file mode 100644
index 00000000..656a60d7
--- /dev/null
+++ b/android/examples/raytracingshadows/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
+
+set(NAME raytracingshadows)
+
+set(SRC_DIR ../../../examples/${NAME})
+set(BASE_DIR ../../../base)
+set(EXTERNAL_DIR ../../../external)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DVK_USE_PLATFORM_ANDROID_KHR -DVK_NO_PROTOTYPES")
+
+file(GLOB EXAMPLE_SRC "${SRC_DIR}/*.cpp")
+
+add_library(native-lib SHARED ${EXAMPLE_SRC})
+
+add_library(native-app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
+
+add_subdirectory(../base ${CMAKE_SOURCE_DIR}/../base)
+
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
+
+include_directories(${BASE_DIR})
+include_directories(${EXTERNAL_DIR})
+include_directories(${EXTERNAL_DIR}/glm)
+include_directories(${EXTERNAL_DIR}/imgui)
+include_directories(${EXTERNAL_DIR}/tinygltf)
+include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
+
+target_link_libraries(
+ native-lib
+ native-app-glue
+ libbase
+ android
+ log
+ z
+)
diff --git a/android/examples/raytracingshadows/build.gradle b/android/examples/raytracingshadows/build.gradle
new file mode 100644
index 00000000..fa968fbb
--- /dev/null
+++ b/android/examples/raytracingshadows/build.gradle
@@ -0,0 +1,65 @@
+apply plugin: 'com.android.application'
+apply from: '../gradle/outputfilename.gradle'
+
+android {
+ compileSdkVersion 26
+ defaultConfig {
+ applicationId "de.saschawillems.vulkanRaytracingshadows"
+ minSdkVersion 19
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+ ndk {
+ abiFilters "armeabi-v7a"
+ }
+ externalNativeBuild {
+ cmake {
+ cppFlags "-std=c++14"
+ arguments "-DANDROID_STL=c++_shared", '-DANDROID_TOOLCHAIN=clang'
+ }
+ }
+ }
+ sourceSets {
+ main.assets.srcDirs = ['assets']
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ path "CMakeLists.txt"
+ }
+ }
+}
+
+task copyTask {
+ copy {
+ from '../../common/res/drawable'
+ into "src/main/res/drawable"
+ include 'icon.png'
+ }
+
+ copy {
+ from '../../../data/shaders/glsl/base'
+ into 'assets/shaders/glsl/base'
+ include '*.spv'
+ }
+
+ copy {
+ from '../../../data/shaders/glsl/raytracingbasic'
+ into 'assets/shaders/glsl/raytracingbasic'
+ include '*.*'
+ }
+
+ copy {
+ from '../../../data/models'
+ into 'assets/models'
+ include 'vulkanscene_shadow.gltf'
+ }
+
+}
+
+preBuild.dependsOn copyTask
\ No newline at end of file
diff --git a/android/examples/raytracingshadows/src/main/AndroidManifest.xml b/android/examples/raytracingshadows/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..ae5447fd
--- /dev/null
+++ b/android/examples/raytracingshadows/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/examples/raytracingshadows/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java b/android/examples/raytracingshadows/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java
new file mode 100644
index 00000000..12e14fc6
--- /dev/null
+++ b/android/examples/raytracingshadows/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 by Sascha Willems - www.saschawillems.de
+ *
+ * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+ */
+package de.saschawillems.vulkanSample;
+
+import android.app.AlertDialog;
+import android.app.NativeActivity;
+import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+
+import java.util.concurrent.Semaphore;
+
+public class VulkanActivity extends NativeActivity {
+
+ static {
+ // Load native library
+ System.loadLibrary("native-lib");
+ }
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ // Use a semaphore to create a modal dialog
+
+ private final Semaphore semaphore = new Semaphore(0, true);
+
+ public void showAlert(final String message)
+ {
+ final VulkanActivity activity = this;
+
+ ApplicationInfo applicationInfo = activity.getApplicationInfo();
+ final String applicationName = applicationInfo.nonLocalizedLabel.toString();
+
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity, android.R.style.Theme_Material_Dialog_Alert);
+ builder.setTitle(applicationName);
+ builder.setMessage(message);
+ builder.setPositiveButton("Close", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ semaphore.release();
+ }
+ });
+ builder.setCancelable(false);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+ });
+ try {
+ semaphore.acquire();
+ }
+ catch (InterruptedException e) { }
+ }
+}
diff --git a/base/VulkanAndroid.cpp b/base/VulkanAndroid.cpp
index a0aa2b8c..5fe482b8 100644
--- a/base/VulkanAndroid.cpp
+++ b/base/VulkanAndroid.cpp
@@ -21,10 +21,12 @@ PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkCreateDevice vkCreateDevice;
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
+PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
+PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
@@ -158,10 +160,12 @@ namespace vks
vkEnumeratePhysicalDevices = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"));
vkGetPhysicalDeviceProperties = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties"));
+ vkGetPhysicalDeviceProperties2 = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
vkEnumerateDeviceLayerProperties = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkEnumerateDeviceLayerProperties"));
vkEnumerateDeviceExtensionProperties = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties"));
vkGetPhysicalDeviceQueueFamilyProperties = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties"));
vkGetPhysicalDeviceFeatures = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures"));
+ vkGetPhysicalDeviceFeatures2 = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
vkCreateDevice = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateDevice"));
vkGetPhysicalDeviceFormatProperties = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties"));
vkGetPhysicalDeviceMemoryProperties = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties"));
diff --git a/base/VulkanAndroid.h b/base/VulkanAndroid.h
index f3a2d68c..885834b3 100644
--- a/base/VulkanAndroid.h
+++ b/base/VulkanAndroid.h
@@ -54,10 +54,12 @@ extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
extern PFN_vkCreateDevice vkCreateDevice;
extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
+extern PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
+extern PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
diff --git a/data/shaders/glsl/base/generate-spirv.bat b/data/shaders/glsl/base/generate-spirv.bat
deleted file mode 100644
index a4ede2cd..00000000
--- a/data/shaders/glsl/base/generate-spirv.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-glslangvalidator -V textoverlay.vert -o textoverlay.vert.spv
-glslangvalidator -V textoverlay.frag -o textoverlay.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/bloom/generate-spirv.bat b/data/shaders/glsl/bloom/generate-spirv.bat
deleted file mode 100644
index fb305f63..00000000
--- a/data/shaders/glsl/bloom/generate-spirv.bat
+++ /dev/null
@@ -1,12 +0,0 @@
-glslangvalidator -V colorpass.vert -o colorpass.vert.spv
-glslangvalidator -V colorpass.frag -o colorpass.frag.spv
-
-glslangvalidator -V phongpass.vert -o phongpass.vert.spv
-glslangvalidator -V phongpass.frag -o phongpass.frag.spv
-
-glslangvalidator -V gaussblur.vert -o gaussblur.vert.spv
-glslangvalidator -V gaussblur.frag -o gaussblur.frag.spv
-
-glslangvalidator -V skybox.vert -o skybox.vert.spv
-glslangvalidator -V skybox.frag -o skybox.frag.spv
-
diff --git a/data/shaders/glsl/computeparticles/generate-spirv.bat b/data/shaders/glsl/computeparticles/generate-spirv.bat
deleted file mode 100644
index be03b7cc..00000000
--- a/data/shaders/glsl/computeparticles/generate-spirv.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-glslangvalidator -V particle.frag -o particle.frag.spv
-glslangvalidator -V particle.vert -o particle.vert.spv
-glslangvalidator -V particle.comp -o particle.comp.spv
-
-
diff --git a/data/shaders/glsl/computeraytracing/generate-spirv.bat b/data/shaders/glsl/computeraytracing/generate-spirv.bat
deleted file mode 100644
index 5266a7f9..00000000
--- a/data/shaders/glsl/computeraytracing/generate-spirv.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-glslangvalidator -V texture.frag -o texture.frag.spv
-glslangvalidator -V texture.vert -o texture.vert.spv
-glslangvalidator -V raytracing.comp -o raytracing.comp.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/computeshader/generate-spirv.bat b/data/shaders/glsl/computeshader/generate-spirv.bat
deleted file mode 100644
index c2e62cc8..00000000
--- a/data/shaders/glsl/computeshader/generate-spirv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V edgedetect.comp -o edgedetect.comp.spv
-glslangvalidator -V emboss.comp -o emboss.comp.spv
-glslangvalidator -V sharpen.comp -o sharpen.comp.spv
-glslangvalidator -V texture.frag -o texture.frag.spv
-glslangvalidator -V texture.vert -o texture.vert.spv
-
-
diff --git a/data/shaders/glsl/debugmarker/generate-spirv.bat b/data/shaders/glsl/debugmarker/generate-spirv.bat
deleted file mode 100644
index f042dcac..00000000
--- a/data/shaders/glsl/debugmarker/generate-spirv.bat
+++ /dev/null
@@ -1,6 +0,0 @@
-glslangvalidator -V toon.vert -o toon.vert.spv
-glslangvalidator -V toon.frag -o toon.frag.spv
-glslangvalidator -V colorpass.vert -o colorpass.vert.spv
-glslangvalidator -V colorpass.frag -o colorpass.frag.spv
-glslangvalidator -V postprocess.vert -o postprocess.vert.spv
-glslangvalidator -V postprocess.frag -o postprocess.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/displacement/generate-spirv.bat b/data/shaders/glsl/displacement/generate-spirv.bat
deleted file mode 100644
index d97ca752..00000000
--- a/data/shaders/glsl/displacement/generate-spirv.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-glslangvalidator -V base.vert -o base.vert.spv
-glslangvalidator -V base.frag -o base.frag.spv
-glslangvalidator -V displacement.tesc -o displacement.tesc.spv
-glslangvalidator -V displacement.tese -o displacement.tese.spv
-
diff --git a/data/shaders/glsl/distancefieldfonts/generate-spirv.bat b/data/shaders/glsl/distancefieldfonts/generate-spirv.bat
deleted file mode 100644
index 10a9063a..00000000
--- a/data/shaders/glsl/distancefieldfonts/generate-spirv.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-glslangvalidator -V sdf.vert -o sdf.vert.spv
-glslangvalidator -V sdf.frag -o sdf.frag.spv
-glslangvalidator -V bitmap.vert -o bitmap.vert.spv
-glslangvalidator -V bitmap.frag -o bitmap.frag.spv
-
diff --git a/data/shaders/glsl/geometryshader/generate-spirv.bat b/data/shaders/glsl/geometryshader/generate-spirv.bat
deleted file mode 100644
index 3bdb6371..00000000
--- a/data/shaders/glsl/geometryshader/generate-spirv.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-glslangvalidator -V base.vert -o base.vert.spv
-glslangvalidator -V base.frag -o base.frag.spv
-glslangvalidator -V normaldebug.geom -o normaldebug.geom.spv
-glslangvalidator -V mesh.vert -o mesh.vert.spv
-glslangvalidator -V mesh.frag -o mesh.frag.spv
diff --git a/data/shaders/glsl/indirectdraw/generate-spirv.bat b/data/shaders/glsl/indirectdraw/generate-spirv.bat
deleted file mode 100644
index b4a3cede..00000000
--- a/data/shaders/glsl/indirectdraw/generate-spirv.bat
+++ /dev/null
@@ -1,6 +0,0 @@
-glslangvalidator -V ground.vert -o ground.vert.spv
-glslangvalidator -V ground.frag -o ground.frag.spv
-glslangvalidator -V indirectdraw.vert -o indirectdraw.vert.spv
-glslangvalidator -V indirectdraw.frag -o indirectdraw.frag.spv
-glslangvalidator -V skysphere.vert -o skysphere.vert.spv
-glslangvalidator -V skysphere.frag -o skysphere.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/instancing/generate-spirv.bat b/data/shaders/glsl/instancing/generate-spirv.bat
deleted file mode 100644
index dc3cda41..00000000
--- a/data/shaders/glsl/instancing/generate-spirv.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-glslangvalidator -V instancing.vert -o instancing.vert.spv
-glslangvalidator -V instancing.frag -o instancing.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/multithreading/generate-spirv.bat b/data/shaders/glsl/multithreading/generate-spirv.bat
deleted file mode 100644
index 0b4e02ac..00000000
--- a/data/shaders/glsl/multithreading/generate-spirv.bat
+++ /dev/null
@@ -1,4 +0,0 @@
-glslangvalidator -V phong.vert -o phong.vert.spv
-glslangvalidator -V phong.frag -o phong.frag.spv
-glslangvalidator -V starsphere.vert -o starsphere.vert.spv
-glslangvalidator -V starsphere.frag -o starsphere.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss b/data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss
deleted file mode 100644
index a00c59b5..00000000
--- a/data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss
+++ /dev/null
@@ -1,9 +0,0 @@
-#version 460
-#extension GL_NV_ray_tracing : require
-
-layout(location = 0) rayPayloadInNV vec3 hitValue;
-
-void main()
-{
- hitValue = vec3(0.0, 0.0, 0.2);
-}
\ No newline at end of file
diff --git a/data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss.spv b/data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss.spv
deleted file mode 100644
index 81c14644..00000000
Binary files a/data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss.spv and /dev/null differ
diff --git a/data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen b/data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen
deleted file mode 100644
index 5b183d9a..00000000
--- a/data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen
+++ /dev/null
@@ -1,32 +0,0 @@
-#version 460
-#extension GL_NV_ray_tracing : require
-
-layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
-layout(binding = 1, set = 0, rgba8) uniform image2D image;
-layout(binding = 2, set = 0) uniform CameraProperties
-{
- mat4 viewInverse;
- mat4 projInverse;
-} cam;
-
-layout(location = 0) rayPayloadNV vec3 hitValue;
-
-void main()
-{
- const vec2 pixelCenter = vec2(gl_LaunchIDNV.xy) + vec2(0.5);
- const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeNV.xy);
- vec2 d = inUV * 2.0 - 1.0;
-
- vec4 origin = cam.viewInverse * vec4(0,0,0,1);
- vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1) ;
- vec4 direction = cam.viewInverse*vec4(normalize(target.xyz / target.w), 0) ;
-
- uint rayFlags = gl_RayFlagsOpaqueNV;
- uint cullMask = 0xff;
- float tmin = 0.001;
- float tmax = 10000.0;
-
- traceNV(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
-
- imageStore(image, ivec2(gl_LaunchIDNV.xy), vec4(hitValue, 0.0));
-}
diff --git a/data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen.spv b/data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen.spv
deleted file mode 100644
index bd277cc8..00000000
Binary files a/data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen.spv and /dev/null differ
diff --git a/data/shaders/glsl/nv_ray_tracing_reflections/closesthit.rchit.spv b/data/shaders/glsl/nv_ray_tracing_reflections/closesthit.rchit.spv
deleted file mode 100644
index 926723c9..00000000
Binary files a/data/shaders/glsl/nv_ray_tracing_reflections/closesthit.rchit.spv and /dev/null differ
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/closesthit.rchit.spv b/data/shaders/glsl/nv_ray_tracing_shadows/closesthit.rchit.spv
deleted file mode 100644
index fe9e37d1..00000000
Binary files a/data/shaders/glsl/nv_ray_tracing_shadows/closesthit.rchit.spv and /dev/null differ
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss b/data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss
deleted file mode 100644
index a00c59b5..00000000
--- a/data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss
+++ /dev/null
@@ -1,9 +0,0 @@
-#version 460
-#extension GL_NV_ray_tracing : require
-
-layout(location = 0) rayPayloadInNV vec3 hitValue;
-
-void main()
-{
- hitValue = vec3(0.0, 0.0, 0.2);
-}
\ No newline at end of file
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss.spv b/data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss.spv
deleted file mode 100644
index 81c14644..00000000
Binary files a/data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss.spv and /dev/null differ
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss b/data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss
deleted file mode 100644
index 429be62e..00000000
--- a/data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss
+++ /dev/null
@@ -1,9 +0,0 @@
-#version 460
-#extension GL_NV_ray_tracing : require
-
-layout(location = 2) rayPayloadInNV bool shadowed;
-
-void main()
-{
- shadowed = false;
-}
\ No newline at end of file
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss.spv b/data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss.spv
deleted file mode 100644
index f411b38d..00000000
Binary files a/data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss.spv and /dev/null differ
diff --git a/data/shaders/glsl/occlusionquery/generate-spirv.bat b/data/shaders/glsl/occlusionquery/generate-spirv.bat
deleted file mode 100644
index 829730cd..00000000
--- a/data/shaders/glsl/occlusionquery/generate-spirv.bat
+++ /dev/null
@@ -1,6 +0,0 @@
-glslangvalidator -V mesh.vert -o mesh.vert.spv
-glslangvalidator -V mesh.frag -o mesh.frag.spv
-glslangvalidator -V occluder.vert -o occluder.vert.spv
-glslangvalidator -V occluder.frag -o occluder.frag.spv
-glslangvalidator -V simple.vert -o simple.vert.spv
-glslangvalidator -V simple.frag -o simple.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/particlefire/generate-spirv.bat b/data/shaders/glsl/particlefire/generate-spirv.bat
deleted file mode 100644
index fe0e23ed..00000000
--- a/data/shaders/glsl/particlefire/generate-spirv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V particle.frag -o particle.frag.spv
-glslangvalidator -V particle.vert -o particle.vert.spv
-glslangvalidator -V normalmap.frag -o normalmap.frag.spv
-glslangvalidator -V normalmap.vert -o normalmap.vert.spv
-
-
-
diff --git a/data/shaders/glsl/pipelines/generate-spriv.bat b/data/shaders/glsl/pipelines/generate-spriv.bat
deleted file mode 100644
index 17806643..00000000
--- a/data/shaders/glsl/pipelines/generate-spriv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V phong.vert -o phong.vert.spv
-glslangvalidator -V phong.frag -o phong.frag.spv
-glslangvalidator -V wireframe.vert -o wireframe.vert.spv
-glslangvalidator -V wireframe.frag -o wireframe.frag.spv
-glslangvalidator -V toon.vert -o toon.vert.spv
-glslangvalidator -V toon.frag -o toon.frag.spv
-
diff --git a/data/shaders/glsl/radialblur/generate-spirv.bat b/data/shaders/glsl/radialblur/generate-spirv.bat
deleted file mode 100644
index 740b6afb..00000000
--- a/data/shaders/glsl/radialblur/generate-spirv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V colorpass.vert -o colorpass.vert.spv
-glslangvalidator -V colorpass.frag -o colorpass.frag.spv
-glslangvalidator -V phongpass.vert -o phongpass.vert.spv
-glslangvalidator -V phongpass.frag -o phongpass.frag.spv
-glslangvalidator -V radialblur.vert -o radialblur.vert.spv
-glslangvalidator -V radialblur.frag -o radialblur.frag.spv
-
diff --git a/data/shaders/glsl/nv_ray_tracing_basic/closesthit.rchit b/data/shaders/glsl/raytracingbasic/closesthit.rchit
similarity index 62%
rename from data/shaders/glsl/nv_ray_tracing_basic/closesthit.rchit
rename to data/shaders/glsl/raytracingbasic/closesthit.rchit
index e8141504..743a2585 100644
--- a/data/shaders/glsl/nv_ray_tracing_basic/closesthit.rchit
+++ b/data/shaders/glsl/raytracingbasic/closesthit.rchit
@@ -1,9 +1,9 @@
#version 460
-#extension GL_NV_ray_tracing : require
+#extension GL_EXT_ray_tracing : enable
#extension GL_EXT_nonuniform_qualifier : enable
-layout(location = 0) rayPayloadInNV vec3 hitValue;
-hitAttributeNV vec3 attribs;
+layout(location = 0) rayPayloadInEXT vec3 hitValue;
+hitAttributeEXT vec3 attribs;
void main()
{
diff --git a/data/shaders/glsl/nv_ray_tracing_basic/closesthit.rchit.spv b/data/shaders/glsl/raytracingbasic/closesthit.rchit.spv
similarity index 55%
rename from data/shaders/glsl/nv_ray_tracing_basic/closesthit.rchit.spv
rename to data/shaders/glsl/raytracingbasic/closesthit.rchit.spv
index 3a89e180..bbf4ba93 100644
Binary files a/data/shaders/glsl/nv_ray_tracing_basic/closesthit.rchit.spv and b/data/shaders/glsl/raytracingbasic/closesthit.rchit.spv differ
diff --git a/data/shaders/glsl/raytracingbasic/miss.rmiss b/data/shaders/glsl/raytracingbasic/miss.rmiss
new file mode 100644
index 00000000..25633fbe
--- /dev/null
+++ b/data/shaders/glsl/raytracingbasic/miss.rmiss
@@ -0,0 +1,9 @@
+#version 460
+#extension GL_EXT_ray_tracing : enable
+
+layout(location = 0) rayPayloadInEXT vec3 hitValue;
+
+void main()
+{
+ hitValue = vec3(0.0, 0.0, 0.2);
+}
\ No newline at end of file
diff --git a/data/shaders/glsl/raytracingbasic/miss.rmiss.spv b/data/shaders/glsl/raytracingbasic/miss.rmiss.spv
new file mode 100644
index 00000000..7fb66cdf
Binary files /dev/null and b/data/shaders/glsl/raytracingbasic/miss.rmiss.spv differ
diff --git a/data/shaders/glsl/raytracingbasic/raygen.rgen b/data/shaders/glsl/raytracingbasic/raygen.rgen
new file mode 100644
index 00000000..7f803f35
--- /dev/null
+++ b/data/shaders/glsl/raytracingbasic/raygen.rgen
@@ -0,0 +1,32 @@
+#version 460
+#extension GL_EXT_ray_tracing : enable
+
+layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
+layout(binding = 1, set = 0, rgba8) uniform image2D image;
+layout(binding = 2, set = 0) uniform CameraProperties
+{
+ mat4 viewInverse;
+ mat4 projInverse;
+} cam;
+
+layout(location = 0) rayPayloadEXT vec3 hitValue;
+
+void main()
+{
+ const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
+ const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.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) ;
+
+ float tmin = 0.001;
+ float tmax = 10000.0;
+
+ hitValue = vec3(0.0);
+
+ traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
+
+ imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 0.0));
+}
diff --git a/data/shaders/glsl/raytracingbasic/raygen.rgen.spv b/data/shaders/glsl/raytracingbasic/raygen.rgen.spv
new file mode 100644
index 00000000..5cc908e5
Binary files /dev/null and b/data/shaders/glsl/raytracingbasic/raygen.rgen.spv differ
diff --git a/data/shaders/glsl/nv_ray_tracing_reflections/closesthit.rchit b/data/shaders/glsl/raytracingreflections/closesthit.rchit
similarity index 88%
rename from data/shaders/glsl/nv_ray_tracing_reflections/closesthit.rchit
rename to data/shaders/glsl/raytracingreflections/closesthit.rchit
index 9f26194c..6d057617 100644
--- a/data/shaders/glsl/nv_ray_tracing_reflections/closesthit.rchit
+++ b/data/shaders/glsl/raytracingreflections/closesthit.rchit
@@ -1,5 +1,5 @@
#version 460
-#extension GL_NV_ray_tracing : require
+#extension GL_EXT_ray_tracing : require
#extension GL_EXT_nonuniform_qualifier : enable
struct RayPayload {
@@ -9,11 +9,11 @@ struct RayPayload {
float reflector;
};
-layout(location = 0) rayPayloadInNV RayPayload rayPayload;
+layout(location = 0) rayPayloadInEXT RayPayload rayPayload;
-hitAttributeNV vec3 attribs;
+hitAttributeEXT vec3 attribs;
-layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
+layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
layout(binding = 2, set = 0) uniform UBO
{
mat4 viewInverse;
@@ -68,7 +68,7 @@ void main()
vec3 lightVector = normalize(ubo.lightPos.xyz);
float dot_product = max(dot(lightVector, normal), 0.6);
rayPayload.color = v0.color.rgb * vec3(dot_product);
- rayPayload.distance = gl_RayTmaxNV;
+ rayPayload.distance = gl_RayTmaxEXT;
rayPayload.normal = normal;
// Objects with full white vertex color are treated as reflectors
diff --git a/data/shaders/glsl/raytracingreflections/closesthit.rchit.spv b/data/shaders/glsl/raytracingreflections/closesthit.rchit.spv
new file mode 100644
index 00000000..41dde2ca
Binary files /dev/null and b/data/shaders/glsl/raytracingreflections/closesthit.rchit.spv differ
diff --git a/data/shaders/glsl/nv_ray_tracing_reflections/miss.rmiss b/data/shaders/glsl/raytracingreflections/miss.rmiss
similarity index 75%
rename from data/shaders/glsl/nv_ray_tracing_reflections/miss.rmiss
rename to data/shaders/glsl/raytracingreflections/miss.rmiss
index 0037ff10..f2da7971 100644
--- a/data/shaders/glsl/nv_ray_tracing_reflections/miss.rmiss
+++ b/data/shaders/glsl/raytracingreflections/miss.rmiss
@@ -1,5 +1,5 @@
#version 460
-#extension GL_NV_ray_tracing : require
+#extension GL_EXT_ray_tracing : require
struct RayPayload {
vec3 color;
@@ -8,14 +8,14 @@ struct RayPayload {
float reflector;
};
-layout(location = 0) rayPayloadInNV RayPayload rayPayload;
+layout(location = 0) rayPayloadInEXT RayPayload rayPayload;
void main()
{
// View-independent background gradient to simulate a basic sky background
const vec3 gradientStart = vec3(0.5, 0.6, 1.0);
const vec3 gradientEnd = vec3(1.0);
- vec3 unitDir = normalize(gl_WorldRayDirectionNV);
+ vec3 unitDir = normalize(gl_WorldRayDirectionEXT);
float t = 0.5 * (unitDir.y + 1.0);
rayPayload.color = (1.0-t) * gradientStart + t * gradientEnd;
diff --git a/data/shaders/glsl/nv_ray_tracing_reflections/miss.rmiss.spv b/data/shaders/glsl/raytracingreflections/miss.rmiss.spv
similarity index 64%
rename from data/shaders/glsl/nv_ray_tracing_reflections/miss.rmiss.spv
rename to data/shaders/glsl/raytracingreflections/miss.rmiss.spv
index f190c331..2d3d0e3b 100644
Binary files a/data/shaders/glsl/nv_ray_tracing_reflections/miss.rmiss.spv and b/data/shaders/glsl/raytracingreflections/miss.rmiss.spv differ
diff --git a/data/shaders/glsl/nv_ray_tracing_reflections/raygen.rgen b/data/shaders/glsl/raytracingreflections/raygen.rgen
similarity index 70%
rename from data/shaders/glsl/nv_ray_tracing_reflections/raygen.rgen
rename to data/shaders/glsl/raytracingreflections/raygen.rgen
index 61fbd0d8..b1e6b63d 100644
--- a/data/shaders/glsl/nv_ray_tracing_reflections/raygen.rgen
+++ b/data/shaders/glsl/raytracingreflections/raygen.rgen
@@ -1,7 +1,7 @@
#version 460
-#extension GL_NV_ray_tracing : require
+#extension GL_EXT_ray_tracing : require
-layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
+layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 0, rgba8) uniform image2D image;
layout(binding = 2, set = 0) uniform CameraProperties
{
@@ -18,22 +18,22 @@ struct RayPayload {
float reflector;
};
-layout(location = 0) rayPayloadNV RayPayload rayPayload;
+layout(location = 0) rayPayloadEXT RayPayload rayPayload;
// Max. number of recursion is passed via a specialization constant
layout (constant_id = 0) const int MAX_RECURSION = 0;
void main()
{
- const vec2 pixelCenter = vec2(gl_LaunchIDNV.xy) + vec2(0.5);
- const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeNV.xy);
+ const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
+ const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.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 / target.w), 0);
- uint rayFlags = gl_RayFlagsOpaqueNV;
+ uint rayFlags = gl_RayFlagsOpaqueEXT;
uint cullMask = 0xff;
float tmin = 0.001;
float tmax = 10000.0;
@@ -41,7 +41,7 @@ void main()
vec3 color = vec3(0.0);
for (int i = 0; i < MAX_RECURSION; i++) {
- traceNV(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
+ traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
vec3 hitColor = rayPayload.color;
if (rayPayload.distance < 0.0f) {
@@ -58,5 +58,5 @@ void main()
}
- imageStore(image, ivec2(gl_LaunchIDNV.xy), vec4(color, 0.0));
+ imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(color, 0.0));
}
diff --git a/data/shaders/glsl/nv_ray_tracing_reflections/raygen.rgen.spv b/data/shaders/glsl/raytracingreflections/raygen.rgen.spv
similarity index 75%
rename from data/shaders/glsl/nv_ray_tracing_reflections/raygen.rgen.spv
rename to data/shaders/glsl/raytracingreflections/raygen.rgen.spv
index 5dc3472d..aab87a9b 100644
Binary files a/data/shaders/glsl/nv_ray_tracing_reflections/raygen.rgen.spv and b/data/shaders/glsl/raytracingreflections/raygen.rgen.spv differ
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/closesthit.rchit b/data/shaders/glsl/raytracingshadows/closesthit.rchit
similarity index 70%
rename from data/shaders/glsl/nv_ray_tracing_shadows/closesthit.rchit
rename to data/shaders/glsl/raytracingshadows/closesthit.rchit
index 758ddda6..df016938 100644
--- a/data/shaders/glsl/nv_ray_tracing_shadows/closesthit.rchit
+++ b/data/shaders/glsl/raytracingshadows/closesthit.rchit
@@ -1,12 +1,12 @@
#version 460
-#extension GL_NV_ray_tracing : require
+#extension GL_EXT_ray_tracing : require
#extension GL_EXT_nonuniform_qualifier : enable
-layout(location = 0) rayPayloadInNV vec3 hitValue;
-layout(location = 2) rayPayloadNV bool shadowed;
-hitAttributeNV vec3 attribs;
+layout(location = 0) rayPayloadInEXT vec3 hitValue;
+layout(location = 2) rayPayloadEXT bool shadowed;
+hitAttributeEXT vec3 attribs;
-layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
+layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
layout(binding = 2, set = 0) uniform UBO
{
mat4 viewInverse;
@@ -23,9 +23,9 @@ struct Vertex
vec3 normal;
vec2 uv;
vec4 color;
- vec4 _pad0;
+ vec4 _pad0;
vec4 _pad1;
-};
+ };
Vertex unpack(uint index)
{
@@ -60,15 +60,15 @@ void main()
// Basic lighting
vec3 lightVector = normalize(ubo.lightPos.xyz);
float dot_product = max(dot(lightVector, normal), 0.2);
- hitValue = v0.color.rgb * vec3(dot_product);
+ hitValue = v0.color.rgb * dot_product;
// Shadow casting
float tmin = 0.001;
- float tmax = 100.0;
- vec3 origin = gl_WorldRayOriginNV + gl_WorldRayDirectionNV * gl_HitTNV;
+ float tmax = 10000.0;
+ vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
shadowed = true;
- // Offset indices to match shadow hit/miss index
- traceNV(topLevelAS, gl_RayFlagsTerminateOnFirstHitNV | gl_RayFlagsOpaqueNV|gl_RayFlagsSkipClosestHitShaderNV, 0xFF, 1, 0, 1, origin, tmin, lightVector, tmax, 2);
+ // Trace shadow ray and offset indices to match shadow hit/miss shader group indices
+ traceRayEXT(topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT, 0xFF, 1, 0, 1, origin, tmin, lightVector, tmax, 2);
if (shadowed) {
hitValue *= 0.3;
}
diff --git a/data/shaders/glsl/raytracingshadows/closesthit.rchit.spv b/data/shaders/glsl/raytracingshadows/closesthit.rchit.spv
new file mode 100644
index 00000000..1904fdde
Binary files /dev/null and b/data/shaders/glsl/raytracingshadows/closesthit.rchit.spv differ
diff --git a/data/shaders/glsl/raytracingshadows/miss.rmiss b/data/shaders/glsl/raytracingshadows/miss.rmiss
new file mode 100644
index 00000000..577f7e8e
--- /dev/null
+++ b/data/shaders/glsl/raytracingshadows/miss.rmiss
@@ -0,0 +1,9 @@
+#version 460
+#extension GL_EXT_ray_tracing : require
+
+layout(location = 0) rayPayloadInEXT vec3 hitValue;
+
+void main()
+{
+ hitValue = vec3(0.0, 0.0, 0.2);
+}
\ No newline at end of file
diff --git a/data/shaders/glsl/raytracingshadows/miss.rmiss.spv b/data/shaders/glsl/raytracingshadows/miss.rmiss.spv
new file mode 100644
index 00000000..7fb66cdf
Binary files /dev/null and b/data/shaders/glsl/raytracingshadows/miss.rmiss.spv differ
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/raygen.rgen b/data/shaders/glsl/raytracingshadows/raygen.rgen
similarity index 50%
rename from data/shaders/glsl/nv_ray_tracing_shadows/raygen.rgen
rename to data/shaders/glsl/raytracingshadows/raygen.rgen
index 2f7f95e7..88b5f3fe 100644
--- a/data/shaders/glsl/nv_ray_tracing_shadows/raygen.rgen
+++ b/data/shaders/glsl/raytracingshadows/raygen.rgen
@@ -1,7 +1,7 @@
#version 460
-#extension GL_NV_ray_tracing : require
+#extension GL_EXT_ray_tracing : require
-layout(binding = 0, set = 0) uniform accelerationStructureNV topLevelAS;
+layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
layout(binding = 1, set = 0, rgba8) uniform image2D image;
layout(binding = 2, set = 0) uniform CameraProperties
{
@@ -10,24 +10,24 @@ layout(binding = 2, set = 0) uniform CameraProperties
vec4 lightPos;
} cam;
-layout(location = 0) rayPayloadNV vec3 hitValue;
+layout(location = 0) rayPayloadEXT vec3 hitValue;
void main()
{
- const vec2 pixelCenter = vec2(gl_LaunchIDNV.xy) + vec2(0.5);
- const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeNV.xy);
+ const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
+ const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.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 / target.w), 0) ;
- uint rayFlags = gl_RayFlagsOpaqueNV;
+ uint rayFlags = gl_RayFlagsOpaqueEXT;
uint cullMask = 0xff;
float tmin = 0.001;
float tmax = 10000.0;
- traceNV(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
+ traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0);
- imageStore(image, ivec2(gl_LaunchIDNV.xy), vec4(hitValue, 0.0));
+ imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 0.0));
}
diff --git a/data/shaders/glsl/nv_ray_tracing_shadows/raygen.rgen.spv b/data/shaders/glsl/raytracingshadows/raygen.rgen.spv
similarity index 69%
rename from data/shaders/glsl/nv_ray_tracing_shadows/raygen.rgen.spv
rename to data/shaders/glsl/raytracingshadows/raygen.rgen.spv
index 7a5d5f50..53552e71 100644
Binary files a/data/shaders/glsl/nv_ray_tracing_shadows/raygen.rgen.spv and b/data/shaders/glsl/raytracingshadows/raygen.rgen.spv differ
diff --git a/data/shaders/glsl/raytracingshadows/shadow.rmiss b/data/shaders/glsl/raytracingshadows/shadow.rmiss
new file mode 100644
index 00000000..36d9b7ba
--- /dev/null
+++ b/data/shaders/glsl/raytracingshadows/shadow.rmiss
@@ -0,0 +1,9 @@
+#version 460
+#extension GL_EXT_ray_tracing : require
+
+layout(location = 2) rayPayloadInEXT bool shadowed;
+
+void main()
+{
+ shadowed = false;
+}
\ No newline at end of file
diff --git a/data/shaders/glsl/raytracingshadows/shadow.rmiss.spv b/data/shaders/glsl/raytracingshadows/shadow.rmiss.spv
new file mode 100644
index 00000000..cf13a98a
Binary files /dev/null and b/data/shaders/glsl/raytracingshadows/shadow.rmiss.spv differ
diff --git a/data/shaders/glsl/shadowmapping/generate-spirv.bat b/data/shaders/glsl/shadowmapping/generate-spirv.bat
deleted file mode 100644
index b1e804fc..00000000
--- a/data/shaders/glsl/shadowmapping/generate-spirv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V offscreen.vert -o offscreen.vert.spv
-glslangvalidator -V offscreen.frag -o offscreen.frag.spv
-glslangvalidator -V quad.vert -o quad.vert.spv
-glslangvalidator -V quad.frag -o quad.frag.spv
-glslangvalidator -V scene.vert -o scene.vert.spv
-glslangvalidator -V scene.frag -o scene.frag.spv
-
diff --git a/data/shaders/glsl/shadowmappingomni/generate-spirv.bat b/data/shaders/glsl/shadowmappingomni/generate-spirv.bat
deleted file mode 100644
index a0a13412..00000000
--- a/data/shaders/glsl/shadowmappingomni/generate-spirv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V offscreen.vert -o offscreen.vert.spv
-glslangvalidator -V offscreen.frag -o offscreen.frag.spv
-glslangvalidator -V scene.vert -o scene.vert.spv
-glslangvalidator -V scene.frag -o scene.frag.spv
-glslangvalidator -V cubemapdisplay.vert -o cubemapdisplay.vert.spv
-glslangvalidator -V cubemapdisplay.frag -o cubemapdisplay.frag.spv
-
diff --git a/data/shaders/glsl/sphericalenvmapping/generate-spirv.bat b/data/shaders/glsl/sphericalenvmapping/generate-spirv.bat
deleted file mode 100644
index f62c9388..00000000
--- a/data/shaders/glsl/sphericalenvmapping/generate-spirv.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-glslangvalidator -V sem.vert -o sem.vert.spv
-glslangvalidator -V sem.frag -o sem.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/terraintessellation/generate-spirv.bat b/data/shaders/glsl/terraintessellation/generate-spirv.bat
deleted file mode 100644
index 79ab91c1..00000000
--- a/data/shaders/glsl/terraintessellation/generate-spirv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V terrain.vert -o terrain.vert.spv
-glslangvalidator -V terrain.frag -o terrain.frag.spv
-glslangvalidator -V skysphere.vert -o skysphere.vert.spv
-glslangvalidator -V skysphere.frag -o skysphere.frag.spv
-glslangvalidator -V terrain.tesc -o terrain.tesc.spv
-glslangvalidator -V terrain.tese -o terrain.tese.spv
-
diff --git a/data/shaders/glsl/tessellation/generate-spriv.bat b/data/shaders/glsl/tessellation/generate-spriv.bat
deleted file mode 100644
index 8181fa03..00000000
--- a/data/shaders/glsl/tessellation/generate-spriv.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-glslangvalidator -V base.vert -o base.vert.spv
-glslangvalidator -V base.frag -o base.frag.spv
-glslangvalidator -V passthrough.tesc -o passthrough.tesc.spv
-glslangvalidator -V passthrough.tese -o passthrough.tese.spv
-glslangvalidator -V pntriangles.tesc -o pntriangles.tesc.spv
-glslangvalidator -V pntriangles.tese -o pntriangles.tese.spv
-
diff --git a/data/shaders/glsl/texture/generate-spirv.bat b/data/shaders/glsl/texture/generate-spirv.bat
deleted file mode 100644
index dadbb7c0..00000000
--- a/data/shaders/glsl/texture/generate-spirv.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-glslangvalidator -V texture.vert -o texture.vert.spv
-glslangvalidator -V texture.frag -o texture.frag.spv
-
diff --git a/data/shaders/glsl/texturearray/generate-spirv.bat b/data/shaders/glsl/texturearray/generate-spirv.bat
deleted file mode 100644
index dc3cda41..00000000
--- a/data/shaders/glsl/texturearray/generate-spirv.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-glslangvalidator -V instancing.vert -o instancing.vert.spv
-glslangvalidator -V instancing.frag -o instancing.frag.spv
\ No newline at end of file
diff --git a/data/shaders/glsl/vulkanscene/generate-spriv.bat b/data/shaders/glsl/vulkanscene/generate-spriv.bat
deleted file mode 100644
index 51a284d7..00000000
--- a/data/shaders/glsl/vulkanscene/generate-spriv.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-glslangvalidator -V logo.vert -o logo.vert.spv
-glslangvalidator -V logo.frag -o logo.frag.spv
-
-glslangvalidator -V mesh.vert -o mesh.vert.spv
-glslangvalidator -V mesh.frag -o mesh.frag.spv
-
-glslangvalidator -V skybox.vert -o skybox.vert.spv
-glslangvalidator -V skybox.frag -o skybox.frag.spv
\ No newline at end of file
diff --git a/data/shaders/hlsl/nv_ray_tracing_basic/closesthit.rchit b/data/shaders/hlsl/raytracingbasic/closesthit.rchit
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_basic/closesthit.rchit
rename to data/shaders/hlsl/raytracingbasic/closesthit.rchit
diff --git a/data/shaders/hlsl/nv_ray_tracing_basic/closesthit.rchit.spv b/data/shaders/hlsl/raytracingbasic/closesthit.rchit.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_basic/closesthit.rchit.spv
rename to data/shaders/hlsl/raytracingbasic/closesthit.rchit.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_basic/miss.rmiss b/data/shaders/hlsl/raytracingbasic/miss.rmiss
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_basic/miss.rmiss
rename to data/shaders/hlsl/raytracingbasic/miss.rmiss
diff --git a/data/shaders/hlsl/nv_ray_tracing_basic/miss.rmiss.spv b/data/shaders/hlsl/raytracingbasic/miss.rmiss.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_basic/miss.rmiss.spv
rename to data/shaders/hlsl/raytracingbasic/miss.rmiss.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_basic/raygen.rgen b/data/shaders/hlsl/raytracingbasic/raygen.rgen
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_basic/raygen.rgen
rename to data/shaders/hlsl/raytracingbasic/raygen.rgen
diff --git a/data/shaders/hlsl/nv_ray_tracing_basic/raygen.rgen.spv b/data/shaders/hlsl/raytracingbasic/raygen.rgen.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_basic/raygen.rgen.spv
rename to data/shaders/hlsl/raytracingbasic/raygen.rgen.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_reflections/closesthit.rchit b/data/shaders/hlsl/raytracingreflections/closesthit.rchit
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_reflections/closesthit.rchit
rename to data/shaders/hlsl/raytracingreflections/closesthit.rchit
diff --git a/data/shaders/hlsl/nv_ray_tracing_reflections/closesthit.rchit.spv b/data/shaders/hlsl/raytracingreflections/closesthit.rchit.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_reflections/closesthit.rchit.spv
rename to data/shaders/hlsl/raytracingreflections/closesthit.rchit.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_reflections/miss.rmiss b/data/shaders/hlsl/raytracingreflections/miss.rmiss
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_reflections/miss.rmiss
rename to data/shaders/hlsl/raytracingreflections/miss.rmiss
diff --git a/data/shaders/hlsl/nv_ray_tracing_reflections/miss.rmiss.spv b/data/shaders/hlsl/raytracingreflections/miss.rmiss.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_reflections/miss.rmiss.spv
rename to data/shaders/hlsl/raytracingreflections/miss.rmiss.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_reflections/raygen.rgen b/data/shaders/hlsl/raytracingreflections/raygen.rgen
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_reflections/raygen.rgen
rename to data/shaders/hlsl/raytracingreflections/raygen.rgen
diff --git a/data/shaders/hlsl/nv_ray_tracing_reflections/raygen.rgen.spv b/data/shaders/hlsl/raytracingreflections/raygen.rgen.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_reflections/raygen.rgen.spv
rename to data/shaders/hlsl/raytracingreflections/raygen.rgen.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/closesthit.rchit b/data/shaders/hlsl/raytracingshadows/closesthit.rchit
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/closesthit.rchit
rename to data/shaders/hlsl/raytracingshadows/closesthit.rchit
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/closesthit.rchit.spv b/data/shaders/hlsl/raytracingshadows/closesthit.rchit.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/closesthit.rchit.spv
rename to data/shaders/hlsl/raytracingshadows/closesthit.rchit.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/miss.rmiss b/data/shaders/hlsl/raytracingshadows/miss.rmiss
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/miss.rmiss
rename to data/shaders/hlsl/raytracingshadows/miss.rmiss
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/miss.rmiss.spv b/data/shaders/hlsl/raytracingshadows/miss.rmiss.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/miss.rmiss.spv
rename to data/shaders/hlsl/raytracingshadows/miss.rmiss.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/raygen.rgen b/data/shaders/hlsl/raytracingshadows/raygen.rgen
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/raygen.rgen
rename to data/shaders/hlsl/raytracingshadows/raygen.rgen
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/raygen.rgen.spv b/data/shaders/hlsl/raytracingshadows/raygen.rgen.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/raygen.rgen.spv
rename to data/shaders/hlsl/raytracingshadows/raygen.rgen.spv
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/shadow.rmiss b/data/shaders/hlsl/raytracingshadows/shadow.rmiss
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/shadow.rmiss
rename to data/shaders/hlsl/raytracingshadows/shadow.rmiss
diff --git a/data/shaders/hlsl/nv_ray_tracing_shadows/shadow.rmiss.spv b/data/shaders/hlsl/raytracingshadows/shadow.rmiss.spv
similarity index 100%
rename from data/shaders/hlsl/nv_ray_tracing_shadows/shadow.rmiss.spv
rename to data/shaders/hlsl/raytracingshadows/shadow.rmiss.spv
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 5ec64ff9..2dfed453 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -84,10 +84,7 @@ set(EXAMPLES
multisampling
multithreading
multiview
- negativeviewportheight
- nv_ray_tracing_basic
- nv_ray_tracing_shadows
- nv_ray_tracing_reflections
+ negativeviewportheight
occlusionquery
offscreen
parallaxmapping
@@ -100,6 +97,9 @@ set(EXAMPLES
pushconstants
pushdescriptors
radialblur
+ raytracingbasic
+ raytracingreflections
+ raytracingshadows
renderheadless
screenshot
shadowmapping
diff --git a/examples/nv_ray_tracing_basic/nv_ray_tracing_basic.cpp b/examples/nv_ray_tracing_basic/nv_ray_tracing_basic.cpp
deleted file mode 100644
index e60f35be..00000000
--- a/examples/nv_ray_tracing_basic/nv_ray_tracing_basic.cpp
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
-* Vulkan Example - Basic example for ray tracing using VK_NV_ray_tracing
-*
-* Copyright (C) by Sascha Willems - www.saschawillems.de
-*
-* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-*/
-
-#include "vulkanexamplebase.h"
-
-// Ray tracing acceleration structure
-struct AccelerationStructure {
- VkDeviceMemory memory;
- VkAccelerationStructureNV accelerationStructure;
- uint64_t handle;
-};
-
-// Ray tracing geometry instance
-struct GeometryInstance {
- glm::mat3x4 transform;
- uint32_t instanceId : 24;
- uint32_t mask : 8;
- uint32_t instanceOffset : 24;
- uint32_t flags : 8;
- uint64_t accelerationStructureHandle;
-};
-
-// Indices for the different ray tracing shader types used in this example
-#define INDEX_RAYGEN 0
-#define INDEX_MISS 1
-#define INDEX_CLOSEST_HIT 2
-
-#define NUM_SHADER_GROUPS 3
-
-class VulkanExample : public VulkanExampleBase
-{
-public:
- PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV;
- PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV;
- PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV;
- PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV;
- PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV;
- PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV;
- PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV;
- PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV;
- PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV;
-
- VkPhysicalDeviceRayTracingPropertiesNV rayTracingProperties{};
-
- AccelerationStructure bottomLevelAS;
- AccelerationStructure topLevelAS;
-
- vks::Buffer vertexBuffer;
- vks::Buffer indexBuffer;
- uint32_t indexCount;
- vks::Buffer shaderBindingTable;
-
- struct StorageImage {
- VkDeviceMemory memory;
- VkImage image;
- VkImageView view;
- VkFormat format;
- } storageImage;
-
- struct UniformData {
- glm::mat4 viewInverse;
- glm::mat4 projInverse;
- } uniformData;
- vks::Buffer ubo;
-
- VkPipeline pipeline;
- VkPipelineLayout pipelineLayout;
- VkDescriptorSet descriptorSet;
- VkDescriptorSetLayout descriptorSetLayout;
-
- VulkanExample() : VulkanExampleBase()
- {
- title = "VK_NV_ray_tracing";
- settings.overlay = true;
- camera.type = Camera::CameraType::lookat;
- camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
- camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
- camera.setTranslation(glm::vec3(0.0f, 0.0f, -2.5f));
- // Enable instance and device extensions required to use VK_NV_ray_tracing
- enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
- enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
- enabledDeviceExtensions.push_back(VK_NV_RAY_TRACING_EXTENSION_NAME);
- }
-
- ~VulkanExample()
- {
- vkDestroyPipeline(device, pipeline, nullptr);
- vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
- vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
- vkDestroyImageView(device, storageImage.view, nullptr);
- vkDestroyImage(device, storageImage.image, nullptr);
- vkFreeMemory(device, storageImage.memory, nullptr);
- vkFreeMemory(device, bottomLevelAS.memory, nullptr);
- vkFreeMemory(device, topLevelAS.memory, nullptr);
- vkDestroyAccelerationStructureNV(device, bottomLevelAS.accelerationStructure, nullptr);
- vkDestroyAccelerationStructureNV(device, topLevelAS.accelerationStructure, nullptr);
- vertexBuffer.destroy();
- indexBuffer.destroy();
- shaderBindingTable.destroy();
- ubo.destroy();
- }
-
- /*
- Set up a storage image that the ray generation shader will be writing to
- */
- void createStorageImage()
- {
- VkImageCreateInfo image = vks::initializers::imageCreateInfo();
- image.imageType = VK_IMAGE_TYPE_2D;
- image.format = swapChain.colorFormat;
- image.extent.width = width;
- image.extent.height = height;
- image.extent.depth = 1;
- image.mipLevels = 1;
- image.arrayLayers = 1;
- image.samples = VK_SAMPLE_COUNT_1_BIT;
- image.tiling = VK_IMAGE_TILING_OPTIMAL;
- image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
- image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &storageImage.image));
-
- VkMemoryRequirements memReqs;
- vkGetImageMemoryRequirements(device, storageImage.image, &memReqs);
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memReqs.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &storageImage.memory));
- VK_CHECK_RESULT(vkBindImageMemory(device, storageImage.image, storageImage.memory, 0));
-
- VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
- colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
- colorImageView.format = swapChain.colorFormat;
- colorImageView.subresourceRange = {};
- colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- colorImageView.subresourceRange.baseMipLevel = 0;
- colorImageView.subresourceRange.levelCount = 1;
- colorImageView.subresourceRange.baseArrayLayer = 0;
- colorImageView.subresourceRange.layerCount = 1;
- colorImageView.image = storageImage.image;
- VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &storageImage.view));
-
- VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
- vks::tools::setImageLayout(cmdBuffer, storageImage.image,
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_GENERAL,
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
- vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
- }
-
- /*
- The bottom level acceleration structure contains the scene's geometry (vertices, triangles)
- */
- void createBottomLevelAccelerationStructure(const VkGeometryNV* geometries)
- {
- VkAccelerationStructureInfoNV accelerationStructureInfo{};
- accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
- accelerationStructureInfo.instanceCount = 0;
- accelerationStructureInfo.geometryCount = 1;
- accelerationStructureInfo.pGeometries = geometries;
-
- VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
- accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
- accelerationStructureCI.info = accelerationStructureInfo;
- VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &bottomLevelAS.accelerationStructure));
-
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
- memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
-
- VkMemoryRequirements2 memoryRequirements2{};
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
-
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &bottomLevelAS.memory));
-
- VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
- accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
- accelerationStructureMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
- accelerationStructureMemoryInfo.memory = bottomLevelAS.memory;
- VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
-
- VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, bottomLevelAS.accelerationStructure, sizeof(uint64_t), &bottomLevelAS.handle));
- }
-
- /*
- The top level acceleration structure contains the scene's object instances
- */
- void createTopLevelAccelerationStructure()
- {
- VkAccelerationStructureInfoNV accelerationStructureInfo{};
- accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV;
- accelerationStructureInfo.instanceCount = 1;
- accelerationStructureInfo.geometryCount = 0;
-
- VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
- accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
- accelerationStructureCI.info = accelerationStructureInfo;
- VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &topLevelAS.accelerationStructure));
-
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
- memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
-
- VkMemoryRequirements2 memoryRequirements2{};
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
-
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &topLevelAS.memory));
-
- VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
- accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
- accelerationStructureMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure;
- accelerationStructureMemoryInfo.memory = topLevelAS.memory;
- VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
-
- VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, topLevelAS.accelerationStructure, sizeof(uint64_t), &topLevelAS.handle));
- }
-
- /*
- Create scene geometry and ray tracing acceleration structures
- */
- void createScene()
- {
- // Setup vertices for a single triangle
- struct Vertex {
- float pos[3];
- };
- std::vector vertices = {
- { { 1.0f, 1.0f, 0.0f } },
- { { -1.0f, 1.0f, 0.0f } },
- { { 0.0f, -1.0f, 0.0f } }
- };
-
- // Setup indices
- std::vector indices = { 0, 1, 2 };
- indexCount = static_cast(indices.size());
-
- // Create buffers
- // For the sake of simplicity we won't stage the vertex data to the gpu memory
- // Vertex buffer
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &vertexBuffer,
- vertices.size() * sizeof(Vertex),
- vertices.data()));
- // Index buffer
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &indexBuffer,
- indices.size() * sizeof(uint32_t),
- indices.data()));
-
- /*
- Create the bottom level acceleration structure containing the actual scene geometry
- */
- VkGeometryNV geometry{};
- geometry.sType = VK_STRUCTURE_TYPE_GEOMETRY_NV;
- geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_NV;
- geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV;
- geometry.geometry.triangles.vertexData = vertexBuffer.buffer;
- geometry.geometry.triangles.vertexOffset = 0;
- geometry.geometry.triangles.vertexCount = static_cast(vertices.size());
- geometry.geometry.triangles.vertexStride = sizeof(Vertex);
- geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
- geometry.geometry.triangles.indexData = indexBuffer.buffer;
- geometry.geometry.triangles.indexOffset = 0;
- geometry.geometry.triangles.indexCount = indexCount;
- geometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
- geometry.geometry.triangles.transformData = VK_NULL_HANDLE;
- geometry.geometry.triangles.transformOffset = 0;
- geometry.geometry.aabbs = {};
- geometry.geometry.aabbs.sType = { VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV };
- geometry.flags = VK_GEOMETRY_OPAQUE_BIT_NV;
-
- createBottomLevelAccelerationStructure(&geometry);
-
- /*
- Create the top-level acceleration structure that contains geometry instance information
- */
-
- // Single instance with a 3x4 transform matrix for the ray traced triangle
- vks::Buffer instanceBuffer;
-
- glm::mat3x4 transform = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- };
-
- GeometryInstance geometryInstance{};
- geometryInstance.transform = transform;
- geometryInstance.instanceId = 0;
- geometryInstance.mask = 0xff;
- geometryInstance.instanceOffset = 0;
- geometryInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV;
- geometryInstance.accelerationStructureHandle = bottomLevelAS.handle;
-
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &instanceBuffer,
- sizeof(GeometryInstance),
- &geometryInstance));
-
- createTopLevelAccelerationStructure();
-
- /*
- Build the acceleration structure
- */
-
- // Acceleration structure build requires some scratch space to store temporary information
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV;
-
- VkMemoryRequirements2 memReqBottomLevelAS;
- memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqBottomLevelAS);
-
- VkMemoryRequirements2 memReqTopLevelAS;
- memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqTopLevelAS);
-
- const VkDeviceSize scratchBufferSize = std::max(memReqBottomLevelAS.memoryRequirements.size, memReqTopLevelAS.memoryRequirements.size);
-
- vks::Buffer scratchBuffer;
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
- &scratchBuffer,
- scratchBufferSize));
-
- VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
-
- /*
- Build bottom level acceleration structure
- */
- VkAccelerationStructureInfoNV buildInfo{};
- buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
- buildInfo.geometryCount = 1;
- buildInfo.pGeometries = &geometry;
-
- vkCmdBuildAccelerationStructureNV(
- cmdBuffer,
- &buildInfo,
- VK_NULL_HANDLE,
- 0,
- VK_FALSE,
- bottomLevelAS.accelerationStructure,
- VK_NULL_HANDLE,
- scratchBuffer.buffer,
- 0);
-
- VkMemoryBarrier memoryBarrier = vks::initializers::memoryBarrier();
- memoryBarrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
- memoryBarrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
- vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
-
- /*
- Build top-level acceleration structure
- */
- buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV;
- buildInfo.pGeometries = 0;
- buildInfo.geometryCount = 0;
- buildInfo.instanceCount = 1;
-
- vkCmdBuildAccelerationStructureNV(
- cmdBuffer,
- &buildInfo,
- instanceBuffer.buffer,
- 0,
- VK_FALSE,
- topLevelAS.accelerationStructure,
- VK_NULL_HANDLE,
- scratchBuffer.buffer,
- 0);
-
- vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
-
- vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
-
- scratchBuffer.destroy();
- instanceBuffer.destroy();
- }
-
- VkDeviceSize copyShaderIdentifier(uint8_t* data, const uint8_t* shaderHandleStorage, uint32_t groupIndex) {
- const uint32_t shaderGroupHandleSize = rayTracingProperties.shaderGroupHandleSize;
- memcpy(data, shaderHandleStorage + groupIndex * shaderGroupHandleSize, shaderGroupHandleSize);
- return shaderGroupHandleSize;
- }
-
- /*
- Create the Shader Binding Table that binds the programs and top-level acceleration structure
- */
- void createShaderBindingTable() {
- // Create buffer for the shader binding table
- const uint32_t sbtSize = rayTracingProperties.shaderGroupHandleSize * NUM_SHADER_GROUPS;
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
- &shaderBindingTable,
- sbtSize));
- shaderBindingTable.map();
-
- auto shaderHandleStorage = new uint8_t[sbtSize];
- // Get shader identifiers
- VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesNV(device, pipeline, 0, NUM_SHADER_GROUPS, sbtSize, shaderHandleStorage));
- auto* data = static_cast(shaderBindingTable.mapped);
- // Copy the shader identifiers to the shader binding table
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_RAYGEN);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_MISS);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_CLOSEST_HIT);
- shaderBindingTable.unmap();
- }
-
- /*
- Create the descriptor sets used for the ray tracing dispatch
- */
- void createDescriptorSets()
- {
- std::vector poolSizes = {
- { VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1 },
- { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 }
- };
- VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
- VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
-
- VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
- VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
-
- VkWriteDescriptorSetAccelerationStructureNV descriptorAccelerationStructureInfo{};
- descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV;
- descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
- descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure;
-
- VkWriteDescriptorSet accelerationStructureWrite{};
- accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- // The specialized acceleration structure descriptor has to be chained
- accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
- accelerationStructureWrite.dstSet = descriptorSet;
- accelerationStructureWrite.dstBinding = 0;
- accelerationStructureWrite.descriptorCount = 1;
- accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
-
- VkDescriptorImageInfo storageImageDescriptor{};
- storageImageDescriptor.imageView = storageImage.view;
- storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
- VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
- VkWriteDescriptorSet uniformBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor);
-
- std::vector writeDescriptorSets = {
- accelerationStructureWrite,
- resultImageWrite,
- uniformBufferWrite
- };
- vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
- }
-
- /*
- Create our ray tracing pipeline
- */
- void createRayTracingPipeline()
- {
- VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding{};
- accelerationStructureLayoutBinding.binding = 0;
- accelerationStructureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
- accelerationStructureLayoutBinding.descriptorCount = 1;
- accelerationStructureLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
-
- VkDescriptorSetLayoutBinding resultImageLayoutBinding{};
- resultImageLayoutBinding.binding = 1;
- resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- resultImageLayoutBinding.descriptorCount = 1;
- resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
-
- VkDescriptorSetLayoutBinding uniformBufferBinding{};
- uniformBufferBinding.binding = 2;
- uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uniformBufferBinding.descriptorCount = 1;
- uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
-
- std::vector bindings({
- accelerationStructureLayoutBinding,
- resultImageLayoutBinding,
- uniformBufferBinding
- });
-
- VkDescriptorSetLayoutCreateInfo layoutInfo{};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = static_cast(bindings.size());
- layoutInfo.pBindings = bindings.data();
- VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout));
-
- VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
- pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutCreateInfo.setLayoutCount = 1;
- pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
-
- VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
-
- const uint32_t shaderIndexRaygen = 0;
- const uint32_t shaderIndexMiss = 1;
- const uint32_t shaderIndexClosestHit = 2;
-
- std::array shaderStages;
- shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "nv_ray_tracing_basic/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_NV);
- shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "nv_ray_tracing_basic/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_NV);
- shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "nv_ray_tracing_basic/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV);
-
- /*
- Setup ray tracing shader groups
- */
- std::array groups{};
- for (auto& group : groups) {
- // Init all groups with some default values
- group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV;
- group.generalShader = VK_SHADER_UNUSED_NV;
- group.closestHitShader = VK_SHADER_UNUSED_NV;
- group.anyHitShader = VK_SHADER_UNUSED_NV;
- group.intersectionShader = VK_SHADER_UNUSED_NV;
- }
-
- // Links shaders and types to ray tracing shader groups
- groups[INDEX_RAYGEN].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
- groups[INDEX_RAYGEN].generalShader = shaderIndexRaygen;
- groups[INDEX_MISS].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
- groups[INDEX_MISS].generalShader = shaderIndexMiss;
- groups[INDEX_CLOSEST_HIT].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV;
- groups[INDEX_CLOSEST_HIT].generalShader = VK_SHADER_UNUSED_NV;
- groups[INDEX_CLOSEST_HIT].closestHitShader = shaderIndexClosestHit;
-
- VkRayTracingPipelineCreateInfoNV rayPipelineInfo{};
- rayPipelineInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV;
- rayPipelineInfo.stageCount = static_cast(shaderStages.size());
- rayPipelineInfo.pStages = shaderStages.data();
- rayPipelineInfo.groupCount = static_cast(groups.size());
- rayPipelineInfo.pGroups = groups.data();
- rayPipelineInfo.maxRecursionDepth = 1;
- rayPipelineInfo.layout = pipelineLayout;
- VK_CHECK_RESULT(vkCreateRayTracingPipelinesNV(device, VK_NULL_HANDLE, 1, &rayPipelineInfo, nullptr, &pipeline));
- }
-
- /*
- Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
- */
- void createUniformBuffer()
- {
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &ubo,
- sizeof(uniformData),
- &uniformData));
- VK_CHECK_RESULT(ubo.map());
-
- updateUniformBuffers();
- }
-
- /*
- Command buffer generation
- */
- void buildCommandBuffers()
- {
- VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
-
- VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
-
- for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
- {
- VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
-
- /*
- Dispatch the ray tracing commands
- */
- vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipeline);
- vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
-
- // Calculate shader binding offsets, which is pretty straight forward in our example
- VkDeviceSize bindingOffsetRayGenShader = rayTracingProperties.shaderGroupHandleSize * INDEX_RAYGEN;
- VkDeviceSize bindingOffsetMissShader = rayTracingProperties.shaderGroupHandleSize * INDEX_MISS;
- VkDeviceSize bindingOffsetHitShader = rayTracingProperties.shaderGroupHandleSize * INDEX_CLOSEST_HIT;
- VkDeviceSize bindingStride = rayTracingProperties.shaderGroupHandleSize;
-
- vkCmdTraceRaysNV(drawCmdBuffers[i],
- shaderBindingTable.buffer, bindingOffsetRayGenShader,
- shaderBindingTable.buffer, bindingOffsetMissShader, bindingStride,
- shaderBindingTable.buffer, bindingOffsetHitShader, bindingStride,
- VK_NULL_HANDLE, 0, 0,
- width, height, 1);
-
- /*
- Copy raytracing output to swap chain image
- */
-
- // Prepare current swapchain image as transfer destination
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- swapChain.images[i],
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- subresourceRange);
-
- // Prepare ray tracing output image as transfer source
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- storageImage.image,
- VK_IMAGE_LAYOUT_GENERAL,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- subresourceRange);
-
- VkImageCopy copyRegion{};
- copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.srcOffset = { 0, 0, 0 };
- copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.dstOffset = { 0, 0, 0 };
- copyRegion.extent = { width, height, 1 };
- vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
-
- // Transition swap chain image back for presentation
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- swapChain.images[i],
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- subresourceRange);
-
- // Transition ray tracing output image back to general layout
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- storageImage.image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_IMAGE_LAYOUT_GENERAL,
- subresourceRange);
-
- //@todo: Default render pass setup will overwrite contents
- //vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
- //drawUI(drawCmdBuffers[i]);
- //vkCmdEndRenderPass(drawCmdBuffers[i]);
-
- VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
- }
- }
-
- void updateUniformBuffers()
- {
- uniformData.projInverse = glm::inverse(camera.matrices.perspective);
- uniformData.viewInverse = glm::inverse(camera.matrices.view);
- memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
- }
-
- void prepare()
- {
- VulkanExampleBase::prepare();
-
- // Query the ray tracing properties of the current implementation, we will need them later on
- rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV;
- VkPhysicalDeviceProperties2 deviceProps2{};
- deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- deviceProps2.pNext = &rayTracingProperties;
- vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2);
-
- // Get VK_NV_ray_tracing related function pointers
- vkCreateAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureNV"));
- vkDestroyAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureNV"));
- vkBindAccelerationStructureMemoryNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryNV"));
- vkGetAccelerationStructureHandleNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureHandleNV"));
- vkGetAccelerationStructureMemoryRequirementsNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsNV"));
- vkCmdBuildAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV"));
- vkCreateRayTracingPipelinesNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesNV"));
- vkGetRayTracingShaderGroupHandlesNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesNV"));
- vkCmdTraceRaysNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysNV"));
-
- createScene();
- createStorageImage();
- createUniformBuffer();
- createRayTracingPipeline();
- createShaderBindingTable();
- createDescriptorSets();
- buildCommandBuffers();
- prepared = true;
- }
-
- void draw()
- {
- VulkanExampleBase::prepareFrame();
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
- VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
- VulkanExampleBase::submitFrame();
- }
-
- virtual void render()
- {
- if (!prepared)
- return;
- draw();
- if (camera.updated)
- updateUniformBuffers();
- }
-};
-
-VULKAN_EXAMPLE_MAIN()
diff --git a/examples/nv_ray_tracing_reflections/nv_ray_tracing_reflections.cpp b/examples/nv_ray_tracing_reflections/nv_ray_tracing_reflections.cpp
deleted file mode 100644
index 4d1a6f9f..00000000
--- a/examples/nv_ray_tracing_reflections/nv_ray_tracing_reflections.cpp
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
-* Vulkan Example - Advanced example for doing reflections with ray tracing using VK_NV_ray_tracing
-*
-* Renders a complex scene doing recursion inside the shaders for creating reflections
-*
-* Copyright (C) by Sascha Willems - www.saschawillems.de
-*
-* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-*/
-
-#include "vulkanexamplebase.h"
-#include "VulkanglTFModel.h"
-
-// Ray tracing acceleration structure
-struct AccelerationStructure {
- VkDeviceMemory memory;
- VkAccelerationStructureNV accelerationStructure;
- uint64_t handle;
-};
-
-// Ray tracing geometry instance
-struct GeometryInstance {
- glm::mat3x4 transform;
- uint32_t instanceId : 24;
- uint32_t mask : 8;
- uint32_t instanceOffset : 24;
- uint32_t flags : 8;
- uint64_t accelerationStructureHandle;
-};
-
-// Indices for the different ray tracing groups used in this example
-#define INDEX_RAYGEN 0
-#define INDEX_MISS 1
-#define INDEX_CLOSEST_HIT 2
-
-#define NUM_SHADER_GROUPS 3
-
-class VulkanExample : public VulkanExampleBase
-{
-public:
- PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV;
- PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV;
- PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV;
- PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV;
- PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV;
- PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV;
- PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV;
- PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV;
- PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV;
-
- VkPhysicalDeviceRayTracingPropertiesNV rayTracingProperties{};
-
- AccelerationStructure bottomLevelAS;
- AccelerationStructure topLevelAS;
-
- vks::Buffer shaderBindingTable;
-
- struct StorageImage {
- VkDeviceMemory memory;
- VkImage image;
- VkImageView view;
- VkFormat format;
- } storageImage;
-
- struct UniformData {
- glm::mat4 viewInverse;
- glm::mat4 projInverse;
- glm::vec4 lightPos;
- int32_t vertexSize;
- } uniformData;
- vks::Buffer ubo;
-
- VkPipeline pipeline;
- VkPipelineLayout pipelineLayout;
- VkDescriptorSet descriptorSet;
- VkDescriptorSetLayout descriptorSetLayout;
-
- vkglTF::Model scene;
-
- VulkanExample() : VulkanExampleBase()
- {
- title = "VK_NV_ray_tracing - Reflections";
- settings.overlay = false;
- timerSpeed *= 0.5f;
- camera.rotationSpeed *= 0.25f;
- camera.type = Camera::CameraType::firstperson;
- camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
- camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
- camera.setTranslation(glm::vec3(0.0f, 0.5f, -2.0f));
- // Enable instance and device extensions required to use VK_NV_ray_tracing
- enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
- enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
- enabledDeviceExtensions.push_back(VK_NV_RAY_TRACING_EXTENSION_NAME);
- }
-
- ~VulkanExample()
- {
- vkDestroyPipeline(device, pipeline, nullptr);
- vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
- vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
- vkDestroyImageView(device, storageImage.view, nullptr);
- vkDestroyImage(device, storageImage.image, nullptr);
- vkFreeMemory(device, storageImage.memory, nullptr);
- vkFreeMemory(device, bottomLevelAS.memory, nullptr);
- vkFreeMemory(device, topLevelAS.memory, nullptr);
- vkDestroyAccelerationStructureNV(device, bottomLevelAS.accelerationStructure, nullptr);
- vkDestroyAccelerationStructureNV(device, topLevelAS.accelerationStructure, nullptr);
- shaderBindingTable.destroy();
- ubo.destroy();
- }
-
- /*
- Set up a storage image that the ray generation shader will be writing to
- */
- void createStorageImage()
- {
- VkImageCreateInfo image = vks::initializers::imageCreateInfo();
- image.imageType = VK_IMAGE_TYPE_2D;
- image.format = swapChain.colorFormat;
- image.extent.width = width;
- image.extent.height = height;
- image.extent.depth = 1;
- image.mipLevels = 1;
- image.arrayLayers = 1;
- image.samples = VK_SAMPLE_COUNT_1_BIT;
- image.tiling = VK_IMAGE_TILING_OPTIMAL;
- image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
- image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &storageImage.image));
-
- VkMemoryRequirements memReqs;
- vkGetImageMemoryRequirements(device, storageImage.image, &memReqs);
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memReqs.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &storageImage.memory));
- VK_CHECK_RESULT(vkBindImageMemory(device, storageImage.image, storageImage.memory, 0));
-
- VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
- colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
- colorImageView.format = swapChain.colorFormat;
- colorImageView.subresourceRange = {};
- colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- colorImageView.subresourceRange.baseMipLevel = 0;
- colorImageView.subresourceRange.levelCount = 1;
- colorImageView.subresourceRange.baseArrayLayer = 0;
- colorImageView.subresourceRange.layerCount = 1;
- colorImageView.image = storageImage.image;
- VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &storageImage.view));
-
- VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
- vks::tools::setImageLayout(cmdBuffer, storageImage.image,
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_GENERAL,
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
- vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
- }
-
- /*
- The bottom level acceleration structure contains the scene's geometry (vertices, triangles)
- */
- void createBottomLevelAccelerationStructure(const VkGeometryNV* geometries)
- {
- VkAccelerationStructureInfoNV accelerationStructureInfo{};
- accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
- accelerationStructureInfo.instanceCount = 0;
- accelerationStructureInfo.geometryCount = 1;
- accelerationStructureInfo.pGeometries = geometries;
-
- VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
- accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
- accelerationStructureCI.info = accelerationStructureInfo;
- VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &bottomLevelAS.accelerationStructure));
-
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
- memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
-
- VkMemoryRequirements2 memoryRequirements2{};
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
-
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &bottomLevelAS.memory));
-
- VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
- accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
- accelerationStructureMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
- accelerationStructureMemoryInfo.memory = bottomLevelAS.memory;
- VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
-
- VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, bottomLevelAS.accelerationStructure, sizeof(uint64_t), &bottomLevelAS.handle));
- }
-
- /*
- The top level acceleration structure contains the scene's object instances
- */
- void createTopLevelAccelerationStructure()
- {
- VkAccelerationStructureInfoNV accelerationStructureInfo{};
- accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV;
- accelerationStructureInfo.instanceCount = 1;
- accelerationStructureInfo.geometryCount = 0;
-
- VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
- accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
- accelerationStructureCI.info = accelerationStructureInfo;
- VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &topLevelAS.accelerationStructure));
-
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
- memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
-
- VkMemoryRequirements2 memoryRequirements2{};
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
-
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &topLevelAS.memory));
-
- VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
- accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
- accelerationStructureMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure;
- accelerationStructureMemoryInfo.memory = topLevelAS.memory;
- VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
-
- VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, topLevelAS.accelerationStructure, sizeof(uint64_t), &topLevelAS.handle));
- }
-
- /*
- Create scene geometry and ray tracing acceleration structures
- */
- void createScene()
- {
- // Instead of a simple triangle, we'll be loading a more complex scene for this example
- // The shaders are accessing the vertex and index buffers of the scene, so the proper usage flag has to be set on the vertex and index buffers for the scene
- vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::PreMultiplyVertexColors | vkglTF::FileLoadingFlags::FlipY;
- scene.loadFromFile(getAssetPath() + "models/reflection_scene.gltf", vulkanDevice, queue, glTFLoadingFlags);
-
- /*
- Create the bottom level acceleration structure containing the actual scene geometry
- */
- VkGeometryNV geometry{};
- geometry.sType = VK_STRUCTURE_TYPE_GEOMETRY_NV;
- geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_NV;
- geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV;
- geometry.geometry.triangles.vertexData = scene.vertices.buffer;
- geometry.geometry.triangles.vertexOffset = 0;
- geometry.geometry.triangles.vertexCount = static_cast(scene.vertices.count);
- geometry.geometry.triangles.vertexStride = sizeof(vkglTF::Vertex);
- geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
- geometry.geometry.triangles.indexData = scene.indices.buffer;
- geometry.geometry.triangles.indexOffset = 0;
- geometry.geometry.triangles.indexCount = scene.indices.count;
- geometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
- geometry.geometry.triangles.transformData = VK_NULL_HANDLE;
- geometry.geometry.triangles.transformOffset = 0;
- geometry.geometry.aabbs = {};
- geometry.geometry.aabbs.sType = { VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV };
- geometry.flags = VK_GEOMETRY_OPAQUE_BIT_NV;
-
- createBottomLevelAccelerationStructure(&geometry);
-
- /*
- Create the top-level acceleration structure that contains geometry instance information
- */
-
- // Single instance with a 3x4 transform matrix for the ray traced triangle
- vks::Buffer instanceBuffer;
-
- glm::mat3x4 transform = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- };
-
- GeometryInstance geometryInstance{};
- geometryInstance.transform = transform;
- geometryInstance.instanceId = 0;
- geometryInstance.mask = 0xff;
- geometryInstance.instanceOffset = 0;
- geometryInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV;
- geometryInstance.accelerationStructureHandle = bottomLevelAS.handle;
-
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &instanceBuffer,
- sizeof(GeometryInstance),
- &geometryInstance));
-
- createTopLevelAccelerationStructure();
-
- /*
- Build the acceleration structure
- */
-
- // Acceleration structure build requires some scratch space to store temporary information
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV;
-
- VkMemoryRequirements2 memReqBottomLevelAS;
- memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqBottomLevelAS);
-
- VkMemoryRequirements2 memReqTopLevelAS;
- memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqTopLevelAS);
-
- const VkDeviceSize scratchBufferSize = std::max(memReqBottomLevelAS.memoryRequirements.size, memReqTopLevelAS.memoryRequirements.size);
-
- vks::Buffer scratchBuffer;
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
- &scratchBuffer,
- scratchBufferSize));
-
- VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
-
- /*
- Build bottom level acceleration structure
- */
- VkAccelerationStructureInfoNV buildInfo{};
- buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
- buildInfo.geometryCount = 1;
- buildInfo.pGeometries = &geometry;
-
- vkCmdBuildAccelerationStructureNV(
- cmdBuffer,
- &buildInfo,
- VK_NULL_HANDLE,
- 0,
- VK_FALSE,
- bottomLevelAS.accelerationStructure,
- VK_NULL_HANDLE,
- scratchBuffer.buffer,
- 0);
-
- VkMemoryBarrier memoryBarrier = vks::initializers::memoryBarrier();
- memoryBarrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
- memoryBarrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
- vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
-
- /*
- Build top-level acceleration structure
- */
- buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV;
- buildInfo.pGeometries = 0;
- buildInfo.geometryCount = 0;
- buildInfo.instanceCount = 1;
-
- vkCmdBuildAccelerationStructureNV(
- cmdBuffer,
- &buildInfo,
- instanceBuffer.buffer,
- 0,
- VK_FALSE,
- topLevelAS.accelerationStructure,
- VK_NULL_HANDLE,
- scratchBuffer.buffer,
- 0);
-
- vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
-
- vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
-
- scratchBuffer.destroy();
- instanceBuffer.destroy();
- }
-
- VkDeviceSize copyShaderIdentifier(uint8_t* data, const uint8_t* shaderHandleStorage, uint32_t groupIndex) {
- const uint32_t shaderGroupHandleSize = rayTracingProperties.shaderGroupHandleSize;
- memcpy(data, shaderHandleStorage + groupIndex * shaderGroupHandleSize, shaderGroupHandleSize);
- return shaderGroupHandleSize;
- }
-
- /*
- Create the Shader Binding Table that binds the programs and top-level acceleration structure
- */
- void createShaderBindingTable() {
- // Create buffer for the shader binding table
- const uint32_t sbtSize = rayTracingProperties.shaderGroupHandleSize * NUM_SHADER_GROUPS;
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
- &shaderBindingTable,
- sbtSize));
- shaderBindingTable.map();
-
- auto shaderHandleStorage = new uint8_t[sbtSize];
- // Get shader identifiers
- VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesNV(device, pipeline, 0, NUM_SHADER_GROUPS, sbtSize, shaderHandleStorage));
- auto* data = static_cast(shaderBindingTable.mapped);
- // Copy the shader identifiers to the shader binding table
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_RAYGEN);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_MISS);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_CLOSEST_HIT);
- shaderBindingTable.unmap();
- }
-
- /*
- Create the descriptor sets used for the ray tracing dispatch
- */
- void createDescriptorSets()
- {
- std::vector poolSizes = {
- { VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1 },
- { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
- { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2 }
- };
- VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
- VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
-
- VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
- VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
-
- VkWriteDescriptorSetAccelerationStructureNV descriptorAccelerationStructureInfo{};
- descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV;
- descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
- descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure;
-
- VkWriteDescriptorSet accelerationStructureWrite{};
- accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- // The specialized acceleration structure descriptor has to be chained
- accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
- accelerationStructureWrite.dstSet = descriptorSet;
- accelerationStructureWrite.dstBinding = 0;
- accelerationStructureWrite.descriptorCount = 1;
- accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
-
- VkDescriptorImageInfo storageImageDescriptor{};
- storageImageDescriptor.imageView = storageImage.view;
- storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
- VkDescriptorBufferInfo vertexBufferDescriptor{};
- vertexBufferDescriptor.buffer = scene.vertices.buffer;
- vertexBufferDescriptor.range = VK_WHOLE_SIZE;
-
- VkDescriptorBufferInfo indexBufferDescriptor{};
- indexBufferDescriptor.buffer = scene.indices.buffer;
- indexBufferDescriptor.range = VK_WHOLE_SIZE;
-
- VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
- VkWriteDescriptorSet uniformBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor);
- VkWriteDescriptorSet vertexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor);
- VkWriteDescriptorSet indexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor);
-
- std::vector writeDescriptorSets = {
- accelerationStructureWrite,
- resultImageWrite,
- uniformBufferWrite,
- vertexBufferWrite,
- indexBufferWrite
- };
- vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
- }
-
- /*
- Create our ray tracing pipeline
- */
- void createRayTracingPipeline()
- {
- VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding{};
- accelerationStructureLayoutBinding.binding = 0;
- accelerationStructureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
- accelerationStructureLayoutBinding.descriptorCount = 1;
- accelerationStructureLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV | VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
-
- VkDescriptorSetLayoutBinding resultImageLayoutBinding{};
- resultImageLayoutBinding.binding = 1;
- resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- resultImageLayoutBinding.descriptorCount = 1;
- resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
-
- VkDescriptorSetLayoutBinding uniformBufferBinding{};
- uniformBufferBinding.binding = 2;
- uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uniformBufferBinding.descriptorCount = 1;
- uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV | VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV | VK_SHADER_STAGE_MISS_BIT_NV;
-
- VkDescriptorSetLayoutBinding vertexBufferBinding{};
- vertexBufferBinding.binding = 3;
- vertexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- vertexBufferBinding.descriptorCount = 1;
- vertexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
-
- VkDescriptorSetLayoutBinding indexBufferBinding{};
- indexBufferBinding.binding = 4;
- indexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- indexBufferBinding.descriptorCount = 1;
- indexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
-
- std::vector bindings({
- accelerationStructureLayoutBinding,
- resultImageLayoutBinding,
- uniformBufferBinding,
- vertexBufferBinding,
- indexBufferBinding
- });
-
- VkDescriptorSetLayoutCreateInfo layoutInfo{};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = static_cast(bindings.size());
- layoutInfo.pBindings = bindings.data();
- VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout));
-
- VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
- pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutCreateInfo.setLayoutCount = 1;
- pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
-
- VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
-
- const uint32_t shaderIndexRaygen = 0;
- const uint32_t shaderIndexMiss = 1;
- const uint32_t shaderIndexClosestHit = 2;
-
- std::array shaderStages;
- shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "nv_ray_tracing_reflections/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_NV);
- shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "nv_ray_tracing_reflections/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_NV);
- shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "nv_ray_tracing_reflections/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV);
-
- // Pass recursion depth for reflections to ray generation shader via specialization constant
- VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t));
- uint32_t maxRecursion = 4;
- VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(maxRecursion), &maxRecursion);
- shaderStages[shaderIndexRaygen].pSpecializationInfo = &specializationInfo;
-
- /*
- Setup ray tracing shader groups
- */
- std::array groups{};
- for (auto& group : groups) {
- // Init all groups with some default values
- group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV;
- group.generalShader = VK_SHADER_UNUSED_NV;
- group.closestHitShader = VK_SHADER_UNUSED_NV;
- group.anyHitShader = VK_SHADER_UNUSED_NV;
- group.intersectionShader = VK_SHADER_UNUSED_NV;
- }
-
- // Links shaders and types to ray tracing shader groups
- // Ray generation shader group
- groups[INDEX_RAYGEN].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
- groups[INDEX_RAYGEN].generalShader = shaderIndexRaygen;
- // Scene miss shader group
- groups[INDEX_MISS].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
- groups[INDEX_MISS].generalShader = shaderIndexMiss;
- // Scene closest hit shader group
- groups[INDEX_CLOSEST_HIT].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV;
- groups[INDEX_CLOSEST_HIT].generalShader = VK_SHADER_UNUSED_NV;
- groups[INDEX_CLOSEST_HIT].closestHitShader = shaderIndexClosestHit;
-
- VkRayTracingPipelineCreateInfoNV rayPipelineInfo{};
- rayPipelineInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV;
- rayPipelineInfo.stageCount = static_cast(shaderStages.size());
- rayPipelineInfo.pStages = shaderStages.data();
- rayPipelineInfo.groupCount = static_cast(groups.size());
- rayPipelineInfo.pGroups = groups.data();
- rayPipelineInfo.maxRecursionDepth = 1;
- rayPipelineInfo.layout = pipelineLayout;
- VK_CHECK_RESULT(vkCreateRayTracingPipelinesNV(device, VK_NULL_HANDLE, 1, &rayPipelineInfo, nullptr, &pipeline));
- }
-
- /*
- Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
- */
- void createUniformBuffer()
- {
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &ubo,
- sizeof(uniformData),
- &uniformData));
- VK_CHECK_RESULT(ubo.map());
-
- updateUniformBuffers();
- }
-
- /*
- Command buffer generation
- */
- void buildCommandBuffers()
- {
- VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
-
- VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
-
- for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
- {
- VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
-
- /*
- Dispatch the ray tracing commands
- */
- vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipeline);
- vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
-
- // Calculate shader binding offsets, which is pretty straight forward in our example
- VkDeviceSize bindingOffsetRayGenShader = rayTracingProperties.shaderGroupHandleSize * INDEX_RAYGEN;
- VkDeviceSize bindingOffsetMissShader = rayTracingProperties.shaderGroupHandleSize * INDEX_MISS;
- VkDeviceSize bindingOffsetHitShader = rayTracingProperties.shaderGroupHandleSize * INDEX_CLOSEST_HIT;
- VkDeviceSize bindingStride = rayTracingProperties.shaderGroupHandleSize;
-
- vkCmdTraceRaysNV(drawCmdBuffers[i],
- shaderBindingTable.buffer, bindingOffsetRayGenShader,
- shaderBindingTable.buffer, bindingOffsetMissShader, bindingStride,
- shaderBindingTable.buffer, bindingOffsetHitShader, bindingStride,
- VK_NULL_HANDLE, 0, 0,
- width, height, 1);
-
- /*
- Copy raytracing output to swap chain image
- */
-
- // Prepare current swapchain image as transfer destination
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- swapChain.images[i],
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- subresourceRange);
-
- // Prepare ray tracing output image as transfer source
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- storageImage.image,
- VK_IMAGE_LAYOUT_GENERAL,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- subresourceRange);
-
- VkImageCopy copyRegion{};
- copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.srcOffset = { 0, 0, 0 };
- copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.dstOffset = { 0, 0, 0 };
- copyRegion.extent = { width, height, 1 };
- vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
-
- // Transition swap chain image back for presentation
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- swapChain.images[i],
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- subresourceRange);
-
- // Transition ray tracing output image back to general layout
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- storageImage.image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_IMAGE_LAYOUT_GENERAL,
- subresourceRange);
-
- //@todo: Default render pass setup will overwrite contents
- //vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
- //drawUI(drawCmdBuffers[i]);
- //vkCmdEndRenderPass(drawCmdBuffers[i]);
-
- VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
- }
- }
-
- void updateUniformBuffers()
- {
- uniformData.projInverse = glm::inverse(camera.matrices.perspective);
- uniformData.viewInverse = glm::inverse(camera.matrices.view);
- uniformData.lightPos = glm::vec4(cos(glm::radians(timer * 360.0f)) * 40.0f, -20.0f + sin(glm::radians(timer * 360.0f)) * 20.0f, 25.0f + sin(glm::radians(timer * 360.0f)) * 5.0f, 0.0f);
- // Pass the vertex size to the shader for unpacking vertices
- uniformData.vertexSize = sizeof(vkglTF::Vertex);
- memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
- }
-
- void prepare()
- {
- VulkanExampleBase::prepare();
-
- // Query the ray tracing properties of the current implementation, we will need them later on
- rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV;
- VkPhysicalDeviceProperties2 deviceProps2{};
- deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- deviceProps2.pNext = &rayTracingProperties;
- vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2);
-
- // Get VK_NV_ray_tracing related function pointers
- vkCreateAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureNV"));
- vkDestroyAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureNV"));
- vkBindAccelerationStructureMemoryNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryNV"));
- vkGetAccelerationStructureHandleNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureHandleNV"));
- vkGetAccelerationStructureMemoryRequirementsNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsNV"));
- vkCmdBuildAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV"));
- vkCreateRayTracingPipelinesNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesNV"));
- vkGetRayTracingShaderGroupHandlesNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesNV"));
- vkCmdTraceRaysNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysNV"));
-
- createScene();
- createStorageImage();
- createUniformBuffer();
- createRayTracingPipeline();
- createShaderBindingTable();
- createDescriptorSets();
- buildCommandBuffers();
- prepared = true;
- }
-
- void draw()
- {
- VulkanExampleBase::prepareFrame();
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
- VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
- VulkanExampleBase::submitFrame();
- }
-
- virtual void render()
- {
- if (!prepared)
- return;
- draw();
- if (!paused || camera.updated)
- updateUniformBuffers();
- }
-};
-
-VULKAN_EXAMPLE_MAIN()
diff --git a/examples/nv_ray_tracing_shadows/nv_ray_tracing_shadows.cpp b/examples/nv_ray_tracing_shadows/nv_ray_tracing_shadows.cpp
deleted file mode 100644
index 7ea2c510..00000000
--- a/examples/nv_ray_tracing_shadows/nv_ray_tracing_shadows.cpp
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
-* Vulkan Example - Advanced example for ray tracing using VK_NV_ray_tracing
-*
-* Renders a complex scene using multiple hit and miss shaders for implementing shadows
-*
-* Copyright (C) by Sascha Willems - www.saschawillems.de
-*
-* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-*/
-
-#include "vulkanexamplebase.h"
-#include "VulkanglTFModel.h"
-
-// Ray tracing acceleration structure
-struct AccelerationStructure {
- VkDeviceMemory memory;
- VkAccelerationStructureNV accelerationStructure;
- uint64_t handle;
-};
-
-// Ray tracing geometry instance
-struct GeometryInstance {
- glm::mat3x4 transform;
- uint32_t instanceId : 24;
- uint32_t mask : 8;
- uint32_t instanceOffset : 24;
- uint32_t flags : 8;
- uint64_t accelerationStructureHandle;
-};
-
-// Indices for the different ray tracing groups used in this example
-#define INDEX_RAYGEN 0
-#define INDEX_MISS 1
-#define INDEX_SHADOW_MISS 2
-#define INDEX_CLOSEST_HIT 3
-#define INDEX_SHADOW_HIT 4
-
-#define NUM_SHADER_GROUPS 5
-
-class VulkanExample : public VulkanExampleBase
-{
-public:
- PFN_vkCreateAccelerationStructureNV vkCreateAccelerationStructureNV;
- PFN_vkDestroyAccelerationStructureNV vkDestroyAccelerationStructureNV;
- PFN_vkBindAccelerationStructureMemoryNV vkBindAccelerationStructureMemoryNV;
- PFN_vkGetAccelerationStructureHandleNV vkGetAccelerationStructureHandleNV;
- PFN_vkGetAccelerationStructureMemoryRequirementsNV vkGetAccelerationStructureMemoryRequirementsNV;
- PFN_vkCmdBuildAccelerationStructureNV vkCmdBuildAccelerationStructureNV;
- PFN_vkCreateRayTracingPipelinesNV vkCreateRayTracingPipelinesNV;
- PFN_vkGetRayTracingShaderGroupHandlesNV vkGetRayTracingShaderGroupHandlesNV;
- PFN_vkCmdTraceRaysNV vkCmdTraceRaysNV;
-
- VkPhysicalDeviceRayTracingPropertiesNV rayTracingProperties{};
-
- AccelerationStructure bottomLevelAS;
- AccelerationStructure topLevelAS;
-
- vks::Buffer shaderBindingTable;
-
- struct StorageImage {
- VkDeviceMemory memory;
- VkImage image;
- VkImageView view;
- VkFormat format;
- } storageImage;
-
- struct UniformData {
- glm::mat4 viewInverse;
- glm::mat4 projInverse;
- glm::vec4 lightPos;
- int32_t vertexSize;
- } uniformData;
- vks::Buffer ubo;
-
- VkPipeline pipeline;
- VkPipelineLayout pipelineLayout;
- VkDescriptorSet descriptorSet;
- VkDescriptorSetLayout descriptorSetLayout;
-
- vkglTF::Model scene;
-
- VulkanExample() : VulkanExampleBase()
- {
- title = "Shadows with VK_NV_ray_tracing";
- settings.overlay = false;
- timerSpeed *= 0.25f;
- camera.type = Camera::CameraType::lookat;
- camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
- camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
- camera.setTranslation(glm::vec3(0.0f, 3.0f, -10.0f));
- // Enable instance and device extensions required to use VK_NV_ray_tracing
- enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
- enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
- enabledDeviceExtensions.push_back(VK_NV_RAY_TRACING_EXTENSION_NAME);
- }
-
- ~VulkanExample()
- {
- vkDestroyPipeline(device, pipeline, nullptr);
- vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
- vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
- vkDestroyImageView(device, storageImage.view, nullptr);
- vkDestroyImage(device, storageImage.image, nullptr);
- vkFreeMemory(device, storageImage.memory, nullptr);
- vkFreeMemory(device, bottomLevelAS.memory, nullptr);
- vkFreeMemory(device, topLevelAS.memory, nullptr);
- vkDestroyAccelerationStructureNV(device, bottomLevelAS.accelerationStructure, nullptr);
- vkDestroyAccelerationStructureNV(device, topLevelAS.accelerationStructure, nullptr);
- shaderBindingTable.destroy();
- ubo.destroy();
- }
-
- /*
- Set up a storage image that the ray generation shader will be writing to
- */
- void createStorageImage()
- {
- VkImageCreateInfo image = vks::initializers::imageCreateInfo();
- image.imageType = VK_IMAGE_TYPE_2D;
- image.format = swapChain.colorFormat;
- image.extent.width = width;
- image.extent.height = height;
- image.extent.depth = 1;
- image.mipLevels = 1;
- image.arrayLayers = 1;
- image.samples = VK_SAMPLE_COUNT_1_BIT;
- image.tiling = VK_IMAGE_TILING_OPTIMAL;
- image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
- image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &storageImage.image));
-
- VkMemoryRequirements memReqs;
- vkGetImageMemoryRequirements(device, storageImage.image, &memReqs);
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memReqs.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &storageImage.memory));
- VK_CHECK_RESULT(vkBindImageMemory(device, storageImage.image, storageImage.memory, 0));
-
- VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
- colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
- colorImageView.format = swapChain.colorFormat;
- colorImageView.subresourceRange = {};
- colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- colorImageView.subresourceRange.baseMipLevel = 0;
- colorImageView.subresourceRange.levelCount = 1;
- colorImageView.subresourceRange.baseArrayLayer = 0;
- colorImageView.subresourceRange.layerCount = 1;
- colorImageView.image = storageImage.image;
- VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &storageImage.view));
-
- VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
- vks::tools::setImageLayout(cmdBuffer, storageImage.image,
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_GENERAL,
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
- vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
- }
-
- /*
- The bottom level acceleration structure contains the scene's geometry (vertices, triangles)
- */
- void createBottomLevelAccelerationStructure(const VkGeometryNV* geometries)
- {
- VkAccelerationStructureInfoNV accelerationStructureInfo{};
- accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
- accelerationStructureInfo.instanceCount = 0;
- accelerationStructureInfo.geometryCount = 1;
- accelerationStructureInfo.pGeometries = geometries;
-
- VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
- accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
- accelerationStructureCI.info = accelerationStructureInfo;
- VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &bottomLevelAS.accelerationStructure));
-
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
- memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
-
- VkMemoryRequirements2 memoryRequirements2{};
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
-
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &bottomLevelAS.memory));
-
- VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
- accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
- accelerationStructureMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
- accelerationStructureMemoryInfo.memory = bottomLevelAS.memory;
- VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
-
- VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, bottomLevelAS.accelerationStructure, sizeof(uint64_t), &bottomLevelAS.handle));
- }
-
- /*
- The top level acceleration structure contains the scene's object instances
- */
- void createTopLevelAccelerationStructure()
- {
- VkAccelerationStructureInfoNV accelerationStructureInfo{};
- accelerationStructureInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- accelerationStructureInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV;
- accelerationStructureInfo.instanceCount = 1;
- accelerationStructureInfo.geometryCount = 0;
-
- VkAccelerationStructureCreateInfoNV accelerationStructureCI{};
- accelerationStructureCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV;
- accelerationStructureCI.info = accelerationStructureInfo;
- VK_CHECK_RESULT(vkCreateAccelerationStructureNV(device, &accelerationStructureCI, nullptr, &topLevelAS.accelerationStructure));
-
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV;
- memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
-
- VkMemoryRequirements2 memoryRequirements2{};
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memoryRequirements2);
-
- VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
- memoryAllocateInfo.allocationSize = memoryRequirements2.memoryRequirements.size;
- memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &topLevelAS.memory));
-
- VkBindAccelerationStructureMemoryInfoNV accelerationStructureMemoryInfo{};
- accelerationStructureMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV;
- accelerationStructureMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure;
- accelerationStructureMemoryInfo.memory = topLevelAS.memory;
- VK_CHECK_RESULT(vkBindAccelerationStructureMemoryNV(device, 1, &accelerationStructureMemoryInfo));
-
- VK_CHECK_RESULT(vkGetAccelerationStructureHandleNV(device, topLevelAS.accelerationStructure, sizeof(uint64_t), &topLevelAS.handle));
- }
-
- /*
- Create scene geometry and ray tracing acceleration structures
- */
- void createScene()
- {
- // Instead of a simple triangle, we'll be loading a more complex scene for this example
- // The shaders are accessing the vertex and index buffers of the scene, so the proper usage flag has to be set on the vertex and index buffers for the scene
- vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::PreMultiplyVertexColors | vkglTF::FileLoadingFlags::FlipY;
- scene.loadFromFile(getAssetPath() + "models/vulkanscene_shadow.gltf", vulkanDevice, queue, glTFLoadingFlags);
-
- /*
- Create the bottom level acceleration structure containing the actual scene geometry
- */
- VkGeometryNV geometry{};
- geometry.sType = VK_STRUCTURE_TYPE_GEOMETRY_NV;
- geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_NV;
- geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV;
- geometry.geometry.triangles.vertexData = scene.vertices.buffer;
- geometry.geometry.triangles.vertexOffset = 0;
- geometry.geometry.triangles.vertexCount = static_cast(scene.vertices.count);
- geometry.geometry.triangles.vertexStride = sizeof(vkglTF::Vertex);
- geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
- geometry.geometry.triangles.indexData = scene.indices.buffer;
- geometry.geometry.triangles.indexOffset = 0;
- geometry.geometry.triangles.indexCount = scene.indices.count;
- geometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
- geometry.geometry.triangles.transformData = VK_NULL_HANDLE;
- geometry.geometry.triangles.transformOffset = 0;
- geometry.geometry.aabbs = {};
- geometry.geometry.aabbs.sType = { VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV };
- geometry.flags = VK_GEOMETRY_OPAQUE_BIT_NV;
-
- createBottomLevelAccelerationStructure(&geometry);
-
- /*
- Create the top-level acceleration structure that contains geometry instance information
- */
-
- // Single instance with a 3x4 transform matrix for the ray traced triangle
- vks::Buffer instanceBuffer;
-
- glm::mat3x4 transform = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- };
-
- std::array geometryInstances{};
- // First geometry instance is used for the scene hit and miss shaders
- geometryInstances[0].transform = transform;
- geometryInstances[0].instanceId = 0;
- geometryInstances[0].mask = 0xff;
- geometryInstances[0].instanceOffset = 0;
- geometryInstances[0].flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV;
- geometryInstances[0].accelerationStructureHandle = bottomLevelAS.handle;
- // Second geometry instance is used for the shadow hit and miss shaders
- geometryInstances[1].transform = transform;
- geometryInstances[1].instanceId = 1;
- geometryInstances[1].mask = 0xff;
- geometryInstances[1].instanceOffset = 2;
- geometryInstances[1].flags = VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV;
- geometryInstances[1].accelerationStructureHandle = bottomLevelAS.handle;
-
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &instanceBuffer,
- sizeof(GeometryInstance) * geometryInstances.size(),
- geometryInstances.data()));
-
- createTopLevelAccelerationStructure();
-
- /*
- Build the acceleration structure
- */
-
- // Acceleration structure build requires some scratch space to store temporary information
- VkAccelerationStructureMemoryRequirementsInfoNV memoryRequirementsInfo{};
- memoryRequirementsInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV;
- memoryRequirementsInfo.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV;
-
- VkMemoryRequirements2 memReqBottomLevelAS;
- memoryRequirementsInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqBottomLevelAS);
-
- VkMemoryRequirements2 memReqTopLevelAS;
- memoryRequirementsInfo.accelerationStructure = topLevelAS.accelerationStructure;
- vkGetAccelerationStructureMemoryRequirementsNV(device, &memoryRequirementsInfo, &memReqTopLevelAS);
-
- const VkDeviceSize scratchBufferSize = std::max(memReqBottomLevelAS.memoryRequirements.size, memReqTopLevelAS.memoryRequirements.size);
-
- vks::Buffer scratchBuffer;
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
- &scratchBuffer,
- scratchBufferSize));
-
- VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
-
- /*
- Build bottom level acceleration structure
- */
- VkAccelerationStructureInfoNV buildInfo{};
- buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV;
- buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV;
- buildInfo.geometryCount = 1;
- buildInfo.pGeometries = &geometry;
-
- vkCmdBuildAccelerationStructureNV(
- cmdBuffer,
- &buildInfo,
- VK_NULL_HANDLE,
- 0,
- VK_FALSE,
- bottomLevelAS.accelerationStructure,
- VK_NULL_HANDLE,
- scratchBuffer.buffer,
- 0);
-
- VkMemoryBarrier memoryBarrier = vks::initializers::memoryBarrier();
- memoryBarrier.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
- memoryBarrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV | VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV;
- vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
-
- /*
- Build top-level acceleration structure
- */
- buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV;
- buildInfo.pGeometries = 0;
- buildInfo.geometryCount = 0;
- buildInfo.instanceCount = 1;
-
- vkCmdBuildAccelerationStructureNV(
- cmdBuffer,
- &buildInfo,
- instanceBuffer.buffer,
- 0,
- VK_FALSE,
- topLevelAS.accelerationStructure,
- VK_NULL_HANDLE,
- scratchBuffer.buffer,
- 0);
-
- vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV, 0, 1, &memoryBarrier, 0, 0, 0, 0);
-
- vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
-
- scratchBuffer.destroy();
- instanceBuffer.destroy();
- }
-
- VkDeviceSize copyShaderIdentifier(uint8_t* data, const uint8_t* shaderHandleStorage, uint32_t groupIndex) {
- const uint32_t shaderGroupHandleSize = rayTracingProperties.shaderGroupHandleSize;
- memcpy(data, shaderHandleStorage + groupIndex * shaderGroupHandleSize, shaderGroupHandleSize);
- return shaderGroupHandleSize;
- }
-
- /*
- Create the Shader Binding Table that binds the programs and top-level acceleration structure
- */
- void createShaderBindingTable() {
- // Create buffer for the shader binding table
- const uint32_t sbtSize = rayTracingProperties.shaderGroupHandleSize * NUM_SHADER_GROUPS;
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
- &shaderBindingTable,
- sbtSize));
- shaderBindingTable.map();
-
- auto shaderHandleStorage = new uint8_t[sbtSize];
- // Get shader identifiers
- VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesNV(device, pipeline, 0, NUM_SHADER_GROUPS, sbtSize, shaderHandleStorage));
- auto* data = static_cast(shaderBindingTable.mapped);
- // Copy the shader identifiers to the shader binding table
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_RAYGEN);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_MISS);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_SHADOW_MISS);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_CLOSEST_HIT);
- data += copyShaderIdentifier(data, shaderHandleStorage, INDEX_SHADOW_HIT);
- shaderBindingTable.unmap();
- }
-
- /*
- Create the descriptor sets used for the ray tracing dispatch
- */
- void createDescriptorSets()
- {
- std::vector poolSizes = {
- { VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV, 1 },
- { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
- { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2 }
- };
- VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
- VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
-
- VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
- VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
-
- VkWriteDescriptorSetAccelerationStructureNV descriptorAccelerationStructureInfo{};
- descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV;
- descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
- descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure;
-
- VkWriteDescriptorSet accelerationStructureWrite{};
- accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- // The specialized acceleration structure descriptor has to be chained
- accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
- accelerationStructureWrite.dstSet = descriptorSet;
- accelerationStructureWrite.dstBinding = 0;
- accelerationStructureWrite.descriptorCount = 1;
- accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
-
- VkDescriptorImageInfo storageImageDescriptor{};
- storageImageDescriptor.imageView = storageImage.view;
- storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
- VkDescriptorBufferInfo vertexBufferDescriptor{};
- vertexBufferDescriptor.buffer = scene.vertices.buffer;
- vertexBufferDescriptor.range = VK_WHOLE_SIZE;
-
- VkDescriptorBufferInfo indexBufferDescriptor{};
- indexBufferDescriptor.buffer = scene.indices.buffer;
- indexBufferDescriptor.range = VK_WHOLE_SIZE;
-
- VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
- VkWriteDescriptorSet uniformBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor);
- VkWriteDescriptorSet vertexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor);
- VkWriteDescriptorSet indexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor);
-
- std::vector writeDescriptorSets = {
- accelerationStructureWrite,
- resultImageWrite,
- uniformBufferWrite,
- vertexBufferWrite,
- indexBufferWrite
- };
- vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
- }
-
- /*
- Create our ray tracing pipeline
- */
- void createRayTracingPipeline()
- {
- VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding{};
- accelerationStructureLayoutBinding.binding = 0;
- accelerationStructureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV;
- accelerationStructureLayoutBinding.descriptorCount = 1;
- accelerationStructureLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV | VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
-
- VkDescriptorSetLayoutBinding resultImageLayoutBinding{};
- resultImageLayoutBinding.binding = 1;
- resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- resultImageLayoutBinding.descriptorCount = 1;
- resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV;
-
- VkDescriptorSetLayoutBinding uniformBufferBinding{};
- uniformBufferBinding.binding = 2;
- uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uniformBufferBinding.descriptorCount = 1;
- uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_NV | VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
-
- VkDescriptorSetLayoutBinding vertexBufferBinding{};
- vertexBufferBinding.binding = 3;
- vertexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- vertexBufferBinding.descriptorCount = 1;
- vertexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
-
- VkDescriptorSetLayoutBinding indexBufferBinding{};
- indexBufferBinding.binding = 4;
- indexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- indexBufferBinding.descriptorCount = 1;
- indexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
-
- std::vector bindings({
- accelerationStructureLayoutBinding,
- resultImageLayoutBinding,
- uniformBufferBinding,
- vertexBufferBinding,
- indexBufferBinding
- });
-
- VkDescriptorSetLayoutCreateInfo layoutInfo{};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = static_cast(bindings.size());
- layoutInfo.pBindings = bindings.data();
- VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout));
-
- VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
- pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutCreateInfo.setLayoutCount = 1;
- pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
-
- VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
-
- const uint32_t shaderIndexRaygen = 0;
- const uint32_t shaderIndexMiss = 1;
- const uint32_t shaderIndexShadowMiss = 2;
- const uint32_t shaderIndexClosestHit = 3;
-
- std::array shaderStages;
- shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "nv_ray_tracing_shadows/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_NV);
- shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "nv_ray_tracing_shadows/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_NV);
- shaderStages[shaderIndexShadowMiss] = loadShader(getShadersPath() + "nv_ray_tracing_shadows/shadow.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_NV);
- shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "nv_ray_tracing_shadows/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV);
-
- /*
- Setup ray tracing shader groups
- */
- std::array groups{};
- for (auto& group : groups) {
- // Init all groups with some default values
- group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV;
- group.generalShader = VK_SHADER_UNUSED_NV;
- group.closestHitShader = VK_SHADER_UNUSED_NV;
- group.anyHitShader = VK_SHADER_UNUSED_NV;
- group.intersectionShader = VK_SHADER_UNUSED_NV;
- }
-
- // Links shaders and types to ray tracing shader groups
- // Ray generation shader group
- groups[INDEX_RAYGEN].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
- groups[INDEX_RAYGEN].generalShader = shaderIndexRaygen;
- // Scene miss shader group
- groups[INDEX_MISS].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
- groups[INDEX_MISS].generalShader = shaderIndexMiss;
- // Shadow miss shader group
- groups[INDEX_SHADOW_MISS].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
- groups[INDEX_SHADOW_MISS].generalShader = shaderIndexShadowMiss;
- // Scene closest hit shader group
- groups[INDEX_CLOSEST_HIT].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV;
- groups[INDEX_CLOSEST_HIT].generalShader = VK_SHADER_UNUSED_NV;
- groups[INDEX_CLOSEST_HIT].closestHitShader = shaderIndexClosestHit;
- // Shadow closest hit shader group
- groups[INDEX_SHADOW_HIT].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV;
- groups[INDEX_SHADOW_HIT].generalShader = VK_SHADER_UNUSED_NV;
- // Reuse shadow miss shader
- groups[INDEX_SHADOW_HIT].closestHitShader = shaderIndexShadowMiss;
-
- VkRayTracingPipelineCreateInfoNV rayPipelineInfo{};
- rayPipelineInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV;
- rayPipelineInfo.stageCount = static_cast(shaderStages.size());
- rayPipelineInfo.pStages = shaderStages.data();
- rayPipelineInfo.groupCount = static_cast(groups.size());
- rayPipelineInfo.pGroups = groups.data();
- rayPipelineInfo.maxRecursionDepth = 2;
- rayPipelineInfo.layout = pipelineLayout;
- VK_CHECK_RESULT(vkCreateRayTracingPipelinesNV(device, VK_NULL_HANDLE, 1, &rayPipelineInfo, nullptr, &pipeline));
- }
-
- /*
- Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
- */
- void createUniformBuffer()
- {
- VK_CHECK_RESULT(vulkanDevice->createBuffer(
- VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- &ubo,
- sizeof(uniformData),
- &uniformData));
- VK_CHECK_RESULT(ubo.map());
-
- updateUniformBuffers();
- }
-
- /*
- Command buffer generation
- */
- void buildCommandBuffers()
- {
- VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
-
- VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
-
- for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
- {
- VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
-
- /*
- Dispatch the ray tracing commands
- */
- vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipeline);
- vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
-
- // Calculate shader binding offsets, which is pretty straight forward in our example
- VkDeviceSize bindingOffsetRayGenShader = rayTracingProperties.shaderGroupHandleSize * INDEX_RAYGEN;
- VkDeviceSize bindingOffsetMissShader = rayTracingProperties.shaderGroupHandleSize * INDEX_MISS;
- VkDeviceSize bindingOffsetHitShader = rayTracingProperties.shaderGroupHandleSize * INDEX_CLOSEST_HIT;
- VkDeviceSize bindingStride = rayTracingProperties.shaderGroupHandleSize;
-
- vkCmdTraceRaysNV(drawCmdBuffers[i],
- shaderBindingTable.buffer, bindingOffsetRayGenShader,
- shaderBindingTable.buffer, bindingOffsetMissShader, bindingStride,
- shaderBindingTable.buffer, bindingOffsetHitShader, bindingStride,
- VK_NULL_HANDLE, 0, 0,
- width, height, 1);
-
- /*
- Copy raytracing output to swap chain image
- */
-
- // Prepare current swapchain image as transfer destination
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- swapChain.images[i],
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- subresourceRange);
-
- // Prepare ray tracing output image as transfer source
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- storageImage.image,
- VK_IMAGE_LAYOUT_GENERAL,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- subresourceRange);
-
- VkImageCopy copyRegion{};
- copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.srcOffset = { 0, 0, 0 };
- copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.dstOffset = { 0, 0, 0 };
- copyRegion.extent = { width, height, 1 };
- vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
-
- // Transition swap chain image back for presentation
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- swapChain.images[i],
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- subresourceRange);
-
- // Transition ray tracing output image back to general layout
- vks::tools::setImageLayout(
- drawCmdBuffers[i],
- storageImage.image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_IMAGE_LAYOUT_GENERAL,
- subresourceRange);
-
- //@todo: Default render pass setup will overwrite contents
- //vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
- //drawUI(drawCmdBuffers[i]);
- //vkCmdEndRenderPass(drawCmdBuffers[i]);
-
- VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
- }
- }
-
- void updateUniformBuffers()
- {
- uniformData.projInverse = glm::inverse(camera.matrices.perspective);
- uniformData.viewInverse = glm::inverse(camera.matrices.view);
- uniformData.lightPos = glm::vec4(cos(glm::radians(timer * 360.0f)) * 40.0f, -50.0f + sin(glm::radians(timer * 360.0f)) * 20.0f, 25.0f + sin(glm::radians(timer * 360.0f)) * 5.0f, 0.0f);
- // Pass the vertex size to the shader for unpacking vertices
- uniformData.vertexSize = sizeof(vkglTF::Vertex);
- memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
- }
-
- void prepare()
- {
- VulkanExampleBase::prepare();
-
- // Query the ray tracing properties of the current implementation, we will need them later on
- rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV;
- VkPhysicalDeviceProperties2 deviceProps2{};
- deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- deviceProps2.pNext = &rayTracingProperties;
- vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2);
-
- // Get VK_NV_ray_tracing related function pointers
- vkCreateAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureNV"));
- vkDestroyAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureNV"));
- vkBindAccelerationStructureMemoryNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryNV"));
- vkGetAccelerationStructureHandleNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureHandleNV"));
- vkGetAccelerationStructureMemoryRequirementsNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsNV"));
- vkCmdBuildAccelerationStructureNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureNV"));
- vkCreateRayTracingPipelinesNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesNV"));
- vkGetRayTracingShaderGroupHandlesNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesNV"));
- vkCmdTraceRaysNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysNV"));
-
- createScene();
- createStorageImage();
- createUniformBuffer();
- createRayTracingPipeline();
- createShaderBindingTable();
- createDescriptorSets();
- buildCommandBuffers();
- prepared = true;
- }
-
- void draw()
- {
- VulkanExampleBase::prepareFrame();
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
- VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
- VulkanExampleBase::submitFrame();
- }
-
- virtual void render()
- {
- if (!prepared)
- return;
- draw();
- if (!paused || camera.updated)
- updateUniformBuffers();
- }
-};
-
-VULKAN_EXAMPLE_MAIN()
diff --git a/examples/raytracingbasic/raytracingbasic.cpp b/examples/raytracingbasic/raytracingbasic.cpp
new file mode 100644
index 00000000..034fcefb
--- /dev/null
+++ b/examples/raytracingbasic/raytracingbasic.cpp
@@ -0,0 +1,881 @@
+/*
+* Vulkan Example - Basic hardware accelerated ray tracing example using VK_KHR_ray_traying
+*
+* Copyright (C) 2019-2020 by Sascha Willems - www.saschawillems.de
+*
+* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+*/
+
+#define VK_ENABLE_BETA_EXTENSIONS
+
+#include "vulkanexamplebase.h"
+
+// Holds data for a ray tracing scratch buffer that is used as a temporary storage
+struct RayTracingScratchBuffer
+{
+ uint64_t deviceAddress = 0;
+ VkBuffer buffer = VK_NULL_HANDLE;
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+};
+
+// Holds data for a memory object bound to an acceleration structure
+struct RayTracingObjectMemory
+{
+ uint64_t deviceAddress = 0;
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+};
+
+// Ray tracing acceleration structure
+struct AccelerationStructure {
+ VkAccelerationStructureKHR accelerationStructure;
+ uint64_t handle;
+ RayTracingObjectMemory objectMemory;
+};
+
+// Indices for the different ray tracing shader types used in this example
+#define INDEX_RAYGEN_GROUP 0
+#define INDEX_MISS_GROUP 1
+#define INDEX_CLOSEST_HIT_GROUP 2
+
+class VulkanExample : public VulkanExampleBase
+{
+public:
+ PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR;
+ PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR;
+ PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR;
+ PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR;
+ PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR;
+ PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR;
+ PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR;
+ PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR;
+ PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR;
+ PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR;
+ PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR;
+
+ VkPhysicalDeviceRayTracingPropertiesKHR rayTracingProperties{};
+ VkPhysicalDeviceRayTracingFeaturesKHR rayTracingFeatures{};
+
+ VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{};
+ VkPhysicalDeviceRayTracingFeaturesKHR enabledRayTracingFeatures{};
+
+ AccelerationStructure bottomLevelAS;
+ AccelerationStructure topLevelAS;
+
+ vks::Buffer vertexBuffer;
+ vks::Buffer indexBuffer;
+ uint32_t indexCount;
+ std::vector shaderGroups{};
+ vks::Buffer shaderBindingTable;
+
+ struct StorageImage {
+ VkDeviceMemory memory;
+ VkImage image;
+ VkImageView view;
+ VkFormat format;
+ } storageImage;
+
+ struct UniformData {
+ glm::mat4 viewInverse;
+ glm::mat4 projInverse;
+ } uniformData;
+ vks::Buffer ubo;
+
+ VkPipeline pipeline;
+ VkPipelineLayout pipelineLayout;
+ VkDescriptorSet descriptorSet;
+ VkDescriptorSetLayout descriptorSetLayout;
+
+ VulkanExample() : VulkanExampleBase()
+ {
+ title = "Ray tracing basic";
+ settings.overlay = true;
+ camera.type = Camera::CameraType::lookat;
+ camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
+ camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
+ camera.setTranslation(glm::vec3(0.0f, 0.0f, -2.5f));
+ // Enable instance and device extensions required to use VK_KHR_ray_tracing
+ enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
+ // We require Vulkan 1.2 for ray tracing
+ apiVersion = VK_API_VERSION_1_2;
+ }
+
+ ~VulkanExample()
+ {
+ vkDestroyPipeline(device, pipeline, nullptr);
+ vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
+ vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
+ vkDestroyImageView(device, storageImage.view, nullptr);
+ vkDestroyImage(device, storageImage.image, nullptr);
+ vkFreeMemory(device, storageImage.memory, nullptr);
+ vkDestroyAccelerationStructureKHR(device, bottomLevelAS.accelerationStructure, nullptr);
+ vkDestroyAccelerationStructureKHR(device, topLevelAS.accelerationStructure, nullptr);
+ vertexBuffer.destroy();
+ indexBuffer.destroy();
+ shaderBindingTable.destroy();
+ ubo.destroy();
+ deleteObjectMemory(bottomLevelAS.objectMemory);
+ deleteObjectMemory(topLevelAS.objectMemory);
+ }
+
+ /*
+ Create a scratch buffer to hold temporary data for a ray tracing acceleration structure
+ */
+ RayTracingScratchBuffer createScratchBuffer(VkAccelerationStructureKHR accelerationStructure)
+ {
+ RayTracingScratchBuffer scratchBuffer{};
+
+ VkMemoryRequirements2 memoryRequirements2{};
+ memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+
+ VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{};
+ accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR;
+ accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR;
+ accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR;
+ accelerationStructureMemoryRequirements.accelerationStructure = accelerationStructure;
+ vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2);
+
+ VkBufferCreateInfo bufferCI{};
+ bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferCI.size = memoryRequirements2.memoryRequirements.size;
+ bufferCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+ bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCI, nullptr, &scratchBuffer.buffer));
+
+ VkMemoryRequirements memoryRequirements{};
+ vkGetBufferMemoryRequirements(device, scratchBuffer.buffer, &memoryRequirements);
+
+ VkMemoryAllocateFlagsInfo memoryAllocateFI{};
+ memoryAllocateFI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
+ memoryAllocateFI.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
+
+ VkMemoryAllocateInfo memoryAI{};
+ memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memoryAI.pNext = &memoryAllocateFI;
+ memoryAI.allocationSize = memoryRequirements.size;
+ memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &scratchBuffer.memory));
+ VK_CHECK_RESULT(vkBindBufferMemory(device, scratchBuffer.buffer, scratchBuffer.memory, 0));
+
+ VkBufferDeviceAddressInfoKHR buffer_device_address_info{};
+ buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
+ buffer_device_address_info.buffer = scratchBuffer.buffer;
+ scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(device, &buffer_device_address_info);
+
+ return scratchBuffer;
+ }
+
+ void deleteScratchBuffer(RayTracingScratchBuffer& scratchBuffer)
+ {
+ if (scratchBuffer.memory != VK_NULL_HANDLE) {
+ vkFreeMemory(device, scratchBuffer.memory, nullptr);
+ }
+ if (scratchBuffer.buffer != VK_NULL_HANDLE) {
+ vkDestroyBuffer(device, scratchBuffer.buffer, nullptr);
+ }
+ }
+
+ /*
+ Allocate memory that will be attached to a ray tracing acceleration structure
+ */
+ RayTracingObjectMemory createObjectMemory(VkAccelerationStructureKHR acceleration_structure)
+ {
+ RayTracingObjectMemory objectMemory{};
+
+ VkMemoryRequirements2 memoryRequirements2{};
+ memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+
+ VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{};
+ accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR;
+ accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR;
+ accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR;
+ accelerationStructureMemoryRequirements.accelerationStructure = acceleration_structure;
+ vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2);
+
+ VkMemoryRequirements memoryRequirements = memoryRequirements2.memoryRequirements;
+
+ VkMemoryAllocateInfo memoryAI{};
+ memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memoryAI.allocationSize = memoryRequirements.size;
+ memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &objectMemory.memory));
+
+ return objectMemory;
+ }
+
+ void deleteObjectMemory(RayTracingObjectMemory& objectMemory)
+ {
+ if (objectMemory.memory != VK_NULL_HANDLE) {
+ vkFreeMemory(device, objectMemory.memory, nullptr);
+ }
+ }
+
+ /*
+ Gets the device address from a buffer that's required for some of the buffers used for ray tracing
+ */
+ uint64_t getBufferDeviceAddress(VkBuffer buffer)
+ {
+ VkBufferDeviceAddressInfoKHR bufferDeviceAI{};
+ bufferDeviceAI.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
+ bufferDeviceAI.buffer = buffer;
+ return vkGetBufferDeviceAddressKHR(device, &bufferDeviceAI);
+ }
+
+ /*
+ Set up a storage image that the ray generation shader will be writing to
+ */
+ void createStorageImage()
+ {
+ VkImageCreateInfo image = vks::initializers::imageCreateInfo();
+ image.imageType = VK_IMAGE_TYPE_2D;
+ image.format = swapChain.colorFormat;
+ image.extent.width = width;
+ image.extent.height = height;
+ image.extent.depth = 1;
+ image.mipLevels = 1;
+ image.arrayLayers = 1;
+ image.samples = VK_SAMPLE_COUNT_1_BIT;
+ image.tiling = VK_IMAGE_TILING_OPTIMAL;
+ image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
+ image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &storageImage.image));
+
+ VkMemoryRequirements memReqs;
+ vkGetImageMemoryRequirements(device, storageImage.image, &memReqs);
+ VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
+ memoryAllocateInfo.allocationSize = memReqs.size;
+ memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &storageImage.memory));
+ VK_CHECK_RESULT(vkBindImageMemory(device, storageImage.image, storageImage.memory, 0));
+
+ VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
+ colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ colorImageView.format = swapChain.colorFormat;
+ colorImageView.subresourceRange = {};
+ colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ colorImageView.subresourceRange.baseMipLevel = 0;
+ colorImageView.subresourceRange.levelCount = 1;
+ colorImageView.subresourceRange.baseArrayLayer = 0;
+ colorImageView.subresourceRange.layerCount = 1;
+ colorImageView.image = storageImage.image;
+ VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &storageImage.view));
+
+ VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vks::tools::setImageLayout(cmdBuffer, storageImage.image,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_GENERAL,
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
+ vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
+ }
+
+ /*
+ Create the bottom level acceleration structure contains the scene's actual geometry (vertices, triangles)
+ */
+ void createBottomLevelAccelerationStructure()
+ {
+ // Setup vertices for a single triangle
+ struct Vertex {
+ float pos[3];
+ };
+ std::vector vertices = {
+ { { 1.0f, 1.0f, 0.0f } },
+ { { -1.0f, 1.0f, 0.0f } },
+ { { 0.0f, -1.0f, 0.0f } }
+ };
+
+ // Setup indices
+ std::vector indices = { 0, 1, 2 };
+ indexCount = static_cast(indices.size());
+
+ // Create buffers
+ // For the sake of simplicity we won't stage the vertex data to the GPU memory
+ // Vertex buffer
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &vertexBuffer,
+ vertices.size() * sizeof(Vertex),
+ vertices.data()));
+ // Index buffer
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &indexBuffer,
+ indices.size() * sizeof(uint32_t),
+ indices.data()));
+
+ VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{};
+ VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{};
+
+ vertexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(vertexBuffer.buffer);
+ indexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(indexBuffer.buffer);
+
+ VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{};
+ accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR;
+ accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ accelerationCreateGeometryInfo.maxPrimitiveCount = 1;
+ accelerationCreateGeometryInfo.indexType = VK_INDEX_TYPE_UINT32;
+ accelerationCreateGeometryInfo.maxVertexCount = static_cast(vertices.size());
+ accelerationCreateGeometryInfo.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
+ accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE;
+
+ VkAccelerationStructureCreateInfoKHR accelerationCI{};
+ accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationCI.maxGeometryCount = 1;
+ accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo;
+ VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &bottomLevelAS.accelerationStructure));
+
+ // Bind object memory to the top level acceleration structure
+ bottomLevelAS.objectMemory = createObjectMemory(bottomLevelAS.accelerationStructure);
+
+ VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{};
+ bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR;
+ bindAccelerationMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
+ bindAccelerationMemoryInfo.memory = bottomLevelAS.objectMemory.memory;
+ VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo));
+
+ VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
+ accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ accelerationStructureGeometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
+ accelerationStructureGeometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
+ accelerationStructureGeometry.geometry.triangles.vertexData.deviceAddress = vertexBufferDeviceAddress.deviceAddress;
+ accelerationStructureGeometry.geometry.triangles.vertexStride = sizeof(Vertex);
+ accelerationStructureGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
+ accelerationStructureGeometry.geometry.triangles.indexData.deviceAddress = indexBufferDeviceAddress.deviceAddress;
+
+ std::vector acceleration_geometries = { accelerationStructureGeometry };
+ VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data();
+
+ // Create a small scratch buffer used during build of the bottom level acceleration structure
+ RayTracingScratchBuffer scratchBuffer = createScratchBuffer(bottomLevelAS.accelerationStructure);
+
+ VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
+ accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationBuildGeometryInfo.update = VK_FALSE;
+ accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.accelerationStructure;
+ accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE;
+ accelerationBuildGeometryInfo.geometryCount = 1;
+ accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries;
+ accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
+
+ VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{};
+ accelerationBuildOffsetInfo.primitiveCount = 1;
+ accelerationBuildOffsetInfo.primitiveOffset = 0x0;
+ accelerationBuildOffsetInfo.firstVertex = 0;
+ accelerationBuildOffsetInfo.transformOffset = 0x0;
+
+ std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo };
+
+ if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands)
+ {
+ // Implementation supports building acceleration structure building on host
+ VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()));
+ }
+ else
+ {
+ // Acceleration structure needs to be build on the device
+ VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data());
+ vulkanDevice->flushCommandBuffer(commandBuffer, queue);
+ }
+
+ VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
+ accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
+ accelerationDeviceAddressInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
+
+ bottomLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
+
+ deleteScratchBuffer(scratchBuffer);
+ }
+
+ /*
+ The top level acceleration structure contains the scene's object instances
+ */
+ void createTopLevelAccelerationStructure()
+ {
+ VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{};
+ accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR;
+ accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ accelerationCreateGeometryInfo.maxPrimitiveCount = 1;
+ accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE;
+
+ VkAccelerationStructureCreateInfoKHR accelerationCI{};
+ accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationCI.maxGeometryCount = 1;
+ accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo;
+ VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &topLevelAS.accelerationStructure));
+
+ // Bind object memory to the top level acceleration structure
+ topLevelAS.objectMemory = createObjectMemory(topLevelAS.accelerationStructure);
+
+ VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{};
+ bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR;
+ bindAccelerationMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure;
+ bindAccelerationMemoryInfo.memory = topLevelAS.objectMemory.memory;
+ VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo));
+
+ VkTransformMatrixKHR transform_matrix = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f };
+
+ VkAccelerationStructureInstanceKHR instance{};
+ instance.transform = transform_matrix;
+ instance.instanceCustomIndex = 0;
+ instance.mask = 0xFF;
+ instance.instanceShaderBindingTableRecordOffset = 0;
+ instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
+ instance.accelerationStructureReference = bottomLevelAS.handle;
+
+ // Buffer for instance data
+ vks::Buffer instancesBuffer;
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &instancesBuffer,
+ sizeof(instance),
+ &instance));
+
+ VkDeviceOrHostAddressConstKHR instance_data_device_address{};
+ instance_data_device_address.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer);
+
+ VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
+ accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ accelerationStructureGeometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
+ accelerationStructureGeometry.geometry.instances.arrayOfPointers = VK_FALSE;
+ accelerationStructureGeometry.geometry.instances.data.deviceAddress = instance_data_device_address.deviceAddress;
+
+ std::vector acceleration_geometries = { accelerationStructureGeometry };
+ VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data();
+
+ // Create a small scratch buffer used during build of the top level acceleration structure
+ RayTracingScratchBuffer scratchBuffer = createScratchBuffer(topLevelAS.accelerationStructure);
+
+ VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
+ accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationBuildGeometryInfo.update = VK_FALSE;
+ accelerationBuildGeometryInfo.srcAccelerationStructure = VK_NULL_HANDLE;
+ accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.accelerationStructure;
+ accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE;
+ accelerationBuildGeometryInfo.geometryCount = 1;
+ accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries;
+ accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
+
+ VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{};
+ accelerationBuildOffsetInfo.primitiveCount = 1;
+ accelerationBuildOffsetInfo.primitiveOffset = 0x0;
+ accelerationBuildOffsetInfo.firstVertex = 0;
+ accelerationBuildOffsetInfo.transformOffset = 0x0;
+ std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo };
+
+ if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands)
+ {
+ // Implementation supports building acceleration structure building on host
+ VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()));
+ }
+ else
+ {
+ // Acceleration structure needs to be build on the device
+ VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data());
+ vulkanDevice->flushCommandBuffer(commandBuffer, queue);
+ }
+
+ VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
+ accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
+ accelerationDeviceAddressInfo.accelerationStructure = topLevelAS.accelerationStructure;
+
+ topLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
+
+ deleteScratchBuffer(scratchBuffer);
+ instancesBuffer.destroy();
+ }
+
+ /*
+ Create the Shader Binding Table that binds the programs and top-level acceleration structure
+ */
+ void createShaderBindingTable() {
+ const uint32_t groupCount = static_cast(shaderGroups.size());
+
+ const uint32_t sbtSize = rayTracingProperties.shaderGroupBaseAlignment * groupCount;
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &shaderBindingTable, sbtSize));
+ shaderBindingTable.map();
+
+ // Write the shader handles to the shader binding table
+ std::vector shaderHandleStorage(sbtSize);
+ VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()));
+
+ auto* data = static_cast(shaderBindingTable.mapped);
+ // This part is required, as the alignment and handle size may differ
+ for (uint32_t i = 0; i < groupCount; i++)
+ {
+ memcpy(data, shaderHandleStorage.data() + i * rayTracingProperties.shaderGroupHandleSize, rayTracingProperties.shaderGroupHandleSize);
+ data += rayTracingProperties.shaderGroupBaseAlignment;
+ }
+ shaderBindingTable.unmap();
+ }
+
+ /*
+ Create the descriptor sets used for the ray tracing dispatch
+ */
+ void createDescriptorSets()
+ {
+ std::vector poolSizes = {
+ { VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 }
+ };
+ VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
+ VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
+
+ VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
+ VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
+
+ VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo{};
+ descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
+ descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
+ descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure;
+
+ VkWriteDescriptorSet accelerationStructureWrite{};
+ accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ // The specialized acceleration structure descriptor has to be chained
+ accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
+ accelerationStructureWrite.dstSet = descriptorSet;
+ accelerationStructureWrite.dstBinding = 0;
+ accelerationStructureWrite.descriptorCount = 1;
+ accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+
+ VkDescriptorImageInfo storageImageDescriptor{};
+ storageImageDescriptor.imageView = storageImage.view;
+ storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+ VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
+ VkWriteDescriptorSet uniformBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor);
+
+ std::vector writeDescriptorSets = {
+ accelerationStructureWrite,
+ resultImageWrite,
+ uniformBufferWrite
+ };
+ vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
+ }
+
+ /*
+ Create our ray tracing pipeline
+ */
+ void createRayTracingPipeline()
+ {
+ VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding{};
+ accelerationStructureLayoutBinding.binding = 0;
+ accelerationStructureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+ accelerationStructureLayoutBinding.descriptorCount = 1;
+ accelerationStructureLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding resultImageLayoutBinding{};
+ resultImageLayoutBinding.binding = 1;
+ resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ resultImageLayoutBinding.descriptorCount = 1;
+ resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding uniformBufferBinding{};
+ uniformBufferBinding.binding = 2;
+ uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uniformBufferBinding.descriptorCount = 1;
+ uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
+
+ std::vector bindings({
+ accelerationStructureLayoutBinding,
+ resultImageLayoutBinding,
+ uniformBufferBinding
+ });
+
+ VkDescriptorSetLayoutCreateInfo descriptorSetlayoutCI{};
+ descriptorSetlayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ descriptorSetlayoutCI.bindingCount = static_cast(bindings.size());
+ descriptorSetlayoutCI.pBindings = bindings.data();
+ VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetlayoutCI, nullptr, &descriptorSetLayout));
+
+ VkPipelineLayoutCreateInfo pipelineLayoutCI{};
+ pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutCI.setLayoutCount = 1;
+ pipelineLayoutCI.pSetLayouts = &descriptorSetLayout;
+ VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
+
+ const uint32_t shaderIndexRaygen = 0;
+ const uint32_t shaderIndexMiss = 1;
+ const uint32_t shaderIndexClosestHit = 2;
+
+ std::array shaderStages;
+ shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "raytracingbasic/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR);
+ shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "raytracingbasic/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR);
+ shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "raytracingbasic/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
+
+ /*
+ Setup ray tracing shader groups
+ */
+ VkRayTracingShaderGroupCreateInfoKHR raygenGroupCI{};
+ raygenGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ raygenGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
+ raygenGroupCI.generalShader = shaderIndexRaygen;
+ raygenGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR;
+ raygenGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ raygenGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(raygenGroupCI);
+
+ VkRayTracingShaderGroupCreateInfoKHR missGroupCI{};
+ missGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ missGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
+ missGroupCI.generalShader = shaderIndexMiss;
+ missGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR;
+ missGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ missGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(missGroupCI);
+
+ VkRayTracingShaderGroupCreateInfoKHR closesHitGroupCI{};
+ closesHitGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ closesHitGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
+ closesHitGroupCI.generalShader = VK_SHADER_UNUSED_KHR;
+ closesHitGroupCI.closestHitShader = shaderIndexClosestHit;
+ closesHitGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ closesHitGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(closesHitGroupCI);
+
+ VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI{};
+ rayTracingPipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
+ rayTracingPipelineCI.stageCount = static_cast(shaderStages.size());
+ rayTracingPipelineCI.pStages = shaderStages.data();
+ rayTracingPipelineCI.groupCount = static_cast(shaderGroups.size());
+ rayTracingPipelineCI.pGroups = shaderGroups.data();
+ rayTracingPipelineCI.maxRecursionDepth = 1;
+ rayTracingPipelineCI.layout = pipelineLayout;
+ rayTracingPipelineCI.libraries.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR;
+ VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline));
+ }
+
+ /*
+ Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
+ */
+ void createUniformBuffer()
+ {
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &ubo,
+ sizeof(uniformData),
+ &uniformData));
+ VK_CHECK_RESULT(ubo.map());
+
+ updateUniformBuffers();
+ }
+
+ /*
+ Command buffer generation
+ */
+ void buildCommandBuffers()
+ {
+ VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
+
+ VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
+
+ for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
+ {
+ VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
+
+ /*
+ Dispatch the ray tracing commands
+ */
+ vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
+ vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
+
+
+ /*
+ Setup the buffer regions pointing to the shaders in our shader binding table
+ */
+ const VkDeviceSize sbtSize = rayTracingProperties.shaderGroupBaseAlignment * (VkDeviceSize)shaderGroups.size();
+
+ VkStridedBufferRegionKHR raygenShaderSBTEntry{};
+ raygenShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ raygenShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_RAYGEN_GROUP);
+ raygenShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ raygenShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR missShaderSBTEntry{};
+ missShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ missShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_MISS_GROUP);
+ missShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ missShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR hitShaderSBTEntry{};
+ hitShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ hitShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_CLOSEST_HIT_GROUP);
+ hitShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ hitShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR callableShaderSBTEntry{};
+
+ /*
+ Dispatch the ray tracing commands
+ */
+ vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
+ vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
+
+ vkCmdTraceRaysKHR(
+ drawCmdBuffers[i],
+ &raygenShaderSBTEntry,
+ &missShaderSBTEntry,
+ &hitShaderSBTEntry,
+ &callableShaderSBTEntry,
+ width,
+ height,
+ 1);
+
+ /*
+ Copy ray tracing output to swap chain image
+ */
+
+ // Prepare current swap chain image as transfer destination
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ swapChain.images[i],
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ subresourceRange);
+
+ // Prepare ray tracing output image as transfer source
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ storageImage.image,
+ VK_IMAGE_LAYOUT_GENERAL,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ subresourceRange);
+
+ VkImageCopy copyRegion{};
+ copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.srcOffset = { 0, 0, 0 };
+ copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.dstOffset = { 0, 0, 0 };
+ copyRegion.extent = { width, height, 1 };
+ vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
+
+ // Transition swap chain image back for presentation
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ swapChain.images[i],
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ subresourceRange);
+
+ // Transition ray tracing output image back to general layout
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ storageImage.image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ VK_IMAGE_LAYOUT_GENERAL,
+ subresourceRange);
+
+ VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
+ }
+ }
+
+ void updateUniformBuffers()
+ {
+ uniformData.projInverse = glm::inverse(camera.matrices.perspective);
+ uniformData.viewInverse = glm::inverse(camera.matrices.view);
+ memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
+ }
+
+ void getEnabledFeatures()
+ {
+ // Enable features required for ray tracing using feature chaining via pNext
+ enabledBufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
+ enabledBufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE;
+
+ enabledRayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+ enabledRayTracingFeatures.rayTracing = VK_TRUE;
+ enabledRayTracingFeatures.pNext = &enabledBufferDeviceAddresFeatures;
+
+ deviceCreatepNextChain = &enabledRayTracingFeatures;
+ }
+
+ void prepare()
+ {
+ VulkanExampleBase::prepare();
+
+ // Query the ray tracing properties of the current implementation, we will need them later on
+ rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR;
+ VkPhysicalDeviceProperties2 deviceProps2{};
+ deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ deviceProps2.pNext = &rayTracingProperties;
+ vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2);
+
+ // Query the ray tracing properties of the current implementation, we will need them later on
+ rayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+ VkPhysicalDeviceFeatures2 deviceFeatures2{};
+ deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ deviceFeatures2.pNext = &rayTracingFeatures;
+ vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
+
+ // Get the function pointers required for ray tracing
+ vkGetBufferDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
+ vkBindAccelerationStructureMemoryKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryKHR"));
+ vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR"));
+ vkDestroyAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR"));
+ vkGetAccelerationStructureMemoryRequirementsKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsKHR"));
+ vkCmdBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureKHR"));
+ vkBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructureKHR"));
+ vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR"));
+ vkCmdTraceRaysKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR"));
+ vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR"));
+ vkCreateRayTracingPipelinesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR"));
+
+ // Create the acceleration structures used to render the ray traced scene
+ createBottomLevelAccelerationStructure();
+ createTopLevelAccelerationStructure();
+
+ createStorageImage();
+ createUniformBuffer();
+ createRayTracingPipeline();
+ createShaderBindingTable();
+ createDescriptorSets();
+ buildCommandBuffers();
+ prepared = true;
+ }
+
+ void draw()
+ {
+ VulkanExampleBase::prepareFrame();
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
+ VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
+ VulkanExampleBase::submitFrame();
+ }
+
+ virtual void render()
+ {
+ if (!prepared)
+ return;
+ draw();
+ if (camera.updated)
+ updateUniformBuffers();
+ }
+};
+
+VULKAN_EXAMPLE_MAIN()
diff --git a/examples/raytracingreflections/raytracingreflections.cpp b/examples/raytracingreflections/raytracingreflections.cpp
new file mode 100644
index 00000000..86cf6174
--- /dev/null
+++ b/examples/raytracingreflections/raytracingreflections.cpp
@@ -0,0 +1,876 @@
+/*
+* Vulkan Example - Hardware accelerated ray tracing example for doing reflections using VK_KHR_ray_traying
+*
+* Renders a complex scene doing recursion inside the shaders for creating reflections
+*
+* Copyright (C) 2019-2020 by Sascha Willems - www.saschawillems.de
+*
+* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+*/
+
+#define VK_ENABLE_BETA_EXTENSIONS
+
+#include "vulkanexamplebase.h"
+#include "VulkanglTFModel.h"
+
+// Ray tracing utility structures, see ray tracing basic sample for details
+struct RayTracingScratchBuffer
+{
+ uint64_t deviceAddress = 0;
+ VkBuffer buffer = VK_NULL_HANDLE;
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+};
+
+struct RayTracingObjectMemory
+{
+ uint64_t deviceAddress = 0;
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+};
+
+struct AccelerationStructure {
+ VkAccelerationStructureKHR accelerationStructure;
+ uint64_t handle;
+ RayTracingObjectMemory objectMemory;
+};
+
+// Indices for the different ray tracing groups used in this example
+#define INDEX_RAYGEN_GROUP 0
+#define INDEX_MISS_GROUP 1
+#define INDEX_CLOSEST_HIT_GROUP 2
+
+class VulkanExample : public VulkanExampleBase
+{
+public:
+ PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR;
+ PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR;
+ PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR;
+ PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR;
+ PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR;
+ PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR;
+ PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR;
+ PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR;
+ PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR;
+ PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR;
+ PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR;
+
+ VkPhysicalDeviceRayTracingPropertiesKHR rayTracingProperties{};
+ VkPhysicalDeviceRayTracingFeaturesKHR rayTracingFeatures{};
+
+ VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{};
+ VkPhysicalDeviceRayTracingFeaturesKHR enabledRayTracingFeatures{};
+
+ AccelerationStructure bottomLevelAS;
+ AccelerationStructure topLevelAS;
+
+ std::vector shaderGroups{};
+ vks::Buffer shaderBindingTable;
+
+ struct StorageImage {
+ VkDeviceMemory memory;
+ VkImage image;
+ VkImageView view;
+ VkFormat format;
+ } storageImage;
+
+ struct UniformData {
+ glm::mat4 viewInverse;
+ glm::mat4 projInverse;
+ glm::vec4 lightPos;
+ int32_t vertexSize;
+ } uniformData;
+ vks::Buffer ubo;
+
+ VkPipeline pipeline;
+ VkPipelineLayout pipelineLayout;
+ VkDescriptorSet descriptorSet;
+ VkDescriptorSetLayout descriptorSetLayout;
+
+ vkglTF::Model scene;
+
+ VulkanExample() : VulkanExampleBase()
+ {
+ title = "Ray tracing reflections";
+ settings.overlay = false;
+ timerSpeed *= 0.5f;
+ camera.rotationSpeed *= 0.25f;
+ camera.type = Camera::CameraType::firstperson;
+ camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
+ camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
+ camera.setTranslation(glm::vec3(0.0f, 0.5f, -2.0f));
+ // Enable instance and device extensions required to use VK_KHR_ray_tracing
+ enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
+ // We require Vulkan 1.2 for ray tracing
+ apiVersion = VK_API_VERSION_1_2;
+ }
+
+ ~VulkanExample()
+ {
+ vkDestroyPipeline(device, pipeline, nullptr);
+ vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
+ vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
+ vkDestroyImageView(device, storageImage.view, nullptr);
+ vkDestroyImage(device, storageImage.image, nullptr);
+ vkFreeMemory(device, storageImage.memory, nullptr);
+ vkDestroyAccelerationStructureKHR(device, bottomLevelAS.accelerationStructure, nullptr);
+ vkDestroyAccelerationStructureKHR(device, topLevelAS.accelerationStructure, nullptr);
+ shaderBindingTable.destroy();
+ ubo.destroy();
+ deleteObjectMemory(bottomLevelAS.objectMemory);
+ deleteObjectMemory(topLevelAS.objectMemory);
+ }
+
+ /*
+ Ray tracing utility functions, see ray tracing basic sample for details
+*/
+ RayTracingScratchBuffer createScratchBuffer(VkAccelerationStructureKHR accelerationStructure)
+ {
+ RayTracingScratchBuffer scratchBuffer{};
+ VkMemoryRequirements2 memoryRequirements2{};
+ memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+ VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{};
+ accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR;
+ accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR;
+ accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR;
+ accelerationStructureMemoryRequirements.accelerationStructure = accelerationStructure;
+ vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2);
+ VkBufferCreateInfo bufferCI{};
+ bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferCI.size = memoryRequirements2.memoryRequirements.size;
+ bufferCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+ bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCI, nullptr, &scratchBuffer.buffer));
+ VkMemoryRequirements memoryRequirements{};
+ vkGetBufferMemoryRequirements(device, scratchBuffer.buffer, &memoryRequirements);
+ VkMemoryAllocateFlagsInfo memoryAllocateFI{};
+ memoryAllocateFI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
+ memoryAllocateFI.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
+ VkMemoryAllocateInfo memoryAI{};
+ memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memoryAI.pNext = &memoryAllocateFI;
+ memoryAI.allocationSize = memoryRequirements.size;
+ memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &scratchBuffer.memory));
+ VK_CHECK_RESULT(vkBindBufferMemory(device, scratchBuffer.buffer, scratchBuffer.memory, 0));
+ VkBufferDeviceAddressInfoKHR buffer_device_address_info{};
+ buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
+ buffer_device_address_info.buffer = scratchBuffer.buffer;
+ scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(device, &buffer_device_address_info);
+ return scratchBuffer;
+ }
+
+ void deleteScratchBuffer(RayTracingScratchBuffer& scratchBuffer)
+ {
+ if (scratchBuffer.memory != VK_NULL_HANDLE) {
+ vkFreeMemory(device, scratchBuffer.memory, nullptr);
+ }
+ if (scratchBuffer.buffer != VK_NULL_HANDLE) {
+ vkDestroyBuffer(device, scratchBuffer.buffer, nullptr);
+ }
+ }
+
+ RayTracingObjectMemory createObjectMemory(VkAccelerationStructureKHR acceleration_structure)
+ {
+ RayTracingObjectMemory objectMemory{};
+ VkMemoryRequirements2 memoryRequirements2{};
+ memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+ VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{};
+ accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR;
+ accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR;
+ accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR;
+ accelerationStructureMemoryRequirements.accelerationStructure = acceleration_structure;
+ vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2);
+ VkMemoryRequirements memoryRequirements = memoryRequirements2.memoryRequirements;
+ VkMemoryAllocateInfo memoryAI{};
+ memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memoryAI.allocationSize = memoryRequirements.size;
+ memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &objectMemory.memory));
+ return objectMemory;
+ }
+
+ void deleteObjectMemory(RayTracingObjectMemory& objectMemory)
+ {
+ if (objectMemory.memory != VK_NULL_HANDLE) {
+ vkFreeMemory(device, objectMemory.memory, nullptr);
+ }
+ }
+
+ uint64_t getBufferDeviceAddress(VkBuffer buffer)
+ {
+ VkBufferDeviceAddressInfoKHR bufferDeviceAI{};
+ bufferDeviceAI.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
+ bufferDeviceAI.buffer = buffer;
+ return vkGetBufferDeviceAddressKHR(device, &bufferDeviceAI);
+ }
+
+ /*
+ Set up a storage image that the ray generation shader will be writing to
+ */
+ void createStorageImage()
+ {
+ VkImageCreateInfo image = vks::initializers::imageCreateInfo();
+ image.imageType = VK_IMAGE_TYPE_2D;
+ image.format = swapChain.colorFormat;
+ image.extent.width = width;
+ image.extent.height = height;
+ image.extent.depth = 1;
+ image.mipLevels = 1;
+ image.arrayLayers = 1;
+ image.samples = VK_SAMPLE_COUNT_1_BIT;
+ image.tiling = VK_IMAGE_TILING_OPTIMAL;
+ image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
+ image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &storageImage.image));
+
+ VkMemoryRequirements memReqs;
+ vkGetImageMemoryRequirements(device, storageImage.image, &memReqs);
+ VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
+ memoryAllocateInfo.allocationSize = memReqs.size;
+ memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &storageImage.memory));
+ VK_CHECK_RESULT(vkBindImageMemory(device, storageImage.image, storageImage.memory, 0));
+
+ VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
+ colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ colorImageView.format = swapChain.colorFormat;
+ colorImageView.subresourceRange = {};
+ colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ colorImageView.subresourceRange.baseMipLevel = 0;
+ colorImageView.subresourceRange.levelCount = 1;
+ colorImageView.subresourceRange.baseArrayLayer = 0;
+ colorImageView.subresourceRange.layerCount = 1;
+ colorImageView.image = storageImage.image;
+ VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &storageImage.view));
+
+ VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vks::tools::setImageLayout(cmdBuffer, storageImage.image,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_GENERAL,
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
+ vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
+ }
+
+ /*
+ Create the bottom level acceleration structure contains the scene's actual geometry (vertices, triangles)
+ */
+ void createBottomLevelAccelerationStructure()
+ {
+ // Instead of a simple triangle, we'll be loading a more complex scene for this example
+ // The shaders are accessing the vertex and index buffers of the scene, so the proper usage flag has to be set on the vertex and index buffers for the scene
+ vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+ const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::PreMultiplyVertexColors | vkglTF::FileLoadingFlags::FlipY;
+ scene.loadFromFile(getAssetPath() + "models/reflection_scene.gltf", vulkanDevice, queue, glTFLoadingFlags);
+
+ const uint32_t numTriangles = static_cast(scene.indices.count) / 3;
+
+ VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{};
+ VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{};
+
+ vertexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.vertices.buffer);
+ indexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.indices.buffer);
+
+ VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{};
+ accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR;
+ accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ accelerationCreateGeometryInfo.maxPrimitiveCount = numTriangles;
+ accelerationCreateGeometryInfo.indexType = VK_INDEX_TYPE_UINT32;
+ accelerationCreateGeometryInfo.maxVertexCount = static_cast(scene.vertices.count);
+ accelerationCreateGeometryInfo.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
+ accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE;
+
+ VkAccelerationStructureCreateInfoKHR accelerationCI{};
+ accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationCI.maxGeometryCount = 1;
+ accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo;
+ VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &bottomLevelAS.accelerationStructure));
+
+ // Bind object memory to the top level acceleration structure
+ bottomLevelAS.objectMemory = createObjectMemory(bottomLevelAS.accelerationStructure);
+
+ VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{};
+ bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR;
+ bindAccelerationMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
+ bindAccelerationMemoryInfo.memory = bottomLevelAS.objectMemory.memory;
+ VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo));
+
+ VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
+ accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ accelerationStructureGeometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
+ accelerationStructureGeometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
+ accelerationStructureGeometry.geometry.triangles.vertexData.deviceAddress = vertexBufferDeviceAddress.deviceAddress;
+ accelerationStructureGeometry.geometry.triangles.vertexStride = sizeof(vkglTF::Vertex);
+ accelerationStructureGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
+ accelerationStructureGeometry.geometry.triangles.indexData.deviceAddress = indexBufferDeviceAddress.deviceAddress;
+
+ std::vector acceleration_geometries = { accelerationStructureGeometry };
+ VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data();
+
+ // Create a small scratch buffer used during build of the bottom level acceleration structure
+ RayTracingScratchBuffer scratchBuffer = createScratchBuffer(bottomLevelAS.accelerationStructure);
+
+ VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
+ accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationBuildGeometryInfo.update = VK_FALSE;
+ accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.accelerationStructure;
+ accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE;
+ accelerationBuildGeometryInfo.geometryCount = 1;
+ accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries;
+ accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
+
+ VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{};
+ accelerationBuildOffsetInfo.primitiveCount = numTriangles;
+ accelerationBuildOffsetInfo.primitiveOffset = 0x0;
+ accelerationBuildOffsetInfo.firstVertex = 0;
+ accelerationBuildOffsetInfo.transformOffset = 0x0;
+
+ std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo };
+
+ if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands)
+ {
+ // Implementation supports building acceleration structure building on host
+ VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()));
+ }
+ else
+ {
+ // Acceleration structure needs to be build on the device
+ VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data());
+ vulkanDevice->flushCommandBuffer(commandBuffer, queue);
+ }
+
+ VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
+ accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
+ accelerationDeviceAddressInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
+
+ bottomLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
+
+ deleteScratchBuffer(scratchBuffer);
+ }
+
+ /*
+ The top level acceleration structure contains the scene's object instances
+ */
+ void createTopLevelAccelerationStructure()
+ {
+ VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{};
+ accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR;
+ accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ accelerationCreateGeometryInfo.maxPrimitiveCount = 1;
+ accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE;
+
+ VkAccelerationStructureCreateInfoKHR accelerationCI{};
+ accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationCI.maxGeometryCount = 1;
+ accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo;
+ VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &topLevelAS.accelerationStructure));
+
+ // Bind object memory to the top level acceleration structure
+ topLevelAS.objectMemory = createObjectMemory(topLevelAS.accelerationStructure);
+
+ VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{};
+ bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR;
+ bindAccelerationMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure;
+ bindAccelerationMemoryInfo.memory = topLevelAS.objectMemory.memory;
+ VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo));
+
+ VkTransformMatrixKHR transform_matrix = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f };
+
+ VkAccelerationStructureInstanceKHR instance{};
+ instance.transform = transform_matrix;
+ instance.instanceCustomIndex = 0;
+ instance.mask = 0xFF;
+ instance.instanceShaderBindingTableRecordOffset = 0;
+ instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
+ instance.accelerationStructureReference = bottomLevelAS.handle;
+
+ // Buffer for instance data
+ vks::Buffer instancesBuffer;
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &instancesBuffer,
+ sizeof(instance),
+ &instance));
+
+ VkDeviceOrHostAddressConstKHR instance_data_device_address{};
+ instance_data_device_address.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer);
+
+ VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
+ accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ accelerationStructureGeometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
+ accelerationStructureGeometry.geometry.instances.arrayOfPointers = VK_FALSE;
+ accelerationStructureGeometry.geometry.instances.data.deviceAddress = instance_data_device_address.deviceAddress;
+
+ std::vector acceleration_geometries = { accelerationStructureGeometry };
+ VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data();
+
+ // Create a small scratch buffer used during build of the top level acceleration structure
+ RayTracingScratchBuffer scratchBuffer = createScratchBuffer(topLevelAS.accelerationStructure);
+
+ VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
+ accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationBuildGeometryInfo.update = VK_FALSE;
+ accelerationBuildGeometryInfo.srcAccelerationStructure = VK_NULL_HANDLE;
+ accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.accelerationStructure;
+ accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE;
+ accelerationBuildGeometryInfo.geometryCount = 1;
+ accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries;
+ accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
+
+ VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{};
+ accelerationBuildOffsetInfo.primitiveCount = 1;
+ accelerationBuildOffsetInfo.primitiveOffset = 0x0;
+ accelerationBuildOffsetInfo.firstVertex = 0;
+ accelerationBuildOffsetInfo.transformOffset = 0x0;
+ std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo };
+
+ if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands)
+ {
+ // Implementation supports building acceleration structure building on host
+ VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()));
+ }
+ else
+ {
+ // Acceleration structure needs to be build on the device
+ VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data());
+ vulkanDevice->flushCommandBuffer(commandBuffer, queue);
+ }
+
+ VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
+ accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
+ accelerationDeviceAddressInfo.accelerationStructure = topLevelAS.accelerationStructure;
+
+ topLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
+
+ deleteScratchBuffer(scratchBuffer);
+ instancesBuffer.destroy();
+ }
+
+ /*
+ Create the Shader Binding Table that binds the programs and top-level acceleration structure
+ */
+ void createShaderBindingTable() {
+ const uint32_t groupCount = static_cast(shaderGroups.size());
+
+ const uint32_t sbtSize = rayTracingProperties.shaderGroupBaseAlignment * groupCount;
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &shaderBindingTable, sbtSize));
+ shaderBindingTable.map();
+
+ // Write the shader handles to the shader binding table
+ std::vector shaderHandleStorage(sbtSize);
+ VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()));
+
+ auto* data = static_cast(shaderBindingTable.mapped);
+ // This part is required, as the alignment and handle size may differ
+ for (uint32_t i = 0; i < groupCount; i++)
+ {
+ memcpy(data, shaderHandleStorage.data() + i * rayTracingProperties.shaderGroupHandleSize, rayTracingProperties.shaderGroupHandleSize);
+ data += rayTracingProperties.shaderGroupBaseAlignment;
+ }
+ shaderBindingTable.unmap();
+ }
+
+ /*
+ Create the descriptor sets used for the ray tracing dispatch
+ */
+ void createDescriptorSets()
+ {
+ std::vector poolSizes = {
+ { VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2 }
+ };
+ VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
+ VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
+
+ VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
+ VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
+
+ VkWriteDescriptorSetAccelerationStructureNV descriptorAccelerationStructureInfo{};
+ descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
+ descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
+ descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure;
+
+ VkWriteDescriptorSet accelerationStructureWrite{};
+ accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ // The specialized acceleration structure descriptor has to be chained
+ accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
+ accelerationStructureWrite.dstSet = descriptorSet;
+ accelerationStructureWrite.dstBinding = 0;
+ accelerationStructureWrite.descriptorCount = 1;
+ accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+
+ VkDescriptorImageInfo storageImageDescriptor{};
+ storageImageDescriptor.imageView = storageImage.view;
+ storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+ VkDescriptorBufferInfo vertexBufferDescriptor{};
+ vertexBufferDescriptor.buffer = scene.vertices.buffer;
+ vertexBufferDescriptor.range = VK_WHOLE_SIZE;
+
+ VkDescriptorBufferInfo indexBufferDescriptor{};
+ indexBufferDescriptor.buffer = scene.indices.buffer;
+ indexBufferDescriptor.range = VK_WHOLE_SIZE;
+
+ VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
+ VkWriteDescriptorSet uniformBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor);
+ VkWriteDescriptorSet vertexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor);
+ VkWriteDescriptorSet indexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor);
+
+ std::vector writeDescriptorSets = {
+ accelerationStructureWrite,
+ resultImageWrite,
+ uniformBufferWrite,
+ vertexBufferWrite,
+ indexBufferWrite
+ };
+ vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
+ }
+
+ /*
+ Create our ray tracing pipeline
+ */
+ void createRayTracingPipeline()
+ {
+ VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding{};
+ accelerationStructureLayoutBinding.binding = 0;
+ accelerationStructureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+ accelerationStructureLayoutBinding.descriptorCount = 1;
+ accelerationStructureLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding resultImageLayoutBinding{};
+ resultImageLayoutBinding.binding = 1;
+ resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ resultImageLayoutBinding.descriptorCount = 1;
+ resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding uniformBufferBinding{};
+ uniformBufferBinding.binding = 2;
+ uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uniformBufferBinding.descriptorCount = 1;
+ uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding vertexBufferBinding{};
+ vertexBufferBinding.binding = 3;
+ vertexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ vertexBufferBinding.descriptorCount = 1;
+ vertexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding indexBufferBinding{};
+ indexBufferBinding.binding = 4;
+ indexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ indexBufferBinding.descriptorCount = 1;
+ indexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+
+ std::vector bindings({
+ accelerationStructureLayoutBinding,
+ resultImageLayoutBinding,
+ uniformBufferBinding,
+ vertexBufferBinding,
+ indexBufferBinding
+ });
+
+ VkDescriptorSetLayoutCreateInfo layoutInfo{};
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = static_cast(bindings.size());
+ layoutInfo.pBindings = bindings.data();
+ VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout));
+
+ VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
+ pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutCreateInfo.setLayoutCount = 1;
+ pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
+
+ VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
+
+ const uint32_t shaderIndexRaygen = 0;
+ const uint32_t shaderIndexMiss = 1;
+ const uint32_t shaderIndexClosestHit = 2;
+
+ std::array shaderStages;
+ shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "raytracingreflections/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR);
+ shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "raytracingreflections/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR);
+ shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "raytracingreflections/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
+
+ // Pass recursion depth for reflections to ray generation shader via specialization constant
+ VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t));
+ uint32_t maxRecursion = 4;
+ VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(maxRecursion), &maxRecursion);
+ shaderStages[shaderIndexRaygen].pSpecializationInfo = &specializationInfo;
+
+ /*
+ Setup ray tracing shader groups
+ */
+ VkRayTracingShaderGroupCreateInfoKHR raygenGroupCI{};
+ raygenGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ raygenGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
+ raygenGroupCI.generalShader = shaderIndexRaygen;
+ raygenGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR;
+ raygenGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ raygenGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(raygenGroupCI);
+
+ VkRayTracingShaderGroupCreateInfoKHR missGroupCI{};
+ missGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ missGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
+ missGroupCI.generalShader = shaderIndexMiss;
+ missGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR;
+ missGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ missGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(missGroupCI);
+
+ VkRayTracingShaderGroupCreateInfoKHR closesHitGroupCI{};
+ closesHitGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ closesHitGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
+ closesHitGroupCI.generalShader = VK_SHADER_UNUSED_KHR;
+ closesHitGroupCI.closestHitShader = shaderIndexClosestHit;
+ closesHitGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ closesHitGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(closesHitGroupCI);
+
+ VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI{};
+ rayTracingPipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
+ rayTracingPipelineCI.stageCount = static_cast(shaderStages.size());
+ rayTracingPipelineCI.pStages = shaderStages.data();
+ rayTracingPipelineCI.groupCount = static_cast(shaderGroups.size());
+ rayTracingPipelineCI.pGroups = shaderGroups.data();
+ rayTracingPipelineCI.maxRecursionDepth = 4;
+ rayTracingPipelineCI.layout = pipelineLayout;
+ rayTracingPipelineCI.libraries.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR;
+ VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline));
+ }
+
+ /*
+ Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
+ */
+ void createUniformBuffer()
+ {
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &ubo,
+ sizeof(uniformData),
+ &uniformData));
+ VK_CHECK_RESULT(ubo.map());
+
+ updateUniformBuffers();
+ }
+
+ /*
+ Command buffer generation
+ */
+ void buildCommandBuffers()
+ {
+ VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
+
+ VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
+
+ for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
+ {
+ VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
+
+ /*
+ Dispatch the ray tracing commands
+ */
+ vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
+ vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
+
+ /*
+ Setup the buffer regions pointing to the shaders in our shader binding table
+ */
+ const VkDeviceSize sbtSize = rayTracingProperties.shaderGroupBaseAlignment * (VkDeviceSize)shaderGroups.size();
+
+ VkStridedBufferRegionKHR raygenShaderSBTEntry{};
+ raygenShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ raygenShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_RAYGEN_GROUP);
+ raygenShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ raygenShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR missShaderSBTEntry{};
+ missShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ missShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_MISS_GROUP);
+ missShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ missShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR hitShaderSBTEntry{};
+ hitShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ hitShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_CLOSEST_HIT_GROUP);
+ hitShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ hitShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR callableShaderSBTEntry{};
+
+ vkCmdTraceRaysKHR(
+ drawCmdBuffers[i],
+ &raygenShaderSBTEntry,
+ &missShaderSBTEntry,
+ &hitShaderSBTEntry,
+ &callableShaderSBTEntry,
+ width,
+ height,
+ 1);
+
+ /*
+ Copy ray tracing output to swap chain image
+ */
+
+ // Prepare current swap chain image as transfer destination
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ swapChain.images[i],
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ subresourceRange);
+
+ // Prepare ray tracing output image as transfer source
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ storageImage.image,
+ VK_IMAGE_LAYOUT_GENERAL,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ subresourceRange);
+
+ VkImageCopy copyRegion{};
+ copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.srcOffset = { 0, 0, 0 };
+ copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.dstOffset = { 0, 0, 0 };
+ copyRegion.extent = { width, height, 1 };
+ vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
+
+ // Transition swap chain image back for presentation
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ swapChain.images[i],
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ subresourceRange);
+
+ // Transition ray tracing output image back to general layout
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ storageImage.image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ VK_IMAGE_LAYOUT_GENERAL,
+ subresourceRange);
+
+ //@todo: Default render pass setup will overwrite contents
+ //vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+ //drawUI(drawCmdBuffers[i]);
+ //vkCmdEndRenderPass(drawCmdBuffers[i]);
+
+ VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
+ }
+ }
+
+ void updateUniformBuffers()
+ {
+ uniformData.projInverse = glm::inverse(camera.matrices.perspective);
+ uniformData.viewInverse = glm::inverse(camera.matrices.view);
+ uniformData.lightPos = glm::vec4(cos(glm::radians(timer * 360.0f)) * 40.0f, -20.0f + sin(glm::radians(timer * 360.0f)) * 20.0f, 25.0f + sin(glm::radians(timer * 360.0f)) * 5.0f, 0.0f);
+ // Pass the vertex size to the shader for unpacking vertices
+ uniformData.vertexSize = sizeof(vkglTF::Vertex);
+ memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
+ }
+
+ void getEnabledFeatures()
+ {
+ // Enable features required for ray tracing using feature chaining via pNext
+ enabledBufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
+ enabledBufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE;
+
+ enabledRayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+ enabledRayTracingFeatures.rayTracing = VK_TRUE;
+ enabledRayTracingFeatures.pNext = &enabledBufferDeviceAddresFeatures;
+
+ deviceCreatepNextChain = &enabledRayTracingFeatures;
+ }
+
+ void prepare()
+ {
+ VulkanExampleBase::prepare();
+
+ // Query the ray tracing properties of the current implementation, we will need them later on
+ rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR;
+ VkPhysicalDeviceProperties2 deviceProps2{};
+ deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ deviceProps2.pNext = &rayTracingProperties;
+ vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2);
+
+ // Query the ray tracing properties of the current implementation, we will need them later on
+ rayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+ VkPhysicalDeviceFeatures2 deviceFeatures2{};
+ deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ deviceFeatures2.pNext = &rayTracingFeatures;
+ vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
+
+ // Get the function pointers required for ray tracing
+ vkGetBufferDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
+ vkBindAccelerationStructureMemoryKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryKHR"));
+ vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR"));
+ vkDestroyAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR"));
+ vkGetAccelerationStructureMemoryRequirementsKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsKHR"));
+ vkCmdBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureKHR"));
+ vkBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructureKHR"));
+ vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR"));
+ vkCmdTraceRaysKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR"));
+ vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR"));
+ vkCreateRayTracingPipelinesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR"));
+
+ // Create the acceleration structures used to render the ray traced scene
+ createBottomLevelAccelerationStructure();
+ createTopLevelAccelerationStructure();
+
+ createStorageImage();
+ createUniformBuffer();
+ createRayTracingPipeline();
+ createShaderBindingTable();
+ createDescriptorSets();
+ buildCommandBuffers();
+ prepared = true;
+ }
+
+ void draw()
+ {
+ VulkanExampleBase::prepareFrame();
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
+ VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
+ VulkanExampleBase::submitFrame();
+ }
+
+ virtual void render()
+ {
+ if (!prepared)
+ return;
+ draw();
+ if (!paused || camera.updated)
+ updateUniformBuffers();
+ }
+};
+
+VULKAN_EXAMPLE_MAIN()
diff --git a/examples/raytracingshadows/raytracingshadows.cpp b/examples/raytracingshadows/raytracingshadows.cpp
new file mode 100644
index 00000000..892d1658
--- /dev/null
+++ b/examples/raytracingshadows/raytracingshadows.cpp
@@ -0,0 +1,870 @@
+/*
+* Vulkan Example - Hardware accelerated ray tracing shadow example using VK_KHR_ray_traying
+*
+* Renders a complex scene using multiple hit and miss shaders for implementing shadows
+*
+* Copyright (C) by Sascha Willems - www.saschawillems.de
+*
+* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+*/
+
+#define VK_ENABLE_BETA_EXTENSIONS
+
+#include "vulkanexamplebase.h"
+#include "VulkanglTFModel.h"
+
+// Ray tracing utility structures, see ray tracing basic sample for details
+struct RayTracingScratchBuffer
+{
+ uint64_t deviceAddress = 0;
+ VkBuffer buffer = VK_NULL_HANDLE;
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+};
+
+struct RayTracingObjectMemory
+{
+ uint64_t deviceAddress = 0;
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+};
+
+struct AccelerationStructure {
+ VkAccelerationStructureKHR accelerationStructure;
+ uint64_t handle;
+ RayTracingObjectMemory objectMemory;
+};
+
+// Indices for the different ray tracing groups used in this example
+#define INDEX_RAYGEN_GROUP 0
+#define INDEX_MISS_GROUP 1
+#define INDEX_CLOSEST_HIT_GROUP 3
+
+class VulkanExample : public VulkanExampleBase
+{
+public:
+ PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR;
+ PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR;
+ PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR;
+ PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR;
+ PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR;
+ PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR;
+ PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR;
+ PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR;
+ PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR;
+ PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR;
+ PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR;
+
+ VkPhysicalDeviceRayTracingPropertiesKHR rayTracingProperties{};
+ VkPhysicalDeviceRayTracingFeaturesKHR rayTracingFeatures{};
+
+ VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{};
+ VkPhysicalDeviceRayTracingFeaturesKHR enabledRayTracingFeatures{};
+
+ AccelerationStructure bottomLevelAS;
+ AccelerationStructure topLevelAS;
+
+ std::vector shaderGroups{};
+ vks::Buffer shaderBindingTable;
+
+ struct StorageImage {
+ VkDeviceMemory memory;
+ VkImage image;
+ VkImageView view;
+ VkFormat format;
+ } storageImage;
+
+ struct UniformData {
+ glm::mat4 viewInverse;
+ glm::mat4 projInverse;
+ glm::vec4 lightPos;
+ int32_t vertexSize;
+ } uniformData;
+ vks::Buffer ubo;
+
+ VkPipeline pipeline;
+ VkPipelineLayout pipelineLayout;
+ VkDescriptorSet descriptorSet;
+ VkDescriptorSetLayout descriptorSetLayout;
+
+ vkglTF::Model scene;
+
+ VulkanExample() : VulkanExampleBase()
+ {
+ title = "Ray traced shadows";
+ settings.overlay = false;
+ timerSpeed *= 0.25f;
+ camera.type = Camera::CameraType::lookat;
+ camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
+ camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
+ camera.setTranslation(glm::vec3(0.0f, 3.0f, -10.0f));
+ // Enable instance and device extensions required to use VK_KHR_ray_tracing
+ enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
+ enabledDeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
+ // We require Vulkan 1.2 for ray tracing
+ apiVersion = VK_API_VERSION_1_2;
+ }
+
+ ~VulkanExample()
+ {
+ vkDestroyPipeline(device, pipeline, nullptr);
+ vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
+ vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
+ vkDestroyImageView(device, storageImage.view, nullptr);
+ vkDestroyImage(device, storageImage.image, nullptr);
+ vkFreeMemory(device, storageImage.memory, nullptr);
+ vkDestroyAccelerationStructureKHR(device, bottomLevelAS.accelerationStructure, nullptr);
+ vkDestroyAccelerationStructureKHR(device, topLevelAS.accelerationStructure, nullptr);
+ shaderBindingTable.destroy();
+ ubo.destroy();
+ deleteObjectMemory(bottomLevelAS.objectMemory);
+ deleteObjectMemory(topLevelAS.objectMemory);
+ }
+
+ /*
+ Ray tracing utility functions, see ray tracing basic sample for details
+ */
+ RayTracingScratchBuffer createScratchBuffer(VkAccelerationStructureKHR accelerationStructure)
+ {
+ RayTracingScratchBuffer scratchBuffer{};
+ VkMemoryRequirements2 memoryRequirements2{};
+ memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+ VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{};
+ accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR;
+ accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR;
+ accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR;
+ accelerationStructureMemoryRequirements.accelerationStructure = accelerationStructure;
+ vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2);
+ VkBufferCreateInfo bufferCI{};
+ bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferCI.size = memoryRequirements2.memoryRequirements.size;
+ bufferCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+ bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCI, nullptr, &scratchBuffer.buffer));
+ VkMemoryRequirements memoryRequirements{};
+ vkGetBufferMemoryRequirements(device, scratchBuffer.buffer, &memoryRequirements);
+ VkMemoryAllocateFlagsInfo memoryAllocateFI{};
+ memoryAllocateFI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
+ memoryAllocateFI.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
+ VkMemoryAllocateInfo memoryAI{};
+ memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memoryAI.pNext = &memoryAllocateFI;
+ memoryAI.allocationSize = memoryRequirements.size;
+ memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &scratchBuffer.memory));
+ VK_CHECK_RESULT(vkBindBufferMemory(device, scratchBuffer.buffer, scratchBuffer.memory, 0));
+ VkBufferDeviceAddressInfoKHR buffer_device_address_info{};
+ buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
+ buffer_device_address_info.buffer = scratchBuffer.buffer;
+ scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(device, &buffer_device_address_info);
+ return scratchBuffer;
+ }
+
+ void deleteScratchBuffer(RayTracingScratchBuffer& scratchBuffer)
+ {
+ if (scratchBuffer.memory != VK_NULL_HANDLE) {
+ vkFreeMemory(device, scratchBuffer.memory, nullptr);
+ }
+ if (scratchBuffer.buffer != VK_NULL_HANDLE) {
+ vkDestroyBuffer(device, scratchBuffer.buffer, nullptr);
+ }
+ }
+
+ RayTracingObjectMemory createObjectMemory(VkAccelerationStructureKHR acceleration_structure)
+ {
+ RayTracingObjectMemory objectMemory{};
+ VkMemoryRequirements2 memoryRequirements2{};
+ memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+ VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{};
+ accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR;
+ accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR;
+ accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR;
+ accelerationStructureMemoryRequirements.accelerationStructure = acceleration_structure;
+ vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2);
+ VkMemoryRequirements memoryRequirements = memoryRequirements2.memoryRequirements;
+ VkMemoryAllocateInfo memoryAI{};
+ memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memoryAI.allocationSize = memoryRequirements.size;
+ memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &objectMemory.memory));
+ return objectMemory;
+ }
+
+ void deleteObjectMemory(RayTracingObjectMemory& objectMemory)
+ {
+ if (objectMemory.memory != VK_NULL_HANDLE) {
+ vkFreeMemory(device, objectMemory.memory, nullptr);
+ }
+ }
+
+ uint64_t getBufferDeviceAddress(VkBuffer buffer)
+ {
+ VkBufferDeviceAddressInfoKHR bufferDeviceAI{};
+ bufferDeviceAI.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
+ bufferDeviceAI.buffer = buffer;
+ return vkGetBufferDeviceAddressKHR(device, &bufferDeviceAI);
+ }
+
+ /*
+ Set up a storage image that the ray generation shader will be writing to
+ */
+ void createStorageImage()
+ {
+ VkImageCreateInfo image = vks::initializers::imageCreateInfo();
+ image.imageType = VK_IMAGE_TYPE_2D;
+ image.format = swapChain.colorFormat;
+ image.extent.width = width;
+ image.extent.height = height;
+ image.extent.depth = 1;
+ image.mipLevels = 1;
+ image.arrayLayers = 1;
+ image.samples = VK_SAMPLE_COUNT_1_BIT;
+ image.tiling = VK_IMAGE_TILING_OPTIMAL;
+ image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
+ image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &storageImage.image));
+
+ VkMemoryRequirements memReqs;
+ vkGetImageMemoryRequirements(device, storageImage.image, &memReqs);
+ VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
+ memoryAllocateInfo.allocationSize = memReqs.size;
+ memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &storageImage.memory));
+ VK_CHECK_RESULT(vkBindImageMemory(device, storageImage.image, storageImage.memory, 0));
+
+ VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
+ colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ colorImageView.format = swapChain.colorFormat;
+ colorImageView.subresourceRange = {};
+ colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ colorImageView.subresourceRange.baseMipLevel = 0;
+ colorImageView.subresourceRange.levelCount = 1;
+ colorImageView.subresourceRange.baseArrayLayer = 0;
+ colorImageView.subresourceRange.layerCount = 1;
+ colorImageView.image = storageImage.image;
+ VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &storageImage.view));
+
+ VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vks::tools::setImageLayout(cmdBuffer, storageImage.image,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_GENERAL,
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
+ vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
+ }
+
+ /*
+ Create the bottom level acceleration structure contains the scene's actual geometry (vertices, triangles)
+ */
+ void createBottomLevelAccelerationStructure()
+ {
+ // Instead of a simple triangle, we'll be loading a more complex scene for this example
+ // The shaders are accessing the vertex and index buffers of the scene, so the proper usage flag has to be set on the vertex and index buffers for the scene
+ vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+ const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::PreMultiplyVertexColors | vkglTF::FileLoadingFlags::FlipY;
+ scene.loadFromFile(getAssetPath() + "models/vulkanscene_shadow.gltf", vulkanDevice, queue, glTFLoadingFlags);
+
+ const uint32_t numTriangles = static_cast(scene.indices.count) / 3;
+
+ VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{};
+ VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{};
+
+ vertexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.vertices.buffer);
+ indexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.indices.buffer);
+
+ VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{};
+ accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR;
+ accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ accelerationCreateGeometryInfo.maxPrimitiveCount = numTriangles;
+ accelerationCreateGeometryInfo.indexType = VK_INDEX_TYPE_UINT32;
+ accelerationCreateGeometryInfo.maxVertexCount = static_cast(scene.vertices.count);
+ accelerationCreateGeometryInfo.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
+ accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE;
+
+ VkAccelerationStructureCreateInfoKHR accelerationCI{};
+ accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationCI.maxGeometryCount = 1;
+ accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo;
+ VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &bottomLevelAS.accelerationStructure));
+
+ // Bind object memory to the top level acceleration structure
+ bottomLevelAS.objectMemory = createObjectMemory(bottomLevelAS.accelerationStructure);
+
+ VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{};
+ bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR;
+ bindAccelerationMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
+ bindAccelerationMemoryInfo.memory = bottomLevelAS.objectMemory.memory;
+ VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo));
+
+ VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
+ accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ accelerationStructureGeometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
+ accelerationStructureGeometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
+ accelerationStructureGeometry.geometry.triangles.vertexData.deviceAddress = vertexBufferDeviceAddress.deviceAddress;
+ accelerationStructureGeometry.geometry.triangles.vertexStride = sizeof(vkglTF::Vertex);
+ accelerationStructureGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
+ accelerationStructureGeometry.geometry.triangles.indexData.deviceAddress = indexBufferDeviceAddress.deviceAddress;
+
+ std::vector acceleration_geometries = { accelerationStructureGeometry };
+ VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data();
+
+ // Create a small scratch buffer used during build of the bottom level acceleration structure
+ RayTracingScratchBuffer scratchBuffer = createScratchBuffer(bottomLevelAS.accelerationStructure);
+
+ VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
+ accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationBuildGeometryInfo.update = VK_FALSE;
+ accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.accelerationStructure;
+ accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE;
+ accelerationBuildGeometryInfo.geometryCount = 1;
+ accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries;
+ accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
+
+ VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{};
+ accelerationBuildOffsetInfo.primitiveCount = numTriangles;
+ accelerationBuildOffsetInfo.primitiveOffset = 0x0;
+ accelerationBuildOffsetInfo.firstVertex = 0;
+ accelerationBuildOffsetInfo.transformOffset = 0x0;
+
+ std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo };
+
+ if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands)
+ {
+ // Implementation supports building acceleration structure building on host
+ VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()));
+ }
+ else
+ {
+ // Acceleration structure needs to be build on the device
+ VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data());
+ vulkanDevice->flushCommandBuffer(commandBuffer, queue);
+ }
+
+ VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
+ accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
+ accelerationDeviceAddressInfo.accelerationStructure = bottomLevelAS.accelerationStructure;
+
+ bottomLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
+
+ deleteScratchBuffer(scratchBuffer);
+ }
+
+ /*
+ The top level acceleration structure contains the scene's object instances
+ */
+ void createTopLevelAccelerationStructure()
+ {
+ VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{};
+ accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR;
+ accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ accelerationCreateGeometryInfo.maxPrimitiveCount = 1;
+ accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE;
+
+ VkAccelerationStructureCreateInfoKHR accelerationCI{};
+ accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationCI.maxGeometryCount = 1;
+ accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo;
+ VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &topLevelAS.accelerationStructure));
+
+ // Bind object memory to the top level acceleration structure
+ topLevelAS.objectMemory = createObjectMemory(topLevelAS.accelerationStructure);
+
+ VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{};
+ bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR;
+ bindAccelerationMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure;
+ bindAccelerationMemoryInfo.memory = topLevelAS.objectMemory.memory;
+ VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo));
+
+ VkTransformMatrixKHR transform_matrix = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f };
+
+ VkAccelerationStructureInstanceKHR instance{};
+ instance.transform = transform_matrix;
+ instance.instanceCustomIndex = 0;
+ instance.mask = 0xFF;
+ instance.instanceShaderBindingTableRecordOffset = 0;
+ instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
+ instance.accelerationStructureReference = bottomLevelAS.handle;
+
+ // Buffer for instance data
+ vks::Buffer instancesBuffer;
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &instancesBuffer,
+ sizeof(instance),
+ &instance));
+
+ VkDeviceOrHostAddressConstKHR instance_data_device_address{};
+ instance_data_device_address.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer);
+
+ VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
+ accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
+ accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ accelerationStructureGeometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
+ accelerationStructureGeometry.geometry.instances.arrayOfPointers = VK_FALSE;
+ accelerationStructureGeometry.geometry.instances.data.deviceAddress = instance_data_device_address.deviceAddress;
+
+ std::vector acceleration_geometries = { accelerationStructureGeometry };
+ VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data();
+
+ // Create a small scratch buffer used during build of the top level acceleration structure
+ RayTracingScratchBuffer scratchBuffer = createScratchBuffer(topLevelAS.accelerationStructure);
+
+ VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
+ accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
+ accelerationBuildGeometryInfo.update = VK_FALSE;
+ accelerationBuildGeometryInfo.srcAccelerationStructure = VK_NULL_HANDLE;
+ accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.accelerationStructure;
+ accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE;
+ accelerationBuildGeometryInfo.geometryCount = 1;
+ accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries;
+ accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress;
+
+ VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{};
+ accelerationBuildOffsetInfo.primitiveCount = 1;
+ accelerationBuildOffsetInfo.primitiveOffset = 0x0;
+ accelerationBuildOffsetInfo.firstVertex = 0;
+ accelerationBuildOffsetInfo.transformOffset = 0x0;
+ std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo };
+
+ if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands)
+ {
+ // Implementation supports building acceleration structure building on host
+ VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()));
+ }
+ else
+ {
+ // Acceleration structure needs to be build on the device
+ VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
+ vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data());
+ vulkanDevice->flushCommandBuffer(commandBuffer, queue);
+ }
+
+ VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
+ accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
+ accelerationDeviceAddressInfo.accelerationStructure = topLevelAS.accelerationStructure;
+
+ topLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
+
+ deleteScratchBuffer(scratchBuffer);
+ instancesBuffer.destroy();
+ }
+
+ /*
+ Create the Shader Binding Table that binds the programs and top-level acceleration structure
+ */
+ void createShaderBindingTable() {
+ const uint32_t groupCount = static_cast(shaderGroups.size());
+
+ const uint32_t sbtSize = rayTracingProperties.shaderGroupBaseAlignment * groupCount;
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &shaderBindingTable, sbtSize));
+ shaderBindingTable.map();
+
+ // Write the shader handles to the shader binding table
+ std::vector shaderHandleStorage(sbtSize);
+ VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()));
+
+ auto* data = static_cast(shaderBindingTable.mapped);
+ // This part is required, as the alignment and handle size may differ
+ for (uint32_t i = 0; i < groupCount; i++)
+ {
+ memcpy(data, shaderHandleStorage.data() + i * rayTracingProperties.shaderGroupHandleSize, rayTracingProperties.shaderGroupHandleSize);
+ data += rayTracingProperties.shaderGroupBaseAlignment;
+ }
+ shaderBindingTable.unmap();
+ }
+
+ /*
+ Create the descriptor sets used for the ray tracing dispatch
+ */
+ void createDescriptorSets()
+ {
+ std::vector poolSizes = {
+ { VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 },
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2 }
+ };
+ VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1);
+ VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
+
+ VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
+ VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet));
+
+ VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo{};
+ descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
+ descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
+ descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure;
+
+ VkWriteDescriptorSet accelerationStructureWrite{};
+ accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ // The specialized acceleration structure descriptor has to be chained
+ accelerationStructureWrite.pNext = &descriptorAccelerationStructureInfo;
+ accelerationStructureWrite.dstSet = descriptorSet;
+ accelerationStructureWrite.dstBinding = 0;
+ accelerationStructureWrite.descriptorCount = 1;
+ accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+
+ VkDescriptorImageInfo storageImageDescriptor{};
+ storageImageDescriptor.imageView = storageImage.view;
+ storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+ VkDescriptorBufferInfo vertexBufferDescriptor{};
+ vertexBufferDescriptor.buffer = scene.vertices.buffer;
+ vertexBufferDescriptor.range = VK_WHOLE_SIZE;
+
+ VkDescriptorBufferInfo indexBufferDescriptor{};
+ indexBufferDescriptor.buffer = scene.indices.buffer;
+ indexBufferDescriptor.range = VK_WHOLE_SIZE;
+
+ VkWriteDescriptorSet resultImageWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor);
+ VkWriteDescriptorSet uniformBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor);
+ VkWriteDescriptorSet vertexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor);
+ VkWriteDescriptorSet indexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor);
+
+ std::vector writeDescriptorSets = {
+ accelerationStructureWrite,
+ resultImageWrite,
+ uniformBufferWrite,
+ vertexBufferWrite,
+ indexBufferWrite
+ };
+ vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE);
+ }
+
+ /*
+ Create our ray tracing pipeline
+ */
+ void createRayTracingPipeline()
+ {
+ VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding{};
+ accelerationStructureLayoutBinding.binding = 0;
+ accelerationStructureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+ accelerationStructureLayoutBinding.descriptorCount = 1;
+ accelerationStructureLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding resultImageLayoutBinding{};
+ resultImageLayoutBinding.binding = 1;
+ resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ resultImageLayoutBinding.descriptorCount = 1;
+ resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding uniformBufferBinding{};
+ uniformBufferBinding.binding = 2;
+ uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uniformBufferBinding.descriptorCount = 1;
+ uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding vertexBufferBinding{};
+ vertexBufferBinding.binding = 3;
+ vertexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ vertexBufferBinding.descriptorCount = 1;
+ vertexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+
+ VkDescriptorSetLayoutBinding indexBufferBinding{};
+ indexBufferBinding.binding = 4;
+ indexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ indexBufferBinding.descriptorCount = 1;
+ indexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+
+ std::vector bindings({
+ accelerationStructureLayoutBinding,
+ resultImageLayoutBinding,
+ uniformBufferBinding,
+ vertexBufferBinding,
+ indexBufferBinding
+ });
+
+ VkDescriptorSetLayoutCreateInfo layoutInfo{};
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = static_cast(bindings.size());
+ layoutInfo.pBindings = bindings.data();
+ VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout));
+
+ VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
+ pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutCreateInfo.setLayoutCount = 1;
+ pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
+
+ VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
+
+ const uint32_t shaderIndexRaygen = 0;
+ const uint32_t shaderIndexMiss = 1;
+ const uint32_t shaderIndexShadowMiss = 2;
+ const uint32_t shaderIndexClosestHit = 3;
+
+ std::array shaderStages;
+ shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "raytracingshadows/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR);
+ shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "raytracingshadows/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR);
+ shaderStages[shaderIndexShadowMiss] = loadShader(getShadersPath() + "raytracingshadows/shadow.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR);
+ shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "raytracingshadows/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
+
+ /*
+ Setup ray tracing shader groups
+ */
+ VkRayTracingShaderGroupCreateInfoKHR raygenGroupCI{};
+ raygenGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ raygenGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
+ raygenGroupCI.generalShader = shaderIndexRaygen;
+ raygenGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR;
+ raygenGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ raygenGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(raygenGroupCI);
+
+ VkRayTracingShaderGroupCreateInfoKHR missGroupCI{};
+ missGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ missGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
+ missGroupCI.generalShader = shaderIndexMiss;
+ missGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR;
+ missGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ missGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(missGroupCI);
+ // Second miss group for the shadow miss shader
+ missGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV;
+ missGroupCI.generalShader = shaderIndexShadowMiss;
+ shaderGroups.push_back(missGroupCI);
+
+ VkRayTracingShaderGroupCreateInfoKHR closesHitGroupCI{};
+ closesHitGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ closesHitGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
+ closesHitGroupCI.generalShader = VK_SHADER_UNUSED_KHR;
+ closesHitGroupCI.closestHitShader = shaderIndexClosestHit;
+ closesHitGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR;
+ closesHitGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR;
+ shaderGroups.push_back(closesHitGroupCI);
+
+ VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI{};
+ rayTracingPipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
+ rayTracingPipelineCI.stageCount = static_cast(shaderStages.size());
+ rayTracingPipelineCI.pStages = shaderStages.data();
+ rayTracingPipelineCI.groupCount = static_cast(shaderGroups.size());
+ rayTracingPipelineCI.pGroups = shaderGroups.data();
+ rayTracingPipelineCI.maxRecursionDepth = 2;
+ rayTracingPipelineCI.layout = pipelineLayout;
+ rayTracingPipelineCI.libraries.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR;
+ VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline));
+ }
+
+ /*
+ Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
+ */
+ void createUniformBuffer()
+ {
+ VK_CHECK_RESULT(vulkanDevice->createBuffer(
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &ubo,
+ sizeof(uniformData),
+ &uniformData));
+ VK_CHECK_RESULT(ubo.map());
+
+ updateUniformBuffers();
+ }
+
+ /*
+ Command buffer generation
+ */
+ void buildCommandBuffers()
+ {
+ VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
+
+ VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
+
+ for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
+ {
+ VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
+
+ /*
+ Dispatch the ray tracing commands
+ */
+ vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
+ vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout, 0, 1, &descriptorSet, 0, 0);
+
+ /*
+ Setup the buffer regions pointing to the shader groups in the shader binding table
+ */
+ const VkDeviceSize sbtSize = rayTracingProperties.shaderGroupBaseAlignment * (VkDeviceSize)shaderGroups.size();
+
+ VkStridedBufferRegionKHR raygenShaderSBTEntry{};
+ raygenShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ raygenShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_RAYGEN_GROUP);
+ raygenShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ raygenShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR missShaderSBTEntry{};
+ missShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ missShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_MISS_GROUP);
+ missShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ missShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR hitShaderSBTEntry{};
+ hitShaderSBTEntry.buffer = shaderBindingTable.buffer;
+ hitShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_CLOSEST_HIT_GROUP);
+ hitShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment;
+ hitShaderSBTEntry.size = sbtSize;
+
+ VkStridedBufferRegionKHR callableShaderSBTEntry{};
+
+ vkCmdTraceRaysKHR(
+ drawCmdBuffers[i],
+ &raygenShaderSBTEntry,
+ &missShaderSBTEntry,
+ &hitShaderSBTEntry,
+ &callableShaderSBTEntry,
+ width,
+ height,
+ 1);
+
+ /*
+ Copy ray tracing output to swap chain image
+ */
+
+ // Prepare current swap chain image as transfer destination
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ swapChain.images[i],
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ subresourceRange);
+
+ // Prepare ray tracing output image as transfer source
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ storageImage.image,
+ VK_IMAGE_LAYOUT_GENERAL,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ subresourceRange);
+
+ VkImageCopy copyRegion{};
+ copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.srcOffset = { 0, 0, 0 };
+ copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.dstOffset = { 0, 0, 0 };
+ copyRegion.extent = { width, height, 1 };
+ vkCmdCopyImage(drawCmdBuffers[i], storageImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapChain.images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
+
+ // Transition swap chain image back for presentation
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ swapChain.images[i],
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ subresourceRange);
+
+ // Transition ray tracing output image back to general layout
+ vks::tools::setImageLayout(
+ drawCmdBuffers[i],
+ storageImage.image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ VK_IMAGE_LAYOUT_GENERAL,
+ subresourceRange);
+
+ VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
+ }
+ }
+
+ void updateUniformBuffers()
+ {
+ uniformData.projInverse = glm::inverse(camera.matrices.perspective);
+ uniformData.viewInverse = glm::inverse(camera.matrices.view);
+ uniformData.lightPos = glm::vec4(cos(glm::radians(timer * 360.0f)) * 40.0f, -50.0f + sin(glm::radians(timer * 360.0f)) * 20.0f, 25.0f + sin(glm::radians(timer * 360.0f)) * 5.0f, 0.0f);
+ // Pass the vertex size to the shader for unpacking vertices
+ uniformData.vertexSize = sizeof(vkglTF::Vertex);
+ memcpy(ubo.mapped, &uniformData, sizeof(uniformData));
+ }
+
+ void getEnabledFeatures()
+ {
+ // Enable features required for ray tracing using feature chaining via pNext
+ enabledBufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
+ enabledBufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE;
+
+ enabledRayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+ enabledRayTracingFeatures.rayTracing = VK_TRUE;
+ enabledRayTracingFeatures.pNext = &enabledBufferDeviceAddresFeatures;
+
+ deviceCreatepNextChain = &enabledRayTracingFeatures;
+ }
+
+ void prepare()
+ {
+ VulkanExampleBase::prepare();
+
+ // Query the ray tracing properties of the current implementation, we will need them later on
+ rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR;
+ VkPhysicalDeviceProperties2 deviceProps2{};
+ deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ deviceProps2.pNext = &rayTracingProperties;
+ vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2);
+
+ // Query the ray tracing properties of the current implementation, we will need them later on
+ rayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR;
+ VkPhysicalDeviceFeatures2 deviceFeatures2{};
+ deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ deviceFeatures2.pNext = &rayTracingFeatures;
+ vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
+
+ // Get the function pointers required for ray tracing
+ vkGetBufferDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
+ vkBindAccelerationStructureMemoryKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryKHR"));
+ vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR"));
+ vkDestroyAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR"));
+ vkGetAccelerationStructureMemoryRequirementsKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsKHR"));
+ vkCmdBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureKHR"));
+ vkBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructureKHR"));
+ vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR"));
+ vkCmdTraceRaysKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR"));
+ vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR"));
+ vkCreateRayTracingPipelinesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR"));
+
+ // Create the acceleration structures used to render the ray traced scene
+ createBottomLevelAccelerationStructure();
+ createTopLevelAccelerationStructure();
+
+ createStorageImage();
+ createUniformBuffer();
+ createRayTracingPipeline();
+ createShaderBindingTable();
+ createDescriptorSets();
+ buildCommandBuffers();
+ prepared = true;
+ }
+
+ void draw()
+ {
+ VulkanExampleBase::prepareFrame();
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
+ VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
+ VulkanExampleBase::submitFrame();
+ }
+
+ virtual void render()
+ {
+ if (!prepared)
+ return;
+ draw();
+ if (!paused || camera.updated)
+ updateUniformBuffers();
+ }
+};
+
+VULKAN_EXAMPLE_MAIN()