diff --git a/.gitignore b/.gitignore index 326331ad33975431b6c8305167496aa9b1ff4dd7..8ab30e60ef913a4d49762b7326c878fc130696cc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .editorconfig # build directories +bin/ build/ cmake-build-debug/ cmake-build-release/ diff --git a/.gitmodules b/.gitmodules index c9eb19ee6ba09ded88a81b5ad253b2ae8c73c814..d59470fa0626799afe59be1dadcdaf76a719ff1c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,3 +40,6 @@ [submodule "modules/algorithm/lib/FidelityFX-SPD"] path = modules/algorithm/lib/FidelityFX-SPD url = https://github.com/GPUOpen-Effects/FidelityFX-SPD.git +[submodule "modules/upscaling/lib/FidelityFX-FSR2"] + path = modules/upscaling/lib/FidelityFX-FSR2 + url = https://github.com/TheJackiMonster/FidelityFX-FSR2.git diff --git a/modules/upscaling/CMakeLists.txt b/modules/upscaling/CMakeLists.txt index 47a963d43f0444216a7a972987a7d584333a1fc8..4578f97fd654a5cad0e66549fbc944ab16051b11 100644 --- a/modules/upscaling/CMakeLists.txt +++ b/modules/upscaling/CMakeLists.txt @@ -20,6 +20,9 @@ set(vkcv_upscaling_sources ${vkcv_upscaling_include}/vkcv/upscaling/NISUpscaling.hpp ${vkcv_upscaling_source}/vkcv/upscaling/NISUpscaling.cpp + + ${vkcv_upscaling_include}/vkcv/upscaling/FSR2Upscaling.hpp + ${vkcv_upscaling_source}/vkcv/upscaling/FSR2Upscaling.cpp ) # Setup some path variables to load libraries @@ -29,6 +32,9 @@ set(vkcv_upscaling_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_upscaling_lib}) # Check and load FidelityFX_FSR include(config/FidelityFX_FSR.cmake) +# Check and load FidelityFX_FSR2 +include(config/FidelityFX_FSR2.cmake) + # Check and load NVIDIAImageScaling include(config/NVIDIAImageScaling.cmake) diff --git a/modules/upscaling/config/FidelityFX_FSR2.cmake b/modules/upscaling/config/FidelityFX_FSR2.cmake new file mode 100644 index 0000000000000000000000000000000000000000..3dbc43e6721ae139f9ceb76c9f05b6fbce010fba --- /dev/null +++ b/modules/upscaling/config/FidelityFX_FSR2.cmake @@ -0,0 +1,14 @@ + +use_git_submodule("${vkcv_upscaling_lib_path}/FidelityFX-FSR2" ffx_fsr2_status) + +if (${ffx_fsr2_status}) + set(FFX_FSR2_API_DX12 OFF CACHE INTERNAL "") + set(FFX_FSR2_API_VK ON CACHE INTERNAL "") + + add_subdirectory(${vkcv_upscaling_lib}/FidelityFX-FSR2/src/ffx-fsr2-api) + + list(APPEND vkcv_upscaling_libraries ${FFX_FSR2_API} ${FFX_FSR2_API_VK}) + + list(APPEND vkcv_upscaling_includes ${vkcv_upscaling_lib}/FidelityFX-FSR2/src/ffx-fsr2-api) + list(APPEND vkcv_upscaling_includes ${vkcv_upscaling_lib}/FidelityFX-FSR2/src/ffx-fsr2-api/vk) +endif () diff --git a/modules/upscaling/include/vkcv/upscaling/FSR2Upscaling.hpp b/modules/upscaling/include/vkcv/upscaling/FSR2Upscaling.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9b1b702147034a782d5c7f63674ff0304d090d04 --- /dev/null +++ b/modules/upscaling/include/vkcv/upscaling/FSR2Upscaling.hpp @@ -0,0 +1,162 @@ +#pragma once + +#include "Upscaling.hpp" + +#include <vector> + +#define FFX_GCC +#include <ffx_fsr2.h> +#undef FFX_GCC + +namespace vkcv::upscaling { + +/** + * @addtogroup vkcv_upscaling + * @{ + */ + + /** + * A class to handle upscaling via FidelityFX Super Resolution. + * https://github.com/GPUOpen-Effects/FidelityFX-FSR2 + */ + class FSR2Upscaling : public Upscaling { + private: + std::vector<char> m_scratchBuffer; + + FfxFsr2ContextDescription m_description; + FfxFsr2Context m_context; + + ImageHandle m_depth; + ImageHandle m_velocity; + + float m_frameDeltaTime; + bool m_reset; + + float m_near; + float m_far; + float m_fov; + + /** + * Current state of HDR support. + */ + bool m_hdr; + + /** + * Sharpness will improve the upscaled image quality with + * a factor between 0.0f for no sharpening and 1.0f for + * maximum sharpening. + * + * The default value for sharpness should be 0.875f. + * + * Beware that 0.0f or any negative value of sharpness will + * disable the sharpening pass completely. + */ + float m_sharpness; + + void createFSR2Context(uint32_t displayWidth, + uint32_t displayHeight, + uint32_t renderWidth, + uint32_t renderHeight); + + void destroyFSR2Context(); + + public: + /** + * Constructor to create an instance for FSR upscaling. + * + * @param[in,out] core Reference to a Core instance + */ + explicit FSR2Upscaling(Core& core); + + /** + * Destructor to free the instance for FSR upscaling. + */ + ~FSR2Upscaling(); + + /** + * Update the upscaling instance with current frame + * delta time and whether the temporal data needs to + * be reset (for example because the camera switched). + * + * @param[in] deltaTime Current frame delta time + * @param[in] reset Reset temporal frame data + */ + void update(float deltaTime, bool reset = false); + + /** + * Bind the depth buffer image to use with the FSR2 + * upscaling instance for utilizing depth information. + * + * @param[in] depthInput Depth input image handle + */ + void bindDepthBuffer(const ImageHandle& depthInput); + + /** + * Bind the velocity buffer image to use with the FSR2 + * upscaling instance for utilizing 2D motion vectors. + * + * @param[in] velocityInput Velocity input image handle + */ + void bindVelocityBuffer(const ImageHandle& velocityInput); + + /** + * Record the comands of the FSR2 upscaling instance to + * scale the image of the input handle to the resolution of + * the output image handle via FidelityFX Super Resolution. + * + * @param[in] cmdStream Command stream handle to record commands + * @param[in] colorInput Color input image handle + * @param[in] output Output image handle + */ + void recordUpscaling(const CommandStreamHandle& cmdStream, + const ImageHandle& colorInput, + const ImageHandle& output) override; + + /** + * Set the required camera values for the FSR2 upscaling + * instance including near- and far-plane as well as + * the FOV angle vertical. + * + * @param[in] near Camera near plane + * @param[in] far Camera far plane + * @param[in] fov Camera field of view angle vertical + */ + void setCamera(float near, float far, float fov); + + /** + * Checks if HDR support is enabled and returns the status as boolean. + * + * @return true if HDR is supported, otherwise false + */ + [[nodiscard]] + bool isHdrEnabled() const; + + /** + * Changes the status of HDR support of the FSR upscaling instance. + * + * @param[in] enabled New status of HDR support + */ + void setHdrEnabled(bool enabled); + + /** + * Returns the amount of sharpness the FSR upscaling instance is using. + * + * @return The amount of sharpness + */ + [[nodiscard]] + float getSharpness() const; + + /** + * Changes the amount of sharpness of the FSR upscaling instance. + * The new sharpness value is restricted by 0.0f as lower and 1.0f + * as upper boundary. + * + * @param[in] sharpness New sharpness value + */ + void setSharpness(float sharpness); + + }; + + /** @} */ + +} \ No newline at end of file diff --git a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp index 64bc78aca4fe42ff813d05fc016a70c7108bd557..ee2572da2d01a8234f03ced018704b48686e1a9b 100644 --- a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp +++ b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp @@ -44,7 +44,13 @@ namespace vkcv::upscaling { * Low quality of FSR upscaling: * 2.0x per dimension */ - PERFORMANCE = 4 + PERFORMANCE = 4, + + /** + * Lowest quality of FSR upscaling: + * 3.0x per dimension + */ + ULTRA_PERFORMANCE = 5, }; /** diff --git a/modules/upscaling/lib/FidelityFX-FSR2 b/modules/upscaling/lib/FidelityFX-FSR2 new file mode 160000 index 0000000000000000000000000000000000000000..0ce4ff5c5a0210273be7e3085bb4b15d0590431c --- /dev/null +++ b/modules/upscaling/lib/FidelityFX-FSR2 @@ -0,0 +1 @@ +Subproject commit 0ce4ff5c5a0210273be7e3085bb4b15d0590431c diff --git a/modules/upscaling/src/vkcv/upscaling/FSR2Upscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSR2Upscaling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ef213e3d89ba57f7be6958a8d74a49a8c4cf4bd --- /dev/null +++ b/modules/upscaling/src/vkcv/upscaling/FSR2Upscaling.cpp @@ -0,0 +1,223 @@ + +#include "vkcv/upscaling/FSR2Upscaling.hpp" + +#define FFX_GCC +#include <ffx_fsr2_vk.h> +#undef FFX_GCC + +namespace vkcv::upscaling { + + void FSR2Upscaling::createFSR2Context(uint32_t displayWidth, + uint32_t displayHeight, + uint32_t renderWidth, + uint32_t renderHeight) { + m_description.displaySize.width = displayWidth; + m_description.displaySize.height = displayHeight; + + m_description.maxRenderSize.width = renderWidth; + m_description.maxRenderSize.height = renderHeight; + + m_description.flags = FFX_FSR2_ENABLE_AUTO_EXPOSURE; + + if (m_hdr) { + m_description.flags |= FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE; + } + + assert(ffxFsr2ContextCreate(&m_context, &m_description) == FFX_OK); + } + + void FSR2Upscaling::destroyFSR2Context() { + m_core.getContext().getDevice().waitIdle(); + + assert(ffxFsr2ContextDestroy(&m_context) == FFX_OK); + } + + FSR2Upscaling::FSR2Upscaling(Core &core) : Upscaling(core) { + const auto& physicalDevice = core.getContext().getPhysicalDevice(); + + memset(&m_description, 0, sizeof(m_description)); + + m_scratchBuffer.resize(ffxFsr2GetScratchMemorySizeVK(physicalDevice)); + + assert(ffxFsr2GetInterfaceVK( + &(m_description.callbacks), + m_scratchBuffer.data(), + m_scratchBuffer.size(), + physicalDevice, + vkGetDeviceProcAddr + ) == FFX_OK); + + m_description.device = ffxGetDeviceVK(core.getContext().getDevice()); + + createFSR2Context(0, 0, 0, 0); + } + + FSR2Upscaling::~FSR2Upscaling() { + destroyFSR2Context(); + + m_scratchBuffer.clear(); + m_description.callbacks.scratchBuffer = nullptr; + } + + void FSR2Upscaling::update(float deltaTime, bool reset) { + m_frameDeltaTime = deltaTime; + m_reset = reset; + } + + void FSR2Upscaling::bindDepthBuffer(const ImageHandle &depthInput) { + m_depth = depthInput; + } + + void FSR2Upscaling::bindVelocityBuffer(const ImageHandle &velocityInput) { + m_velocity = velocityInput; + } + + void FSR2Upscaling::recordUpscaling(const CommandStreamHandle &cmdStream, const ImageHandle &colorInput, + const ImageHandle &output) { + FfxFsr2DispatchDescription dispatch; + memset(&dispatch, 0, sizeof(dispatch)); + + const uint32_t inputWidth = m_core.getImageWidth(colorInput); + const uint32_t inputHeight = m_core.getImageHeight(colorInput); + + const uint32_t outputWidth = m_core.getImageWidth(output); + const uint32_t outputHeight = m_core.getImageHeight(output); + + if ((m_description.displaySize.width != outputWidth) || + (m_description.displaySize.height != outputHeight) || + (m_description.maxRenderSize.width < inputWidth) || + (m_description.maxRenderSize.height < inputHeight) || + (m_hdr != ((m_description.flags & FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE) != 0))) { + destroyFSR2Context(); + + createFSR2Context( + outputWidth, + outputHeight, + inputWidth, + inputHeight + ); + } + + const bool sharpeningEnabled = ( + (m_sharpness > +0.0f) && + ((inputWidth < outputWidth) || (inputHeight < outputHeight)) + ); + + dispatch.color = ffxGetTextureResourceVK( + &m_context, + m_core.getVulkanImage(colorInput), + m_core.getVulkanImageView(colorInput), + inputWidth, + inputHeight, + static_cast<VkFormat>(m_core.getImageFormat(colorInput)) + ); + + dispatch.depth = ffxGetTextureResourceVK( + &m_context, + m_core.getVulkanImage(m_depth), + m_core.getVulkanImageView(m_depth), + m_core.getImageWidth(m_depth), + m_core.getImageHeight(m_depth), + static_cast<VkFormat>(m_core.getImageFormat(m_depth)) + ); + + dispatch.motionVectors = ffxGetTextureResourceVK( + &m_context, + m_core.getVulkanImage(m_velocity), + m_core.getVulkanImageView(m_velocity), + m_core.getImageWidth(m_velocity), + m_core.getImageHeight(m_velocity), + static_cast<VkFormat>(m_core.getImageFormat(m_velocity)) + ); + + dispatch.exposure = ffxGetTextureResourceVK( + &m_context, + nullptr, + nullptr, + 1, + 1, + VK_FORMAT_UNDEFINED + ); + + dispatch.reactive = ffxGetTextureResourceVK( + &m_context, + nullptr, + nullptr, + 1, + 1, + VK_FORMAT_UNDEFINED + ); + + dispatch.transparencyAndComposition = ffxGetTextureResourceVK( + &m_context, + nullptr, + nullptr, + 1, + 1, + VK_FORMAT_UNDEFINED + ); + + dispatch.output = ffxGetTextureResourceVK( + &m_context, + m_core.getVulkanImage(output), + m_core.getVulkanImageView(output), + outputWidth, + outputHeight, + static_cast<VkFormat>(m_core.getImageFormat(output)) + ); + + dispatch.jitterOffset.x = 0; + dispatch.jitterOffset.y = 0; + + dispatch.motionVectorScale.x = 0; + dispatch.motionVectorScale.y = 0; + + dispatch.renderSize.width = inputWidth; + dispatch.renderSize.height = inputHeight; + + dispatch.enableSharpening = sharpeningEnabled; + dispatch.sharpness = m_sharpness; + + dispatch.frameTimeDelta = m_frameDeltaTime * 1000.0f; // from seconds to milliseconds + dispatch.preExposure = 1.0f; + dispatch.reset = m_reset; + + dispatch.cameraNear = m_near; + dispatch.cameraFar = m_far; + dispatch.cameraFovAngleVertical = m_fov; + + m_core.recordCommandsToStream(cmdStream, [&dispatch](const vk::CommandBuffer& cmdBuffer) { + dispatch.commandList = ffxGetCommandListVK(cmdBuffer); + }, [&]() { + assert(ffxFsr2ContextDispatch( + &m_context, + &dispatch + ) == FFX_OK); + + m_reset = false; + }); + } + + void FSR2Upscaling::setCamera(float near, float far, float fov) { + m_near = near; + m_far = far; + m_fov = fov; + } + + bool FSR2Upscaling::isHdrEnabled() const { + return m_hdr; + } + + void FSR2Upscaling::setHdrEnabled(bool enabled) { + m_hdr = enabled; + } + + float FSR2Upscaling::getSharpness() const { + return m_sharpness; + } + + void FSR2Upscaling::setSharpness(float sharpness) { + m_sharpness = (sharpness < 0.0f ? 0.0f : (sharpness > 1.0f ? 1.0f : sharpness)); + } + +} \ No newline at end of file diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index 247161e35718cde352da5461b51f30c4fe8570c7..2f37765e270c342a7aea3d52d37f1c9d4828cd89 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -36,6 +36,9 @@ namespace vkcv::upscaling { case FSRQualityMode::PERFORMANCE: scale = 2.0f; break; + case FSRQualityMode::ULTRA_PERFORMANCE: + scale = 3.0f; + break; default: scale = 1.0f; break; @@ -60,6 +63,8 @@ namespace vkcv::upscaling { return -0.79f; case FSRQualityMode::PERFORMANCE: return -1.0f; + case FSRQualityMode::ULTRA_PERFORMANCE: + return -2.0f; default: return 0.0f; } @@ -333,7 +338,7 @@ namespace vkcv::upscaling { cmdStream, m_easuPipeline, dispatch, - {DescriptorSetUsage(0, m_easuDescriptorSet, { 0 })}, + {vkcv::useDescriptorSet(0, m_easuDescriptorSet, { 0 })}, PushConstants(0) ); @@ -353,7 +358,7 @@ namespace vkcv::upscaling { cmdStream, m_rcasPipeline, dispatch, - {DescriptorSetUsage(0,m_rcasDescriptorSet, { 0 })}, + {vkcv::useDescriptorSet(0,m_rcasDescriptorSet, { 0 })}, PushConstants(0) ); @@ -371,7 +376,7 @@ namespace vkcv::upscaling { cmdStream, m_easuPipeline, dispatch, - {DescriptorSetUsage(0, m_easuDescriptorSet, { 0 })}, + {vkcv::useDescriptorSet(0, m_easuDescriptorSet, { 0 })}, PushConstants(0) ); } diff --git a/src/vkcv/DescriptorSetUsage.cpp b/src/vkcv/DescriptorSetUsage.cpp index 70fc7811791e02d57cb3a4de3d1c2f75db6e9b3a..cfa2ba1998e124cec0f1fc851356d28009288e1b 100644 --- a/src/vkcv/DescriptorSetUsage.cpp +++ b/src/vkcv/DescriptorSetUsage.cpp @@ -5,7 +5,10 @@ namespace vkcv { DescriptorSetUsage useDescriptorSet(uint32_t location, const DescriptorSetHandle &descriptorSet, const std::vector<uint32_t> &dynamicOffsets) { - DescriptorSetUsage usage(location, descriptorSet, dynamicOffsets); + DescriptorSetUsage usage; + usage.location = location; + usage.descriptorSet = descriptorSet; + usage.dynamicOffsets = dynamicOffsets; return usage; } diff --git a/src/vkcv/VertexData.cpp b/src/vkcv/VertexData.cpp index 9b9db90166a0be6f0e3a4a5666f837ceba293690..a1fcfb3692fcc6051e237e759ce29c38e4c688f4 100644 --- a/src/vkcv/VertexData.cpp +++ b/src/vkcv/VertexData.cpp @@ -4,7 +4,9 @@ namespace vkcv { VertexBufferBinding vertexBufferBinding(const BufferHandle &buffer, size_t offset) { - VertexBufferBinding binding(buffer, offset); + VertexBufferBinding binding; + binding.buffer = buffer; + binding.offset = offset; return binding; }