From ee946e2abfcf27e883afa191160919e4096aab43 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 15 Aug 2020 17:59:02 +0200 Subject: [PATCH] Update ray tracing samples to use VK_KHR_ray_tracing (#753) * Started updating ray tracing samples to KHR extension * Updated GLSL shaders to use GL_EXT_ray_tracing * Code cleanup, naming * Fix include directories to use Vulkan headers from repository instead of NDK for the Android build * Added new Android function pointers * Renamed basic ray tracing sample Added android build files * Remove unused batch file * Replaced remaining NV identifiers * Updating ray tracing shadow sample to KHR extension * Updated shaders to use KHR instead of NV extension Fixed shader bindings * Updating ray tracing reflections sample to KHR extension * Renamed ray tracing reflections sample * Renamed ray tracing shadows sample Added android build files * Removed no-longer used batch files for shader generation * Proper alignment for the shader binding table * Updated readme * Reworked shader group setup * Cleanup * Reworked shader group setup * Reworked shader group setup * Code cleanup --- README.md | 27 +- android/examples/base/CMakeLists.txt | 1 + android/examples/base/liblibktx.a | Bin 0 -> 145320 bytes .../examples/raytracingbasic/CMakeLists.txt | 34 + android/examples/raytracingbasic/build.gradle | 60 ++ .../src/main/AndroidManifest.xml | 24 + .../vulkanSample/VulkanActivity.java | 58 ++ .../raytracingreflections/CMakeLists.txt | 35 + .../raytracingreflections/build.gradle | 65 ++ .../src/main/AndroidManifest.xml | 24 + .../vulkanSample/VulkanActivity.java | 58 ++ .../examples/raytracingshadows/CMakeLists.txt | 35 + .../examples/raytracingshadows/build.gradle | 65 ++ .../src/main/AndroidManifest.xml | 24 + .../vulkanSample/VulkanActivity.java | 58 ++ base/VulkanAndroid.cpp | 4 + base/VulkanAndroid.h | 2 + data/shaders/glsl/base/generate-spirv.bat | 2 - data/shaders/glsl/bloom/generate-spirv.bat | 12 - .../glsl/computeparticles/generate-spirv.bat | 5 - .../glsl/computeraytracing/generate-spirv.bat | 3 - .../glsl/computeshader/generate-spirv.bat | 7 - .../glsl/debugmarker/generate-spirv.bat | 6 - .../glsl/displacement/generate-spirv.bat | 5 - .../distancefieldfonts/generate-spirv.bat | 5 - .../glsl/geometryshader/generate-spirv.bat | 5 - .../glsl/indirectdraw/generate-spirv.bat | 6 - .../glsl/instancing/generate-spirv.bat | 2 - .../glsl/multithreading/generate-spirv.bat | 4 - .../glsl/nv_ray_tracing_basic/miss.rmiss | 9 - .../glsl/nv_ray_tracing_basic/miss.rmiss.spv | Bin 380 -> 0 bytes .../glsl/nv_ray_tracing_basic/raygen.rgen | 32 - .../glsl/nv_ray_tracing_basic/raygen.rgen.spv | Bin 3028 -> 0 bytes .../closesthit.rchit.spv | Bin 5552 -> 0 bytes .../closesthit.rchit.spv | Bin 5848 -> 0 bytes .../glsl/nv_ray_tracing_shadows/miss.rmiss | 9 - .../nv_ray_tracing_shadows/miss.rmiss.spv | Bin 380 -> 0 bytes .../glsl/nv_ray_tracing_shadows/shadow.rmiss | 9 - .../nv_ray_tracing_shadows/shadow.rmiss.spv | Bin 316 -> 0 bytes .../glsl/occlusionquery/generate-spirv.bat | 6 - .../glsl/particlefire/generate-spirv.bat | 7 - .../shaders/glsl/pipelines/generate-spriv.bat | 7 - .../glsl/radialblur/generate-spirv.bat | 7 - .../closesthit.rchit | 6 +- .../closesthit.rchit.spv | Bin 780 -> 788 bytes data/shaders/glsl/raytracingbasic/miss.rmiss | 9 + .../glsl/raytracingbasic/miss.rmiss.spv | Bin 0 -> 384 bytes data/shaders/glsl/raytracingbasic/raygen.rgen | 32 + .../glsl/raytracingbasic/raygen.rgen.spv | Bin 0 -> 2844 bytes .../closesthit.rchit | 10 +- .../closesthit.rchit.spv | Bin 0 -> 5800 bytes .../miss.rmiss | 6 +- .../miss.rmiss.spv | Bin 1296 -> 1300 bytes .../raygen.rgen | 16 +- .../raygen.rgen.spv | Bin 4640 -> 4660 bytes .../closesthit.rchit | 24 +- .../raytracingshadows/closesthit.rchit.spv | Bin 0 -> 5872 bytes .../shaders/glsl/raytracingshadows/miss.rmiss | 9 + .../glsl/raytracingshadows/miss.rmiss.spv | Bin 0 -> 384 bytes .../raygen.rgen | 16 +- .../raygen.rgen.spv | Bin 3076 -> 3096 bytes .../glsl/raytracingshadows/shadow.rmiss | 9 + .../glsl/raytracingshadows/shadow.rmiss.spv | Bin 0 -> 320 bytes .../glsl/shadowmapping/generate-spirv.bat | 7 - .../glsl/shadowmappingomni/generate-spirv.bat | 7 - .../sphericalenvmapping/generate-spirv.bat | 2 - .../terraintessellation/generate-spirv.bat | 7 - .../glsl/tessellation/generate-spriv.bat | 7 - data/shaders/glsl/texture/generate-spirv.bat | 3 - .../glsl/texturearray/generate-spirv.bat | 2 - .../glsl/vulkanscene/generate-spriv.bat | 8 - .../closesthit.rchit | 0 .../closesthit.rchit.spv | Bin .../miss.rmiss | 0 .../miss.rmiss.spv | Bin .../raygen.rgen | 0 .../raygen.rgen.spv | Bin .../closesthit.rchit | 0 .../closesthit.rchit.spv | Bin .../miss.rmiss | 0 .../miss.rmiss.spv | Bin .../raygen.rgen | 0 .../raygen.rgen.spv | Bin .../closesthit.rchit | 0 .../closesthit.rchit.spv | Bin .../miss.rmiss | 0 .../miss.rmiss.spv | Bin .../raygen.rgen | 0 .../raygen.rgen.spv | Bin .../shadow.rmiss | 0 .../shadow.rmiss.spv | Bin examples/CMakeLists.txt | 8 +- .../nv_ray_tracing_basic.cpp | 720 -------------- .../nv_ray_tracing_reflections.cpp | 738 --------------- .../nv_ray_tracing_shadows.cpp | 753 --------------- examples/raytracingbasic/raytracingbasic.cpp | 881 ++++++++++++++++++ .../raytracingreflections.cpp | 876 +++++++++++++++++ .../raytracingshadows/raytracingshadows.cpp | 870 +++++++++++++++++ 98 files changed, 3291 insertions(+), 2457 deletions(-) create mode 100644 android/examples/base/liblibktx.a create mode 100644 android/examples/raytracingbasic/CMakeLists.txt create mode 100644 android/examples/raytracingbasic/build.gradle create mode 100644 android/examples/raytracingbasic/src/main/AndroidManifest.xml create mode 100644 android/examples/raytracingbasic/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java create mode 100644 android/examples/raytracingreflections/CMakeLists.txt create mode 100644 android/examples/raytracingreflections/build.gradle create mode 100644 android/examples/raytracingreflections/src/main/AndroidManifest.xml create mode 100644 android/examples/raytracingreflections/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java create mode 100644 android/examples/raytracingshadows/CMakeLists.txt create mode 100644 android/examples/raytracingshadows/build.gradle create mode 100644 android/examples/raytracingshadows/src/main/AndroidManifest.xml create mode 100644 android/examples/raytracingshadows/src/main/java/de/saschawillems/vulkanSample/VulkanActivity.java delete mode 100644 data/shaders/glsl/base/generate-spirv.bat delete mode 100644 data/shaders/glsl/bloom/generate-spirv.bat delete mode 100644 data/shaders/glsl/computeparticles/generate-spirv.bat delete mode 100644 data/shaders/glsl/computeraytracing/generate-spirv.bat delete mode 100644 data/shaders/glsl/computeshader/generate-spirv.bat delete mode 100644 data/shaders/glsl/debugmarker/generate-spirv.bat delete mode 100644 data/shaders/glsl/displacement/generate-spirv.bat delete mode 100644 data/shaders/glsl/distancefieldfonts/generate-spirv.bat delete mode 100644 data/shaders/glsl/geometryshader/generate-spirv.bat delete mode 100644 data/shaders/glsl/indirectdraw/generate-spirv.bat delete mode 100644 data/shaders/glsl/instancing/generate-spirv.bat delete mode 100644 data/shaders/glsl/multithreading/generate-spirv.bat delete mode 100644 data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss delete mode 100644 data/shaders/glsl/nv_ray_tracing_basic/miss.rmiss.spv delete mode 100644 data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen delete mode 100644 data/shaders/glsl/nv_ray_tracing_basic/raygen.rgen.spv delete mode 100644 data/shaders/glsl/nv_ray_tracing_reflections/closesthit.rchit.spv delete mode 100644 data/shaders/glsl/nv_ray_tracing_shadows/closesthit.rchit.spv delete mode 100644 data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss delete mode 100644 data/shaders/glsl/nv_ray_tracing_shadows/miss.rmiss.spv delete mode 100644 data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss delete mode 100644 data/shaders/glsl/nv_ray_tracing_shadows/shadow.rmiss.spv delete mode 100644 data/shaders/glsl/occlusionquery/generate-spirv.bat delete mode 100644 data/shaders/glsl/particlefire/generate-spirv.bat delete mode 100644 data/shaders/glsl/pipelines/generate-spriv.bat delete mode 100644 data/shaders/glsl/radialblur/generate-spirv.bat rename data/shaders/glsl/{nv_ray_tracing_basic => raytracingbasic}/closesthit.rchit (62%) rename data/shaders/glsl/{nv_ray_tracing_basic => raytracingbasic}/closesthit.rchit.spv (55%) create mode 100644 data/shaders/glsl/raytracingbasic/miss.rmiss create mode 100644 data/shaders/glsl/raytracingbasic/miss.rmiss.spv create mode 100644 data/shaders/glsl/raytracingbasic/raygen.rgen create mode 100644 data/shaders/glsl/raytracingbasic/raygen.rgen.spv rename data/shaders/glsl/{nv_ray_tracing_reflections => raytracingreflections}/closesthit.rchit (88%) create mode 100644 data/shaders/glsl/raytracingreflections/closesthit.rchit.spv rename data/shaders/glsl/{nv_ray_tracing_reflections => raytracingreflections}/miss.rmiss (75%) rename data/shaders/glsl/{nv_ray_tracing_reflections => raytracingreflections}/miss.rmiss.spv (64%) rename data/shaders/glsl/{nv_ray_tracing_reflections => raytracingreflections}/raygen.rgen (70%) rename data/shaders/glsl/{nv_ray_tracing_reflections => raytracingreflections}/raygen.rgen.spv (75%) rename data/shaders/glsl/{nv_ray_tracing_shadows => raytracingshadows}/closesthit.rchit (70%) create mode 100644 data/shaders/glsl/raytracingshadows/closesthit.rchit.spv create mode 100644 data/shaders/glsl/raytracingshadows/miss.rmiss create mode 100644 data/shaders/glsl/raytracingshadows/miss.rmiss.spv rename data/shaders/glsl/{nv_ray_tracing_shadows => raytracingshadows}/raygen.rgen (50%) rename data/shaders/glsl/{nv_ray_tracing_shadows => raytracingshadows}/raygen.rgen.spv (69%) create mode 100644 data/shaders/glsl/raytracingshadows/shadow.rmiss create mode 100644 data/shaders/glsl/raytracingshadows/shadow.rmiss.spv delete mode 100644 data/shaders/glsl/shadowmapping/generate-spirv.bat delete mode 100644 data/shaders/glsl/shadowmappingomni/generate-spirv.bat delete mode 100644 data/shaders/glsl/sphericalenvmapping/generate-spirv.bat delete mode 100644 data/shaders/glsl/terraintessellation/generate-spirv.bat delete mode 100644 data/shaders/glsl/tessellation/generate-spriv.bat delete mode 100644 data/shaders/glsl/texture/generate-spirv.bat delete mode 100644 data/shaders/glsl/texturearray/generate-spirv.bat delete mode 100644 data/shaders/glsl/vulkanscene/generate-spriv.bat rename data/shaders/hlsl/{nv_ray_tracing_basic => raytracingbasic}/closesthit.rchit (100%) rename data/shaders/hlsl/{nv_ray_tracing_basic => raytracingbasic}/closesthit.rchit.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_basic => raytracingbasic}/miss.rmiss (100%) rename data/shaders/hlsl/{nv_ray_tracing_basic => raytracingbasic}/miss.rmiss.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_basic => raytracingbasic}/raygen.rgen (100%) rename data/shaders/hlsl/{nv_ray_tracing_basic => raytracingbasic}/raygen.rgen.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_reflections => raytracingreflections}/closesthit.rchit (100%) rename data/shaders/hlsl/{nv_ray_tracing_reflections => raytracingreflections}/closesthit.rchit.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_reflections => raytracingreflections}/miss.rmiss (100%) rename data/shaders/hlsl/{nv_ray_tracing_reflections => raytracingreflections}/miss.rmiss.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_reflections => raytracingreflections}/raygen.rgen (100%) rename data/shaders/hlsl/{nv_ray_tracing_reflections => raytracingreflections}/raygen.rgen.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/closesthit.rchit (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/closesthit.rchit.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/miss.rmiss (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/miss.rmiss.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/raygen.rgen (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/raygen.rgen.spv (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/shadow.rmiss (100%) rename data/shaders/hlsl/{nv_ray_tracing_shadows => raytracingshadows}/shadow.rmiss.spv (100%) delete mode 100644 examples/nv_ray_tracing_basic/nv_ray_tracing_basic.cpp delete mode 100644 examples/nv_ray_tracing_reflections/nv_ray_tracing_reflections.cpp delete mode 100644 examples/nv_ray_tracing_shadows/nv_ray_tracing_shadows.cpp create mode 100644 examples/raytracingbasic/raytracingbasic.cpp create mode 100644 examples/raytracingreflections/raytracingreflections.cpp create mode 100644 examples/raytracingshadows/raytracingshadows.cpp 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 0000000000000000000000000000000000000000..fa1df34b0abe51b6ad1fff7af810183a088b9feb GIT binary patch literal 145320 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 JD2FLm{|l_)i*f(} literal 0 HcmV?d00001 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 81c1464458dc3092a703f7fecd20c4a868a1f45e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 380 zcmZXQKT88q5X2|2>~JPHHQd+YmY-k4@`=97Jfjx_zlF*VH5B- zrxxNK%iEdVnYZu4VAzrxYN@R~eaF56y&p;)HMO|T@~bRg7cY6WE^f-zz0`$oFq))` zbo^A^jxQ$XR`wLu2JZD0>lKfPdRde!H$uLEbHhM{N0R=tMiu?h#4tN(9?B{!9-r^* zlQ3cK#DF-!)xM|o4XW!S>L%QPJZ7Fp*4P^kz-`VC_A`I^gY9W<1h%$AI(~7N`fZcW i&*)mWOM1rX-jrRvhu`e*U7s*9=Nx2zYqtEo8Tkd$q$EKA 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 bd277cc85ac08d36dd83621785f905bbe4112e52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3028 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 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 fe9e37d15829e64e6e67f3b05ff8be2b44053da5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5848 zcmZ9OioB@1#eiKwV34mdhPO)v=#*7MYOm~()mGv|zF&J1E^ zqab!MwXzF#v-{mHR+imFAjGgt$-IZv|Ip=my8M3o>=nD&^Q>pR@4LQlt@T~@KGW8^ zaB7mYB-8l&YtnpXCauYfbCTr5WJLRkl{jb>dTuPi`e?Cz7ur?;vM?x!x$>m@uo!k&=}70R-W=m<25UpLIzBXO4U7~^E;zLIOk0j`=WhmntU6L0yngZ6@>OaD_9jUx z)sij2+mhM%;S8UOzk2Nk@=Zy^KI4`0j&;@Xa(%S?Ki!^3>b2`8>-IfV*|xpW#{zjG zkNuN@eb`vJiOsj}X=r0xYAHSo>_Y5$0oXmO43@JTg;YaM*phV2LUC@4`Ie!TSh#ql z_}nI5<5#C)+l;UNo)p_-EbX(9eDMEbQ({m2Hk_Po}2t5qq+^Rv#)|RouBD4Xy7dHZ6U>aAOd~r_$J@lxk1mN4FPCwH@UWFx8&HH)z2j$N zKEW4&BR(HI1#9-!y!+6!hTeRRw}$hrozExF$FGH(uYlQK5%1$TAM>e2zCmz4pWJ-T zx1N_`I_5sey)W}HAGzO9zj}H%!k{Xrv55MPD}NKy)W?PPg3rD`H2}fm)zbQ?|SEf{9ZdpbFA^O1&lfg z?ilOY%S`-ytR?k@WES3-`ds2HJDuOm-~6Vkh2ETBpzl~;lB{B$+`D6+OS3w2!LGwK zpPt2>AMrE5-Xr7gv3=P4narA>;d$T%V7cSY##=+py7GmY7I_!JedO-(l9V;)F9kc_ zIuTz1ZpraWz>cwAC*Ho?LwQ%m-S4P(B{)C78y@TK$;NwTj@NI-l4RmC&+}a%_aw%@ z8*Dvw_u*Q+Yj7Wmc)5LS!P}#n`ye08G~*?(J(=6M+;>CG_;$SW%^mA#WSa30gJ0m# zU8nQqe#6y_-<{$7x*kG%;z;jm<39zzoSQHAT~v#Gcobfnwd>;G2jEHa*jnfR8f33g zUw$al>_>h$1DzU3~%HIQPAP`LtnwNAcTkZqMJ}eD8p~ z6Yp zL{^V~1JeH=uf#{a8aV11k9s3uV^Qx0uv*lsgY)%9;nq`+dShVq1{U?k!BNk6)Y}0z z7WHlftM##ZzX>}r*K8lgR&#^AFY0SppWpNMU}{US==0`GH?RBnUQEsT-Y5A*%rSYwa9-f*!(N7$bTDHJ@W4Yt2uu+ULN^x2b*8r_yk@p^4|eAzu)1=|9-G~ zeUf%x_uj&ouByGJO|gvr6| zn0n0nIM})BG4B)L$@M;orXFKHm5s^g-ixO0*`I*F4>P}Wjkz}8U3K$x;Xi|UUfyl@ z&Uv53)E(1<{~YGL{Q5ti>31>4Irn4EQ;*zV08e1~++T#NNA53y&7EJzm*MJ>`zv7Q zso$E_`zrW;%vjX>8rZYT*ZVqLJ?eb}Y`wTEp2;^c^{DqPu=CWT-nYTlG}e*r?{~m0 z*cF&@_t$Tsy7iXgzl)uQ`7XP^)A8TK)HiT*+`I2*n!1lUTd}C~gG{rIW3BT5UOmq2 zhhVkfKLXp!z4YN4e~dXsy@Ri@+D|ZREyj#Lgqiz6yfN1>5C1dFJ2DrGHT*o&V-3H6 zt7$&52FF|Lmza6uZvHCM)V15GgFj$m=dzXdx+JSdw{jn#Z}0k2~}v_+`wV{zh-d@IL>fH}yYZ$1wj-5JwMx z2D_iJ2Y&&py@JJFtNnv{$MDYA|BKVS5c7YL4)_er=Ok<;^{3)b#vFeN-v2{p;b&vU zn7uPS3UfvAO z_i_$gEqYlF&i8UI+%f9W%Xwh+6{da!zY*EWF7?ObEg zV_%A!zfJZicWmT-JJ@~5*S`v`9%D9UWAgPkp{d81tFtklLG;)UR`26&^iE!bncKO> gHe=5B9eqcNo9~!?${la64*WZ__`f*;vEPON0^vF+r~m)} 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 81c1464458dc3092a703f7fecd20c4a868a1f45e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 380 zcmZXQKT88q5X2|2>~JPHHQd+YmY-k4@`=97Jfjx_zlF*VH5B- zrxxNK%iEdVnYZu4VAzrxYN@R~eaF56y&p;)HMO|T@~bRg7cY6WE^f-zz0`$oFq))` zbo^A^jxQ$XR`wLu2JZD0>lKfPdRde!H$uLEbHhM{N0R=tMiu?h#4tN(9?B{!9-r^* zlQ3cK#DF-!)xM|o4XW!S>L%QPJZ7Fp*4P^kz-`VC_A`I^gY9W<1h%$AI(~7N`fZcW i&*)mWOM1rX-jrRvhu`e*U7s*9=Nx2zYqtEo8Tkd$q$EKA 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 f411b38dfdbcdc2a8b13717c6d95eb143240736e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 316 zcmZWky9&ZU5Zt_@f+D6C#m*vFs0e~>njk_TZ8(f*3L_)|@dNGr1o1m;1ZSd+c*ow} z&d$u;8v4i)(Zmr~n(|p)(dF(5YFnaBoUG%dP?w}C)HciaA}!z=s6iNoep#jdbT*-~ zEk-01GJiA{5Eq*ApwiQMm(nKygIFIyzaCEJ zVg14f^MKgE2H;{qdEhUsm*1LtVq<8CHxP5YMIZi|i_<)TSja0>)R6bW^b5orbL$~1 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 3a89e180e527cbc7d5d785969bfab09d2a755ff1..bbf4ba938782c8c7e454d01cd2a2d824d54bb746 100644 GIT binary patch delta 106 zcmeBSo5E(y%%sfDz{<$L#lXQJ&j0~}3``6!MHql$Yz)BxVe#G`LGeY2mGLD-iOHFH p=@X6B#n~B-02QzR)#oN==7F^F0I}@EOf!Dhh!AAe8`s4#0RXb37O4OL delta 98 zcmbQj*28AZ%%sfDz`)4B&cMMS&j0~}3``7nL>L&j7}yws1H$6{!s3e(E8|Ow5|cCY i(itWitMjum904j|0jkeU%*Cp7RrNdhd!V;{R-Xt23-Pw zZ!^$YhMD)~&HE4QI+wnAIV)Mw&g?I$=Gb@L;0iVw&7$F89IfKdC|$*iWch4m_#Dz8 zoP?eC^s#e$ccaa7b29_YDrnYtGC<$4Wc}nAdLF+>5;v8Ob+)v8123! z=`4Qzc%rocg}9~wQNvZf?d%21`UZUgu0>v;_o>3VvIQJHtn&|5z+9<>LOzjl84gAe2m&fO&L literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5cc908e5bb0ea59521e744d087231cc3c316104a GIT binary patch literal 2844 zcmZ9M+j10D6oxxzBmo4%Nf9StL?uQyMU~Rx1m0cPm-^O{JB^)wEuV2I0F1oh>hy$G2K*;}pYGo9(^S{xG-WCx|@9JzY;*tMSI;ByjF=tI;ec+sVe% za=VUuo^Hl9gJ!AYxeS6|hugMir2QNA9DdjA=mT^72m4IUKFbZjJ)g(5^IUglp0;_D zAk>lzd9&<`^}P?y%{@8|9Kjwz4}RBtN+(0V>+Ou!Hr}D%wRifp^*e{dRJHC1bMPjs zA4Tg&mcTLcou{_G680XXoH&BLH|P0d81FvHSKZSi3DJP77 z4e9*k?XT@Q$+-t_AWI<3NBbObm_LRz)_P%nZ=pNJn2GZ^599($=*C*>9S~}}SC@gq z+V3J=OFuAP|5aeTYoA8y^E^WDGJ50C)2qS$2s@fQdE0u6sDJVf%yX^U-Z{B3D#_mg zVV=srhP$J?Nb`Ae`Or3B+dJt9^Yf$hA2`7m?E%vHIp5CVeueY;qHq{%O>OV7!!=fs z?vpu}xicXbGhg>VFuqB1y}y1(-Lqi(t?ab@9tPXHGP=vYu*;t4usx53UAEsX>s_b6 z@8AIN4J^WX|NVZ*35R>pB-WgRK>rWLTi_US&Np#`)wvcqYa4$Q$c0|V(S0kS*9mkv z;ppu30=E7ii(W6HTTk9z?vq^T^%A<=PeuI8=yJZrrGgtlFBN!NaHp}2)n{GzTW$)! zZ{V#`vZ}%=_r_OYFFFxem;eFBJ&$yn$_BW1OdVM=s2B5`Fhtr{Lu6XZ;yq-Xgbm z8hNweW_&R*`E!zq!-M1hn_3eQsYB9Af9(Y6WMVaBk}b*LiL!ocYG<_uQ)Vd5E;H{(qUx G74SbVWW$O8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..41dde2cab4fba4d7f9556df12053ffebb3fd1dca GIT binary patch literal 5800 zcmZ9O`FC7(8HaD0Nm^)1DJ`~D2nns)TCJ3=V1XtOnpCQdO=;0{bePUe+ktc@OedkO zh(StmK|sX?+;A5caH)!lD_Bu0?kkJb-~0nSF6Zd+dG6eoTyt~Y^M2mXyMC8@Go5o* z%uTvFl9Q8p$zPN9vnZL9{B21B*PV=w?kHY0vaQ%G9W1t*rE;ylCz%i5LFn+7u`O%& zw<>GTzu+7*Pf0q{0{Rvv3zEmEQ2_5N)#^HyA}f$GQbq1W9zl*FCy-A5=Ae&LpujxC zTZ&g+v%Oev)Fi_-W^jI&HmX}4osUAZydXrhC&S8<|LaRY+u%D8ptF8&sxC+icX^7X4G z*KLq1uvbY^t5+NeyE9pg-k0Ii(N|x-m3rNY*k`I%y>WAWs@mLNeU5kLiDu)v*}QX) z*Y@mfjj}+VsN?)pU?0Y6hd2QHdM1;*8Yw;t>_VKmAMBph%GIn!A?2VGwj_=5EUgzY z)>{i#Vd3KS;&a=0&{)K^7tu3oFC-=G&GkxJ#`DqksUgODUx-irU985tvuC_G+N|xX zwQ5t<%|q=Thv28u`3uR-;E7VR6ni?YFP*E99G>MnqA#7Zki7l>d~=gKuy>W32g}uZ zt63{w(P%U)ZisVve@iXsUHen}gV=G0+`|X4({tESEw{Kea!27RjaHF!t4x+#Dfcb7 zZKZ>wrGw**Ql)*5q58Gaf{PT#Mm-2qI3&}}fZS%EH z&TMOGJBxnj?*;k2HAgX4e@H)33$Tr`pR+7N_aPmrE+nU+^~o>8&oa~ecK!A@Q7-s) zeu24TeMz!`JZ`B1tm6(er#g$UTYpH-POY?>=0Mb`9=B39aoMyU@-g=RRncGfsa6>`d0y zukBrz)4vyOzO`c=EpV*+o!}=qbk}LVw%=em^Y6;A>(PD)ZEozV{KLq7_b%VqOBcV9 z){+lx-nX%zp{9QOX!{Pz>3=lC=4k&2-GNxgcphD;f%sg=_r*08QmcJN|AgtnHrBK9|EuSvJ%B!xv*mBj*#qF|oUQ+G z&K>|C$=Uk-9~t$Bz<12D{XdxZ`+qR(5%AH>zLfdA3%e2T!C_XRy$A6x+IjfaRi} zzYX*K{HI&iZ$u??(KN z#Qw|!zboT!B}V(*h~G&0$a@diyjZt!_aO3-_g=8M@{#vG@a%r?hm(((4`ea<+V{fA zd-f-x??bF_u0Gf1yC`p+A@qk3&&#{*-kJAdMBbPY^hXf$^6UR-#@|VdIrk&x$w%#v zfv1st?T=&2N9|95t({-TC$Z(D_NTz+$={Oo`!x7|L|^p#4A`^F_xmiieDr$&Y`?fG zp2_DB`RMm~uzB*)?+aji>g&n&_lw{T{t% z?%h{1PTt3wbCBrs)r_-`vG#coEgxt0HLzURUk5wOJ|qQ8T9N0uS6hVN#4tl@jua*9u^!FYRpAF*!S%^zf(ymA}8+>0L~*3xhP zN70WVk02`%=hHSWYX2B~3^D$3^iL4uHzCGr8xwo;Q?Ppz^?wF7-ZL^@+ZeySBj}$a zvHsQI==((GJ4)Z<;9nqeJCT1-=T~T-f3pYreu>EW|5zOLe+`cM`S;*A@cN?uZ^3fb z{}(l)miq6UsWbczu~!#jynUSI4`?4}G3NJ(oU@2ymOp}Hmi#;NCwP4^%b&q=F-z1^ z$1G2R?d5#N+vfrH)cf!>qTl?dkT|<%z@CM7&9l%p_CMUHix7X`^k6SUd=?<9wewGc`#>mGkmxATJyD`gU;Fv{!%(4-z&sjWo?eJX=cCX_5b_G~Y z@rm!7_hJa!Z?kvBy|;FXAc#9Re-Px9ZGE!grA^QtVyy^cDs z2Fu5{bt~A~=IV>f4E!?>qY16wiDEw2ik`5BhbP|G&KJV!sRj19V;>8UO$Q literal 0 HcmV?d00001 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 f190c3317d3c4ead2f91f2d47cc6bf278bea4e6d..2d3d0e3bd3af6b5d50c454df4a2f3141b9aac652 100644 GIT binary patch delta 131 zcmbQhHHFKVnMs+Qft8Vgi-Ci|hyelw8JHMeiZB4h*cgHX!s5L>g5rx3E8|Ow5|cCY z(kB|L+psen1u9?xs?SZ#%mZoT24X27W(GngAbo}rB+tg+?i24C5rU$Bk{vTpXyavD F765bFhyelw8JHOEh%hj4F|aWN2ZY7@g~b;oR>qeUB_?O) qr87)4Ru^VtI0{t20#u)yn3)IC#yzo6j2~U)G&^R$FouoSZCL;i{uluO 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 5dc3472db3a0250a844ab91e66f1f710232c148b..aab87a9b1568af7b604e6d2962e1925324dc1d70 100644 GIT binary patch delta 153 zcmZ3WvPH$1nMs+Qft8Vgi-Ch-D+2@wGB7c`6k!00u`vV(gvEP%1jQF6R>qeUB_?O) zrB5_gXXKt3Ey=41RGtCEr9ixDVxbtnYeWc&!fBQUKp_SORt6RZQJ|vCywETp1?00c bhy&^LoOqwa(!Au1;LNI2uu6uFzf}bRVV=K!6|v6T=-51_mw$HiqDUuz0_)_@czh_>!W;+A$>QnI0c)4(;o>j&z^T?37Jaj;U|mQ00jA+)D&L*Mcp zjneW9ElrK)2NvIrSO%E(>F!^jcjC~^#W5_uYFg+D)L(vBzJU%P{vo67Y@`R0VI zrVW*h)OKLEr+(+J(xNzYGR9d($F!RR7qHqx?VKnMdli z8z%D3JyhAYz0uDCd7_TlWQ*|MeMcJQd-9I(e|kz#(Q^&PyOwz#(T7F zXrRAd8Ll)cW97Bo%^tVFkEQb$lH0%|#dz6tzL3NoXfjhY(Q_>k=mccjyvQYK7gH`!>00JgIgoFAFfnu3~+9x z(ZNQ_`95r~G&U87MqL_QAvu6<3^(5)?SrXZ^tz<}!{}PQvdxHg-WA^`_GELdK2%y? z+_f%s@%A+1r=;&%&fi_BGgGBjHN?4m5ApX_8XMCrIp512+l!^z&T^?)r#*d78?}+X z@>qGOYeSOsGF#lyc7l4z3)}nQljkO5PfxjKUJE#%r)^#*5_xhb^P2U&>Yf6ifC4>Nkt&p~{`UI-5V0`MfHIa~AoW2QaS*2~A+J6}&*zcX0>dbITli1QWE zKF0Z2PcHfog7fvXt!KXVyckmv_d(k`GavEM_Wbo9<@>Acw^jSG%=Ub>k7u@LYku_i z`ae`ncL9fGw9*^79c(gu$@hje;JWeQr_QyLUIaN+kEX)Guv9)&Zgh> z&Ifg%%~6ciAF`0B)3A-PpR>$BFF;yST}Wo4^~ul0&$83}X8q=ORWA5ueu24TeMz#4 zJZ>QI^6ta+XxHFA6w%twu?6i+a_)onV8-b$ft|_P`n7#Gtr!tB=MINF@wp?$Q?(e^vwk%*XFcA}t%!GX53APRhWPD}?_xK%qbrE_doiNl zT=)3~MBlAhts65gY7b%OYY$^vTYfz2$G-;Y|CDRc(XR%Me)^-|2v}eAy9q28{p#R+ zKmP}^pM3Ni1S}y9}0k*#1<*5H&uzb{iA6U+O@3VH){{Yzf^7{9p<*a`<`X0n@TkOvi z@P{&fH!<2DM*MEeN8U%k=Eb^=yBCpJ(Vs!g%dh{l8Gjcs=G>2%Cm*#x2OdZA zwLgz7AGN;#wsw9UU&NM=+Ft^jCx3g^@5|u(5q;6`D`3wq-|wr~^3m^WVEe^g@l3vs z$Vb0#fX$PSe%}P!Q(s56zuyA4AXg*$-Cw_j^7eZW{cU6p;=AnrPDOtQkzdEnaqqsH zaq>RaY(=8a_cG2t#@gorw0xY|_rY>u{{ZYP_cDiT{2^kDd==J2DrEHT*Q=V+}vUmQ#FU4aVE+=ZJMBX7@#(T`;K0Q%7kA4DHQ zVqL!kAIaH|fsbakeI7@SA<^g8U}NOtEPn&Gjy`)IM$3txL_dYt?>PGR$kUnaSv`js zAM1J^?7T7GAHZ=A&hrA|8lIiqk=A-fjCkLdX4;z8G1vIGD^Gx5M4ahw%yt6p^G{}z z|08k&@&5sF%c+Gl0lJhW?a z208aY|0@x>`2N2tdT@T0bFt-OmKEUqEazbxBOkL|0G2-=iCHcL$1M6|mW#mpoW;G@j#(}S z=V!SDTP|j~6r7)B6}B<*G0Wv(`OA=)Wi>cv(I2y10oLa%p1XGVt^~VR@eR2OET{Oi zAgze^q8sh^&%5H@TTj~@{k`b5i1m69d-(pn0g;cGYryV_XBshmVEKr7BiI=CI%3`g zmXF`obzp0ot1o8kPjT}%$QiYbjoNPpyAS#P>#^k{WCp7RrNdhd!V;{R-Xt23-Pw zZ!^$YhMD)~&HE4QI+wnAIV)Mw&g?I$=Gb@L;0iVw&7$F89IfKdC|$*iWch4m_#Dz8 zoP?eC^s#e$ccaa7b29_YDrnYtGC<$4Wc}nAdLF+>5;v8Ob+)v8123! z=`4Qzc%rocg}9~wQNvZf?d%21`UZUgu0>v;_o>3VvIQJHtn&|5z+9<>LOzjl84gAe2m&fO&L literal 0 HcmV?d00001 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 7a5d5f503479a4f108c1047737e3e87c60c9be0b..53552e71931018a8524ebd4176ea036fa298c083 100644 GIT binary patch delta 153 zcmZpXm?2@z%%sfDz{<$L#lXQ(%m4v`3``6!MHql$Yz)BxVe#G`LGeY2mGLD-iOHFH z=@X6B8M!A$OY&+0l}7<_8W87BEEMB+jR-+eIL*=kD8#_P%D}=P3RIMt7a9hnfP8ia baUh+Z6YrB)nwOjroLQ9$R>`pOHzzj$^!yCC)P5Esa2V-N?@={fN}iKThT8Nr!V MseWOb`58I60Y!!#o&W#< 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 0000000000000000000000000000000000000000..cf13a98acfee1e20fc78b2cde512214d1c019605 GIT binary patch literal 320 zcmY*Vy9&ZU5Zol5Pf*0vqS#pk3l%}IlL)2|6|oD45w%bu35XwP=Qr5<2R4E;iG^O6 z?CtE#?%i2tD<{g3qU3>eRmGI2Ey%O7n63QjWbTLh>c^qp98Nnafj1y^y@lsQao}`& z9XiWmB@I}sKyyQn4E9HTII)liEPN*79ij|0uIG=}%fI%bQ2F&KF!V-y9h@)Q09$dP zAXf+2uZBNkGntTbHkd592DCZE2hPKM_|54j*M^6D0qA2E`*1!NZ}bAA5J$-9q3(?r G7yutc1R>V| literal 0 HcmV?d00001 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()