diff --git a/.github/workflows/msvc_analysis.yml b/.github/workflows/msvc_analysis.yml index 1ed71e73a6..936226d88a 100644 --- a/.github/workflows/msvc_analysis.yml +++ b/.github/workflows/msvc_analysis.yml @@ -60,7 +60,7 @@ jobs: # Ruleset file that will determine what checks will be run ruleset: NativeRecommendedRules.ruleset # Paths to ignore analysis of CMake targets and includes - ignoredPaths: '${{ github.workspace }}/ThirdParty' + ignoredPaths: '${{ github.workspace }}/ThirdParty;${{ env.DILIGENT_BUILD_DIR }}/_deps' # Upload SARIF file to GitHub Code Scanning Alerts - name: Upload SARIF to GitHub diff --git a/CMakeLists.txt b/CMakeLists.txt index a06ee52baa..0a4fb92121 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ set(VULKAN_SUPPORTED FALSE CACHE INTERNAL "Vulkan is not supported") set(METAL_SUPPORTED FALSE CACHE INTERNAL "Metal is not supported") set(WEBGPU_SUPPORTED FALSE CACHE INTERNAL "WebGPU is not supported") set(ARCHIVER_SUPPORTED FALSE CACHE INTERNAL "Archiver is not supported") +set(SUPER_RESOLUTION_SUPPORTED FALSE CACHE INTERNAL "Super resolution is not supported") set(DILIGENT_CORE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "DiligentCore module source directory") @@ -180,10 +181,12 @@ if(MINGW) endif() if(PLATFORM_WIN32) - set(GL_SUPPORTED TRUE CACHE INTERNAL "OpenGL is supported on Win32 platform") - set(VULKAN_SUPPORTED TRUE CACHE INTERNAL "Vulkan is supported on Win32 platform") - set(WEBGPU_SUPPORTED TRUE CACHE INTERNAL "WebGPU is supported on Win32 platform") - set(ARCHIVER_SUPPORTED TRUE CACHE INTERNAL "Archiver is supported on Win32 platform") + set(GL_SUPPORTED TRUE CACHE INTERNAL "OpenGL is supported on Win32 platform") + set(VULKAN_SUPPORTED TRUE CACHE INTERNAL "Vulkan is supported on Win32 platform") + set(WEBGPU_SUPPORTED TRUE CACHE INTERNAL "WebGPU is supported on Win32 platform") + set(ARCHIVER_SUPPORTED TRUE CACHE INTERNAL "Archiver is supported on Win32 platform") + set(SUPER_RESOLUTION_SUPPORTED TRUE CACHE INTERNAL "Super resolution is supported on Win32 platform") + set(DILIGENT_DLSS_SUPPORTED TRUE CACHE INTERNAL "DLSS is supported on Win32 platform") target_compile_definitions(Diligent-PublicBuildSettings INTERFACE PLATFORM_WIN32=1) elseif(PLATFORM_UNIVERSAL_WINDOWS) set(ARCHIVER_SUPPORTED TRUE CACHE INTERNAL "Archiver is supported on Universal Windows platform") @@ -199,12 +202,14 @@ elseif(PLATFORM_LINUX) set(ARCHIVER_SUPPORTED TRUE CACHE INTERNAL "Archiver is supported on Linux platform") target_compile_definitions(Diligent-PublicBuildSettings INTERFACE PLATFORM_LINUX=1) elseif(PLATFORM_MACOS) - set(GL_SUPPORTED TRUE CACHE INTERNAL "OpenGL is supported on MacOS platform") - set(VULKAN_SUPPORTED TRUE CACHE INTERNAL "Vulkan is enabled through MoltenVK on MacOS platform") - set(ARCHIVER_SUPPORTED TRUE CACHE INTERNAL "Archiver is supported on MacOS platform") + set(GL_SUPPORTED TRUE CACHE INTERNAL "OpenGL is supported on MacOS platform") + set(VULKAN_SUPPORTED TRUE CACHE INTERNAL "Vulkan is enabled through MoltenVK on MacOS platform") + set(ARCHIVER_SUPPORTED TRUE CACHE INTERNAL "Archiver is supported on MacOS platform") + set(SUPER_RESOLUTION_SUPPORTED TRUE CACHE INTERNAL "Super resolution is supported on MacOS platform") target_compile_definitions(Diligent-PublicBuildSettings INTERFACE PLATFORM_MACOS=1 PLATFORM_APPLE=1) elseif(PLATFORM_IOS) - set(GLES_SUPPORTED TRUE CACHE INTERNAL "OpenGLES is supported on iOS platform") + set(GLES_SUPPORTED TRUE CACHE INTERNAL "OpenGLES is supported on iOS platform") + set(SUPER_RESOLUTION_SUPPORTED TRUE CACHE INTERNAL "Super resolution is supported on iOS platform") target_compile_definitions(Diligent-PublicBuildSettings INTERFACE PLATFORM_IOS=1 PLATFORM_APPLE=1) elseif(PLATFORM_TVOS) target_compile_definitions(Diligent-PublicBuildSettings INTERFACE PLATFORM_TVOS=1 PLATFORM_APPLE=1) @@ -303,6 +308,7 @@ else() option(DILIGENT_NO_WEBGPU "Disable WebGPU backend" ON) endif() option(DILIGENT_NO_ARCHIVER "Do not build archiver" OFF) +option(DILIGENT_NO_SUPER_RESOLUTION "Do not build super resolution" OFF) option(DILIGENT_EMSCRIPTEN_STRIP_DEBUG_INFO "Strip debug information from WebAsm binaries" OFF) @@ -329,6 +335,9 @@ endif() if(${DILIGENT_NO_ARCHIVER}) set(ARCHIVER_SUPPORTED FALSE CACHE INTERNAL "Archiver is forcibly disabled") endif() +if(${DILIGENT_NO_SUPER_RESOLUTION}) + set(SUPER_RESOLUTION_SUPPORTED FALSE CACHE INTERNAL "Super resolution is forcibly disabled") +endif() if(NOT (${D3D11_SUPPORTED} OR ${D3D12_SUPPORTED} OR ${GL_SUPPORTED} OR ${GLES_SUPPORTED} OR ${VULKAN_SUPPORTED} OR ${METAL_SUPPORTED} OR ${WEBGPU_SUPPORTED})) message(FATAL_ERROR "No rendering backends are select to build") diff --git a/Graphics/CMakeLists.txt b/Graphics/CMakeLists.txt index 41cbdbd65b..49e32b169d 100644 --- a/Graphics/CMakeLists.txt +++ b/Graphics/CMakeLists.txt @@ -56,3 +56,7 @@ if(ARCHIVER_SUPPORTED) endif() add_subdirectory(GraphicsTools) + +if(SUPER_RESOLUTION_SUPPORTED) + add_subdirectory(SuperResolution) +endif() diff --git a/Graphics/SuperResolution/CMakeLists.txt b/Graphics/SuperResolution/CMakeLists.txt new file mode 100644 index 0000000000..ed668ccbb4 --- /dev/null +++ b/Graphics/SuperResolution/CMakeLists.txt @@ -0,0 +1,178 @@ +cmake_minimum_required (VERSION 3.11) + +include(../../BuildTools/CMake/BuildUtils.cmake) + +project(Diligent-SuperResolution CXX) + +if(D3D12_SUPPORTED) + # Fetch DirectSR headers + FetchContent_DeclareShallowGit(DirectSR-Headers + GIT_REPOSITORY https://github.com/MikhailGorobets/DirectSR-Headers.git + GIT_TAG master + ) + FetchContent_MakeAvailable(DirectSR-Headers) + if(TARGET DirectSR-AgilitySDK) + set_target_properties(DirectSR-AgilitySDK PROPERTIES FOLDER DiligentCore/ThirdParty) + endif() +endif() + +if(DILIGENT_DLSS_SUPPORTED) + # Fetch NVIDIA DLSS SDK headers + FetchContent_DeclareShallowGit(DLSS-Headers + GIT_REPOSITORY https://github.com/NVIDIA/DLSS.git + GIT_TAG main + ) + FetchContent_MakeAvailable(DLSS-Headers) +endif() + +set(INCLUDE + include/SuperResolutionBackend.hpp + include/SuperResolutionBase.hpp + include/SuperResolutionVariants.hpp +) + +set(INTERFACE + interface/SuperResolution.h + interface/SuperResolutionFactory.h + interface/SuperResolutionFactoryLoader.h +) + +set(SOURCE + src/SuperResolutionBackend.cpp + src/SuperResolutionBase.cpp + src/SuperResolutionFactory.cpp +) + +if(D3D12_SUPPORTED) + list(APPEND INCLUDE include/SuperResolutionDSR.hpp) + list(APPEND SOURCE src/SuperResolutionDSR.cpp) +endif() + +if(DILIGENT_DLSS_SUPPORTED) + list(APPEND INCLUDE include/SuperResolutionDLSS.hpp) + list(APPEND SOURCE src/SuperResolutionDLSS.cpp) +endif() + +set(DLL_SOURCE + src/DLLMain.cpp + src/SuperResolution.def +) + +add_library(Diligent-SuperResolutionInterface INTERFACE) +target_link_libraries (Diligent-SuperResolutionInterface INTERFACE Diligent-GraphicsEngineInterface) +target_include_directories(Diligent-SuperResolutionInterface INTERFACE interface) +target_compile_definitions(Diligent-SuperResolutionInterface INTERFACE SUPER_RESOLUTION_SUPPORTED=1) + +add_library(Diligent-SuperResolution-static STATIC + ${SOURCE} ${INTERFACE} ${INCLUDE} + readme.md +) +add_library(Diligent-SuperResolution-shared SHARED + readme.md +) + +if((PLATFORM_WIN32 OR PLATFORM_UNIVERSAL_WINDOWS) AND NOT MINGW_BUILD) + target_sources(Diligent-SuperResolution-shared PRIVATE ${DLL_SOURCE}) +endif() + +target_include_directories(Diligent-SuperResolution-static +PRIVATE + include + ../GraphicsEngine/include + ../GraphicsEngineD3DBase/include + ../GraphicsEngineNextGenBase/include +) + +if(DILIGENT_DLSS_SUPPORTED) + target_compile_definitions(Diligent-SuperResolution-static PRIVATE DLSS_SUPPORTED=1) +endif() + +target_compile_definitions(Diligent-SuperResolution-shared PUBLIC DILIGENT_SUPER_RESOLUTION_SHARED=1) + +target_link_libraries(Diligent-SuperResolution-static +PUBLIC + Diligent-SuperResolutionInterface +PRIVATE + Diligent-BuildSettings + Diligent-Common + Diligent-GraphicsAccessories + Diligent-ShaderTools +) + +if(D3D12_SUPPORTED) + target_link_libraries(Diligent-SuperResolution-static PRIVATE Diligent-GraphicsEngineD3D12-static DirectSR-Headers) + target_include_directories(Diligent-SuperResolution-static PRIVATE ../GraphicsEngineD3D12/include) +endif() + +if(DILIGENT_DLSS_SUPPORTED) + set(DLSS_SDK_DIR ${FETCHCONTENT_BASE_DIR}/dlss-headers-src) + target_include_directories(Diligent-SuperResolution-static PRIVATE ${DLSS_SDK_DIR}/include) + + # Link NGX static library (dynamic CRT /MD variant) + target_link_libraries(Diligent-SuperResolution-static PRIVATE + debug ${DLSS_SDK_DIR}/lib/Windows_x86_64/x64/nvsdk_ngx_d_dbg.lib + optimized ${DLSS_SDK_DIR}/lib/Windows_x86_64/x64/nvsdk_ngx_d.lib + ) + + if(D3D12_SUPPORTED) + target_link_libraries(Diligent-SuperResolution-static PRIVATE Diligent-GraphicsEngineD3D12-static) + target_include_directories(Diligent-SuperResolution-static PRIVATE ../GraphicsEngineD3D12/include) + endif() + if(D3D11_SUPPORTED) + target_link_libraries(Diligent-SuperResolution-static PRIVATE Diligent-GraphicsEngineD3D11-static) + target_include_directories(Diligent-SuperResolution-static PRIVATE ../GraphicsEngineD3D11/include) + endif() + if(VULKAN_SUPPORTED) + target_link_libraries(Diligent-SuperResolution-static PRIVATE Diligent-GraphicsEngineVk-static Vulkan::Headers) + target_include_directories(Diligent-SuperResolution-static PRIVATE ../GraphicsEngineVulkan/include) + endif() +endif() + +target_link_libraries(Diligent-SuperResolution-shared +PUBLIC + Diligent-SuperResolutionInterface +PRIVATE + Diligent-BuildSettings +) +target_link_whole_archive(Diligent-SuperResolution-shared Diligent-SuperResolution-static) + +if(PLATFORM_WIN32) + # Do not add 'lib' prefix when building with MinGW + set_target_properties(Diligent-SuperResolution-shared PROPERTIES PREFIX "") + + # Set output name to SuperResolution{32|64}{r|d} + set_dll_output_name(Diligent-SuperResolution-shared SuperResolution) +else() + set_target_properties(Diligent-SuperResolution-shared PROPERTIES + OUTPUT_NAME SuperResolution + ) +endif() + +if (MINGW_BUILD) + # Restrict export to GetSuperResolutionFactory + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/export.map + "{ global: *CreateSuperResolutionFactory*; local: *; };" + ) + target_link_options(Diligent-SuperResolution-shared PRIVATE LINKER:--version-script=export.map) +endif() + +source_group("src" FILES ${SOURCE}) +source_group("include" FILES ${INCLUDE}) +source_group("interface" FILES ${INTERFACE}) +source_group("dll" FILES ${DLL_SOURCE}) + +set_source_files_properties( + readme.md PROPERTIES HEADER_FILE_ONLY TRUE +) + +set_target_properties(Diligent-SuperResolution-static Diligent-SuperResolution-shared PROPERTIES + FOLDER DiligentCore/Graphics +) + +set_common_target_properties(Diligent-SuperResolution-static) +set_common_target_properties(Diligent-SuperResolution-shared) + +if(DILIGENT_INSTALL_CORE) + install_core_lib(Diligent-SuperResolution-shared) + install_core_lib(Diligent-SuperResolution-static) +endif() diff --git a/Graphics/SuperResolution/include/SuperResolutionBackend.hpp b/Graphics/SuperResolution/include/SuperResolutionBackend.hpp new file mode 100644 index 0000000000..47bbbe8ef2 --- /dev/null +++ b/Graphics/SuperResolution/include/SuperResolutionBackend.hpp @@ -0,0 +1,54 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include + +#include "SuperResolutionFactory.h" +#include "SuperResolution.h" + +namespace Diligent +{ + +/// Validates super resolution source settings attributes and throws an exception in case of an error. +void ValidateSourceSettingsAttribs(const SuperResolutionSourceSettingsAttribs& Attribs) noexcept(false); + +class ISuperResolutionBackend +{ +public: + virtual ~ISuperResolutionBackend() = default; + + virtual void EnumerateVariants(std::vector& Variants) = 0; + + virtual void GetSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, + SuperResolutionSourceSettings& Settings) = 0; + + virtual void CreateSuperResolution(const SuperResolutionDesc& Desc, + ISuperResolution** ppUpscaler) = 0; +}; + +} // namespace Diligent diff --git a/Graphics/SuperResolution/include/SuperResolutionBase.hpp b/Graphics/SuperResolution/include/SuperResolutionBase.hpp new file mode 100644 index 0000000000..1b0604f9e4 --- /dev/null +++ b/Graphics/SuperResolution/include/SuperResolutionBase.hpp @@ -0,0 +1,120 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include "ObjectBase.hpp" +#include "SuperResolution.h" +#include "GraphicsAccessories.hpp" + +#include +#include + +namespace Diligent +{ + +#define LOG_SUPER_RESOLUTION_ERROR_AND_THROW(Name, ...) LOG_ERROR_AND_THROW("Super resolution upscaler '", ((Name) != nullptr ? (Name) : ""), "': ", ##__VA_ARGS__) + +#define VERIFY_SUPER_RESOLUTION(Name, Expr, ...) \ + do \ + { \ + if (!(Expr)) \ + { \ + LOG_SUPER_RESOLUTION_ERROR_AND_THROW(Name, __VA_ARGS__); \ + } \ + } while (false) + +/// Validates super resolution description and throws an exception in case of an error. +void ValidateSuperResolutionDesc(const SuperResolutionDesc& Desc) noexcept(false); + +/// Validates super resolution description for temporal upscaling and throws an exception in case of an error. +void ValidateTemporalSuperResolutionDesc(const SuperResolutionDesc& Desc) noexcept(false); + +/// Validates execute super resolution attributes and throws an exception in case of an error. +void ValidateExecuteSuperResolutionAttribs(const SuperResolutionDesc& Desc, + const ExecuteSuperResolutionAttribs& Attribs) noexcept(false); + +/// Validates execute super resolution attributes for temporal upscaling and throws an exception in case of an error. +void ValidateTemporalExecuteSuperResolutionAttribs(const SuperResolutionDesc& Desc, + const ExecuteSuperResolutionAttribs& Attribs) noexcept(false); + +class SuperResolutionBase : public ObjectBase +{ +public: + using TBase = ObjectBase; + + struct JitterOffset + { + float X = 0.0f; + float Y = 0.0f; + }; + + SuperResolutionBase(IReferenceCounters* pRefCounters, + const SuperResolutionDesc& Desc) : + TBase{pRefCounters}, + m_Desc{Desc} + { + if (Desc.Name != nullptr) + { + m_Name = Desc.Name; + m_Desc.Name = m_Name.c_str(); + } + } + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_SuperResolution, TBase) + + virtual const SuperResolutionDesc& DILIGENT_CALL_TYPE GetDesc() const override final + { + return m_Desc; + } + + virtual void DILIGENT_CALL_TYPE GetJitterOffset(Uint32 Index, float* pJitterX, float* pJitterY) const override final + { + DEV_CHECK_ERR(pJitterX != nullptr && pJitterY != nullptr, "pJitterX and pJitterY must not be null"); + + if (!m_JitterPattern.empty()) + { + const Uint32 WrappedIndex = Index % static_cast(m_JitterPattern.size()); + *pJitterX = m_JitterPattern[WrappedIndex].X; + *pJitterY = m_JitterPattern[WrappedIndex].Y; + } + else + { + *pJitterX = 0.0f; + *pJitterY = 0.0f; + } + } + +protected: + SuperResolutionDesc m_Desc; + std::string m_Name; + std::vector m_JitterPattern; +}; + +/// Populates a Halton(2,3) jitter pattern centered at origin. +void PopulateHaltonJitterPattern(std::vector& JitterPattern, Uint32 PatternSize); + +} // namespace Diligent diff --git a/Graphics/SuperResolution/include/SuperResolutionDLSS.hpp b/Graphics/SuperResolution/include/SuperResolutionDLSS.hpp new file mode 100644 index 0000000000..8a12916d71 --- /dev/null +++ b/Graphics/SuperResolution/include/SuperResolutionDLSS.hpp @@ -0,0 +1,57 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include "SuperResolutionBackend.hpp" +#include "RefCntAutoPtr.hpp" + +struct NVSDK_NGX_Parameter; + +namespace Diligent +{ + +class SuperResolutionBackendDLSS final : public ISuperResolutionBackend +{ +public: + SuperResolutionBackendDLSS(IRenderDevice* pDevice); + + ~SuperResolutionBackendDLSS(); + + virtual void EnumerateVariants(std::vector& Variants) override final; + + virtual void GetSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, + SuperResolutionSourceSettings& Settings) override final; + + virtual void CreateSuperResolution(const SuperResolutionDesc& Desc, + ISuperResolution** ppUpscaler) override final; + +private: + RefCntAutoPtr m_pDevice; + NVSDK_NGX_Parameter* m_pNGXParams = nullptr; +}; + +} // namespace Diligent diff --git a/Graphics/SuperResolution/include/SuperResolutionDSR.hpp b/Graphics/SuperResolution/include/SuperResolutionDSR.hpp new file mode 100644 index 0000000000..5090fcee0c --- /dev/null +++ b/Graphics/SuperResolution/include/SuperResolutionDSR.hpp @@ -0,0 +1,59 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include "SuperResolutionBackend.hpp" +#include "RefCntAutoPtr.hpp" +#include + + +struct IDSRDevice; + +namespace Diligent +{ + +class SuperResolutionBackendDSR final : public ISuperResolutionBackend +{ +public: + SuperResolutionBackendDSR(IRenderDevice* pDevice); + + ~SuperResolutionBackendDSR(); + + virtual void EnumerateVariants(std::vector& Variants) override final; + + virtual void GetSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, + SuperResolutionSourceSettings& Settings) override final; + + virtual void CreateSuperResolution(const SuperResolutionDesc& Desc, + ISuperResolution** ppUpscaler) override final; + +private: + RefCntAutoPtr m_pDevice; + CComPtr m_pDSRDevice; +}; + +} // namespace Diligent diff --git a/Graphics/SuperResolution/include/SuperResolutionVariants.hpp b/Graphics/SuperResolution/include/SuperResolutionVariants.hpp new file mode 100644 index 0000000000..1499aea97f --- /dev/null +++ b/Graphics/SuperResolution/include/SuperResolutionVariants.hpp @@ -0,0 +1,49 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Super resolution upscaler variant IDs + +#include "InterfaceID.h" + +namespace Diligent +{ + +// {7B3A8D2E-1F4C-4E9A-B5D0-6C8E2F1A3B5D} +static constexpr INTERFACE_ID VariantId_DLSS = + {0x7b3a8d2e, 0x1f4c, 0x4e9a, {0xb5, 0xd0, 0x6c, 0x8e, 0x2f, 0x1a, 0x3b, 0x5d}}; + +// {C4D70001-A1B2-4C3D-8E9F-0A1B2C3D4E5F} +static constexpr INTERFACE_ID VariantId_MetalFXSpatial = + {0xc4d70001, 0xa1b2, 0x4c3d, {0x8e, 0x9f, 0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f}}; + +// {C4D70002-A1B2-4C3D-8E9F-0A1B2C3D4E5F} +static constexpr INTERFACE_ID VariantId_MetalFXTemporal = + {0xc4d70002, 0xa1b2, 0x4c3d, {0x8e, 0x9f, 0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f}}; + +} // namespace Diligent diff --git a/Graphics/SuperResolution/interface/SuperResolution.h b/Graphics/SuperResolution/interface/SuperResolution.h new file mode 100644 index 0000000000..460229f4d8 --- /dev/null +++ b/Graphics/SuperResolution/interface/SuperResolution.h @@ -0,0 +1,320 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Defines Diligent::ISuperResolution interface and related data structures + +#include "../../../Primitives/interface/Object.h" +#include "../../GraphicsEngine/interface/GraphicsTypes.h" +#include "../../GraphicsEngine/interface/TextureView.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {A1B2C3D4-E5F6-7890-ABCD-EF1234567890} +static DILIGENT_CONSTEXPR INTERFACE_ID IID_SuperResolution = + {0xa1b2c3d4, 0xe5f6, 0x7890, {0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90}}; + +// clang-format off + +/// Super resolution flags. +DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_FLAGS, Uint32) +{ + SUPER_RESOLUTION_FLAG_NONE = 0u, + + /// When set, the upscaler automatically calculates exposure for each frame. + /// The exposure texture in ExecuteSuperResolutionAttribs is ignored. + SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE = 1u << 0, + + /// When set, enables the sharpening pass in the upscaler. + /// The Sharpness field in ExecuteSuperResolutionAttribs controls the amount. + SUPER_RESOLUTION_FLAG_ENABLE_SHARPENING = 1u << 1, + + SUPER_RESOLUTION_FLAG_LAST = SUPER_RESOLUTION_FLAG_ENABLE_SHARPENING +}; +DEFINE_FLAG_ENUM_OPERATORS(SUPER_RESOLUTION_FLAGS) + + +/// This structure describes the super resolution upscaler object and is part of the creation +/// parameters given to ISuperResolutionFactory::CreateSuperResolution(). +struct SuperResolutionDesc +{ + /// Object name. + const Char* Name DEFAULT_INITIALIZER(nullptr); + + /// Unique identifier of the super resolution variant to create. + /// + /// Must match one of the VariantIds reported by ISuperResolutionFactory::EnumerateVariants(). + INTERFACE_ID VariantId DEFAULT_INITIALIZER({}); + + /// Input (render) width. Must be greater than zero and not exceed OutputWidth. + /// + /// Use ISuperResolutionFactory::GetSourceSettings() to obtain the + /// optimal input resolution for a given output resolution and optimization type. + Uint32 InputWidth DEFAULT_INITIALIZER(0); + + /// Input (render) height. Must be greater than zero and not exceed OutputHeight + /// + /// Use ISuperResolutionFactory::GetSourceSettings() to obtain the + /// optimal input resolution for a given output resolution and optimization type. + Uint32 InputHeight DEFAULT_INITIALIZER(0); + + /// Target (output) texture width. + Uint32 OutputWidth DEFAULT_INITIALIZER(0); + + /// Target (output) texture height. + Uint32 OutputHeight DEFAULT_INITIALIZER(0); + + /// Output texture format. + TEXTURE_FORMAT OutputFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA16_FLOAT); + + /// Color input texture format. + TEXTURE_FORMAT ColorFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA16_FLOAT); + + /// Depth input texture format. + /// Required for temporal upscaling. + TEXTURE_FORMAT DepthFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// Motion vectors texture format. + /// + /// Required for temporal upscaling. + TEXTURE_FORMAT MotionFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// Reactive mask texture format. + /// + /// Optional. Used for temporal upscaling to guide the denoiser for areas with inaccurate motion information (e.g., alpha-blended objects). + TEXTURE_FORMAT ReactiveMaskFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// Exposure scale texture format. + /// + /// Optional. When auto-exposure is disabled, specifies the format of the 1x1 exposure + /// texture provided in ExecuteSuperResolutionAttribs::pExposureTextureSRV. + TEXTURE_FORMAT ExposureFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// Engine creation flags controlling the super resolution upscaler behavior. + /// See SUPER_RESOLUTION_FLAGS. + SUPER_RESOLUTION_FLAGS Flags DEFAULT_INITIALIZER(SUPER_RESOLUTION_FLAG_NONE); +}; +typedef struct SuperResolutionDesc SuperResolutionDesc; + + +/// Super resolution execute attributes + +/// This structure is used by ISuperResolution::Execute(). +struct ExecuteSuperResolutionAttribs +{ + /// Device context to execute the super resolution on. + IDeviceContext* pContext DEFAULT_INITIALIZER(nullptr); + + /// Low-resolution color texture (shader resource view). + /// + /// This is the input image to be upscaled. + ITextureView* pColorTextureSRV DEFAULT_INITIALIZER(nullptr); + + /// Depth buffer of the low-resolution render (shader resource view). + /// + /// Required for temporal upscaling (SUPER_RESOLUTION_TYPE_TEMPORAL). + ITextureView* pDepthTextureSRV DEFAULT_INITIALIZER(nullptr); + + /// Motion vectors texture (shader resource view). + /// + /// Required for temporal upscaling (SUPER_RESOLUTION_TYPE_TEMPORAL). + /// Expected to contain per-pixel 2D motion vectors in pixel space. + ITextureView* pMotionVectorsSRV DEFAULT_INITIALIZER(nullptr); + + /// Output (upscaled) texture (unordered access view or render target view). + /// + /// Must match SuperResolutionDesc::OutputWidth x OutputHeight. + ITextureView* pOutputTextureView DEFAULT_INITIALIZER(nullptr); + + /// Exposure texture (shader resource view). + /// + /// Optional. A 1x1 R16_FLOAT texture containing the exposure value. + /// The upscaler reads the R channel and uses it to multiply the input color. + /// Ignored when SuperResolutionDesc::Flags includes SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE. + ITextureView* pExposureTextureSRV DEFAULT_INITIALIZER(nullptr); + + /// Reactive mask texture (shader resource view). + /// + /// Optional. Per-pixel mask in [0, 1] range guiding temporal history usage: + /// 0.0 - normal temporal behavior + /// 1.0 - ignore temporal history (use current frame only) + /// Useful for alpha-blended objects or areas with inaccurate motion vectors. + /// Only used when SuperResolutionDesc::ReactiveMaskFormat != TEX_FORMAT_UNKNOWN. + ITextureView* pReactiveMaskTextureSRV DEFAULT_INITIALIZER(nullptr); + + /// Ignore history mask texture (shader resource view). + /// + /// Optional. Binary per-pixel mask where non-zero values indicate regions + /// where temporal history should be completely discarded. + /// Unlike the reactive mask which provides proportional control, + /// this is a binary decision (discard or keep). + /// Format must be TEX_FORMAT_R8_UINT. + ITextureView* pIgnoreHistoryMaskTextureSRV DEFAULT_INITIALIZER(nullptr); + + /// Jitter offset X applied to the projection matrix (in pixels). + /// + /// Used for temporal upscaling. + float JitterX DEFAULT_INITIALIZER(0.0f); + + /// Jitter offset Y applied to the projection matrix (in pixels). + /// + /// Used for temporal upscaling. + float JitterY DEFAULT_INITIALIZER(0.0f); + + /// Pre-exposure value. + /// + /// If the input color texture is pre-multiplied by a fixed value, + /// set this to that value so the upscaler can divide by it. + /// Default is 1.0 (no pre-exposure adjustment). + float PreExposure DEFAULT_INITIALIZER(1.0f); + + /// Motion vector scale X. + /// + /// Multiplier applied to the X component of motion vectors. + /// Use this to convert motion vectors from their native space to pixel space. + /// Default is 1.0 (motion vectors are already in pixel space). + float MotionVectorScaleX DEFAULT_INITIALIZER(1.0f); + + /// Motion vector scale Y. + /// + /// Multiplier applied to the Y component of motion vectors. + /// Use this to convert motion vectors from their native space to pixel space. + /// Default is 1.0 (motion vectors are already in pixel space). + float MotionVectorScaleY DEFAULT_INITIALIZER(1.0f); + + /// Exposure scale value (scalar). + /// + /// A multiplier applied to the exposure. This is separate from PreExposure + /// and the exposure texture. Used by DirectSR-style upscalers. + /// Default is 1.0 (no additional scaling). + float ExposureScale DEFAULT_INITIALIZER(1.0f); + + /// Sharpness control. + /// + /// Controls the amount of sharpening applied during upscaling. + /// Range is typically [0.0, 1.0], where 0.0 means no sharpening + /// and 1.0 means maximum sharpening. + /// Only used when the upscaler supports sharpness (see SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_SHARPNESS). + /// Default is 0.0 (no sharpening). + float Sharpness DEFAULT_INITIALIZER(0.0f); + + /// Camera near plane distance. + /// + /// Used by some upscalers for depth reconstruction. + /// Default is 0.0 (not provided). + float CameraNear DEFAULT_INITIALIZER(0.0f); + + /// Camera far plane distance. + /// + /// Used by some upscalers for depth reconstruction. + /// Default is 0.0 (not provided). + float CameraFar DEFAULT_INITIALIZER(0.0f); + + /// Camera vertical field of view angle, in radians. + /// + /// Used by some upscalers for depth reconstruction. + /// Default is 0.0 (not provided). + float CameraFovAngleVert DEFAULT_INITIALIZER(0.0f); + + /// Time elapsed since the previous frame, in seconds. + /// + /// Used by some upscalers to adjust temporal accumulation behavior. + /// Default is 0.0. + float TimeDeltaInSeconds DEFAULT_INITIALIZER(0.0f); + + /// Set to true to reset temporal history (e.g., on camera cut). + /// + /// Default is False. + Bool ResetHistory DEFAULT_INITIALIZER(False); +}; +typedef struct ExecuteSuperResolutionAttribs ExecuteSuperResolutionAttribs; + + +#define DILIGENT_INTERFACE_NAME ISuperResolution +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define ISuperResolutionInclusiveMethods \ + IObjectInclusiveMethods; \ + ISuperResolutionMethods SuperResolution + +/// Super resolution upscaler interface. +/// +/// The super resolution object encapsulates a hardware-accelerated or software-based super resolution +/// effect (e.g., MetalFX on Metal, DirectSR on D3D12). +/// It is created via ISuperResolutionFactory::CreateSuperResolution(). +DILIGENT_BEGIN_INTERFACE(ISuperResolution, IObject) +{ + /// Returns the super resolution description used to create the object. + VIRTUAL const SuperResolutionDesc REF METHOD(GetDesc)(THIS) CONST PURE; + + /// Returns the optimal jitter offset for the given frame index. + + /// \param [in] Index - Frame index. The sequence wraps automatically. + /// \param [out] pJitterX - Jitter offset X in pixel space, typically in [-0.5, 0.5] range. + /// \param [out] pJitterY - Jitter offset Y in pixel space, typically in [-0.5, 0.5] range. + /// + /// For temporal upscaling, the upscaler provides a recommended jitter pattern + /// (e.g. Halton sequence) that should be applied to the projection matrix each frame. + /// For spatial upscaling, both values are set to zero. + VIRTUAL void METHOD(GetJitterOffset)(THIS_ + Uint32 Index, + float* pJitterX, + float* pJitterY) CONST PURE; + + + /// Executes the super resolution upscaler. + + /// \param [in] Attribs - Upscale operation attributes, see Diligent::ExecuteSuperResolutionAttribs. + /// + /// The command must be called outside of a render pass. + /// All input textures must be in the appropriate states or + /// TransitionMode should be set to RESOURCE_STATE_TRANSITION_MODE_TRANSITION. + /// + /// \remarks Supported contexts: graphics. + VIRTUAL void METHOD(Execute)(THIS_ + const ExecuteSuperResolutionAttribs REF Attribs) PURE; +}; +DILIGENT_END_INTERFACE + +// clang-format on + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +// clang-format off +# define ISuperResolution_GetDesc(This) CALL_IFACE_METHOD(SuperResolution, GetDesc, This) +# define ISuperResolution_GetJitterOffset(This, ...) CALL_IFACE_METHOD(SuperResolution, GetJitterOffset, This, __VA_ARGS__) +# define ISuperResolution_Execute(This, ...) CALL_IFACE_METHOD(SuperResolution, Execute, This, __VA_ARGS__) + +// clang-format on + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/SuperResolution/interface/SuperResolutionFactory.h b/Graphics/SuperResolution/interface/SuperResolutionFactory.h new file mode 100644 index 0000000000..a79369a7dc --- /dev/null +++ b/Graphics/SuperResolution/interface/SuperResolutionFactory.h @@ -0,0 +1,333 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Defines Diligent::ISuperResolutionFactory interface and related structures. + +#include "../../../Primitives/interface/Object.h" +#include "../../../Primitives/interface/DebugOutput.h" +#include "../../../Primitives/interface/MemoryAllocator.h" +#include "../../../Primitives/interface/FlagEnum.h" +#include "../../../Graphics/GraphicsEngine/interface/RenderDevice.h" + +#include "SuperResolution.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {79A904EC-EB17-4339-86BC-8A37632B0BD1} +static DILIGENT_CONSTEXPR INTERFACE_ID IID_SuperResolutionFactory = + {0x79a904ec, 0xeb17, 0x4339, {0x86, 0xbc, 0x8a, 0x37, 0x63, 0x2b, 0xb, 0xd1}}; + +// clang-format off + +/// Super resolution upscaler type. +DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_TYPE, Uint8) +{ + /// Spatial upscaling only (single frame, no motion vectors required). + SUPER_RESOLUTION_TYPE_SPATIAL = 0u, + + /// Temporal upscaling (uses motion vectors and history accumulation). + SUPER_RESOLUTION_TYPE_TEMPORAL +}; + +// Capability flags for spatial super resolution upscaling. +DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_SPATIAL_CAP_FLAGS, Uint32) +{ + SUPER_RESOLUTION_SPATIAL_CAP_FLAG_NONE = 0u, + + /// The upscaler is a native hardware-accelerated implementation (e.g. MetalFX, DirectSR) + /// as opposed to a custom software fallback. + SUPER_RESOLUTION_SPATIAL_CAP_FLAG_NATIVE = 1u << 0, + + SUPER_RESOLUTION_SPATIAL_CAP_FLAG_LAST = SUPER_RESOLUTION_SPATIAL_CAP_FLAG_NATIVE +}; +DEFINE_FLAG_ENUM_OPERATORS(SUPER_RESOLUTION_SPATIAL_CAP_FLAGS) + + +/// Capability flags for temporal super resolution upscaling. +DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_TEMPORAL_CAP_FLAGS, Uint32) +{ + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_NONE = 0u, + + /// The upscaler is a native hardware-accelerated implementation (e.g. MetalFX, DirectSR) + /// as opposed to a custom software fallback. + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_NATIVE = 1u << 0, + + /// The upscaler supports exposure scale texture input. + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_EXPOSURE_SCALE_TEXTURE = 1u << 1, + + /// The upscaler supports ignore history mask texture input. + /// When set, the backend processes the pIgnoreHistoryMaskTextureSRV field + /// in ExecuteSuperResolutionAttribs. + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_IGNORE_HISTORY_MASK = 1u << 2, + + /// The upscaler supports reactive mask texture input. + /// When set, the backend processes the pReactiveMaskTextureSRV field + /// in ExecuteSuperResolutionAttribs. + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_REACTIVE_MASK = 1u << 3, + + /// The upscaler supports the sharpness control parameter. + /// When set, the Sharpness field in ExecuteSuperResolutionAttribs is used. + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_SHARPNESS = 1u << 4, + + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_LAST = SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_SHARPNESS +}; +DEFINE_FLAG_ENUM_OPERATORS(SUPER_RESOLUTION_TEMPORAL_CAP_FLAGS) + + +/// Information about a supported super resolution variant +struct SuperResolutionInfo +{ + /// Human-readable name of the upscaler variant (e.g. "DLSS", "FSR", "MetalFX Spatial", "MetalFX Temporal"). + Char Name[128] DEFAULT_INITIALIZER({}); + + /// Unique identifier for this upscaler variant. + /// Use this identifier when creating the upscaler with ISuperResolutionFactory::CreateSuperResolution(). + INTERFACE_ID VariantId DEFAULT_INITIALIZER({}); + + /// Upscaler type. Determines which input textures and parameters are required. + SUPER_RESOLUTION_TYPE Type DEFAULT_INITIALIZER(SUPER_RESOLUTION_TYPE_SPATIAL); + +#if defined(DILIGENT_SHARP_GEN) + Uint32 CapFlags DEFAULT_INITIALIZER(0); +#else + union + { + /// Capability flags for SUPER_RESOLUTION_TYPE_SPATIAL. + SUPER_RESOLUTION_SPATIAL_CAP_FLAGS SpatialCapFlags DEFAULT_INITIALIZER(SUPER_RESOLUTION_SPATIAL_CAP_FLAG_NONE); + + /// Capability flags for SUPER_RESOLUTION_TYPE_TEMPORAL. + SUPER_RESOLUTION_TEMPORAL_CAP_FLAGS TemporalCapFlags; + }; +#endif + +#if DILIGENT_CPP_INTERFACE + constexpr Uint32 SpatialOrTemporalCapFlags() const + { +# if defined(DILIGENT_SHARP_GEN) + return CapFlags; +# else + return SpatialCapFlags; +# endif + } + + /// Comparison operator tests if two structures are equivalent + + /// \param [in] RHS - reference to the structure to perform comparison with + /// \return + /// - True if all members of the two structures are equal. + /// - False otherwise. + bool operator==(const SuperResolutionInfo& RHS) const noexcept + { + return (VariantId == RHS.VariantId && + Type == RHS.Type && + SpatialOrTemporalCapFlags() == RHS.SpatialOrTemporalCapFlags() && + memcmp(Name, RHS.Name, sizeof(Name)) == 0); + } +#endif +}; +typedef struct SuperResolutionInfo SuperResolutionInfo; + + +/// Optimal source (input) settings returned by ISuperResolutionFactory::GetSourceSettings(). +struct SuperResolutionSourceSettings +{ + /// Recommended input width for the given output resolution and optimization type. + Uint32 OptimalInputWidth DEFAULT_INITIALIZER(0); + + /// Recommended input height for the given output resolution and optimization type. + Uint32 OptimalInputHeight DEFAULT_INITIALIZER(0); +}; +typedef struct SuperResolutionSourceSettings SuperResolutionSourceSettings; + + +/// Super resolution optimization type. +/// Defines the quality/performance trade-off for super resolution upscaling. +DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_OPTIMIZATION_TYPE, Uint8) +{ + /// Maximum quality, lowest performance. + SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_QUALITY = 0u, + + /// Favor quality over performance. + SUPER_RESOLUTION_OPTIMIZATION_TYPE_HIGH_QUALITY, + + /// Balanced quality/performance trade-off. + SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED, + + /// Favor performance over quality. + SUPER_RESOLUTION_OPTIMIZATION_TYPE_HIGH_PERFORMANCE, + + /// Maximum performance, lowest quality. + SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_PERFORMANCE, + + SUPER_RESOLUTION_OPTIMIZATION_TYPE_COUNT +}; + + +/// Attributes for querying the optimal source (input) settings for super resolution upscaling. +/// +/// This structure is used by ISuperResolutionFactory::GetSourceSettings(). +struct SuperResolutionSourceSettingsAttribs +{ + /// Unique identifier of the super resolution variant to create. + /// + /// Must match one of the VariantIds reported by ISuperResolutionFactory::EnumerateVariants(). + INTERFACE_ID VariantId DEFAULT_INITIALIZER({}); + + /// Target (output) texture width. Must be greater than zero. + Uint32 OutputWidth DEFAULT_INITIALIZER(0); + + /// Target (output) texture height. Must be greater than zero. + Uint32 OutputHeight DEFAULT_INITIALIZER(0); + + /// Output texture format. + /// + /// Some backends (e.g. DirectSR) may return different optimal input resolutions + /// depending on the output format. When set to TEX_FORMAT_UNKNOWN, the backend will use a reasonable default. + TEXTURE_FORMAT OutputFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// Flags controlling the super resolution behavior. + /// + /// These flags affect the optimal source resolution returned by the backend. + /// Must match the flags that will be used when creating the upscaler. + SUPER_RESOLUTION_FLAGS Flags DEFAULT_INITIALIZER(SUPER_RESOLUTION_FLAG_NONE); + + /// Optimization type controlling the quality/performance trade-off. + SUPER_RESOLUTION_OPTIMIZATION_TYPE OptimizationType DEFAULT_INITIALIZER(SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED); +}; +typedef struct SuperResolutionSourceSettingsAttribs SuperResolutionSourceSettingsAttribs; + + +#define DILIGENT_INTERFACE_NAME ISuperResolutionFactory +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define ISuperResolutionFactoryInclusiveMethods \ + IObjectInclusiveMethods; \ + ISuperResolutionFactoryMethods SuperResolutionFactory + +// clang-format off + +/// SuperResolution factory interface +/// +/// The factory is created per render device using CreateSuperResolutionFactory(). +/// It enumerates available super resolution backends, queries optimal settings, +/// and creates upscaler instances for the device it was created with. +DILIGENT_BEGIN_INTERFACE(ISuperResolutionFactory, IObject) +{ + /// Enumerates the supported super resolution variants. + + /// \param [in, out] NumVariants - Number of super resolution variants. If `Variants` is null, this + /// parameter is used to return the number of supported variants. + /// If `Variants` is not null, this parameter should contain the maximum number + /// of elements to be written to `Variants` array. It is overwritten with the actual + /// number of variants written to the array. + /// \param [out] Variants - Array to receive the supported super resolution variants. + /// Each variant is described by SuperResolutionInfo structure. + VIRTUAL void METHOD(EnumerateVariants)(THIS_ + Uint32 REF NumVariants, + SuperResolutionInfo* Variants) PURE; + + + /// Returns the optimal source (input) settings for super resolution upscaling. + + /// \param [in] Attribs - Attributes, see Diligent::SuperResolutionSourceSettingsAttribs for details. + /// \param [out] Settings - On success, receives the optimal source settings, + /// see Diligent::SuperResolutionSourceSettings for details. + /// + /// \remarks On backends that don't support hardware upscaling, Settings will be zero-initialized. + /// Use this method to determine the optimal render resolution before creating + /// the upscaler object. + VIRTUAL void METHOD(GetSourceSettings)(THIS_ + const SuperResolutionSourceSettingsAttribs REF Attribs, + SuperResolutionSourceSettings REF Settings) CONST PURE; + + + /// Creates a new upscaler object. + + /// \param [in] Desc - Super resolution upscaler description, see Diligent::SuperResolutionDesc for details. + /// \param [out] ppUpscaler - Address of the memory location where a pointer to the + /// super resolution upscaler interface will be written. + /// The function calls AddRef(), so that the new object will have + /// one reference. + /// + /// \remarks On backends that don't support hardware upscaling, the method will + /// return nullptr. + VIRTUAL void METHOD(CreateSuperResolution)(THIS_ + const SuperResolutionDesc REF Desc, + ISuperResolution** ppUpscaler) PURE; + + /// Sets a user-provided debug message callback. + + /// \param [in] MessageCallback - Debug message callback function to use instead of the default one. + VIRTUAL void METHOD(SetMessageCallback)(THIS_ + DebugMessageCallbackType MessageCallback) CONST PURE; + + /// Sets whether to break program execution on assertion failure. + + /// \param [in] BreakOnError - Whether to break on assertion failure. + VIRTUAL void METHOD(SetBreakOnError)(THIS_ + bool BreakOnError) CONST PURE; + + /// Sets the memory allocator to be used by the SuperResolution. + + /// \param [in] pAllocator - Pointer to the memory allocator. + /// + /// The allocator is a global setting that applies to the entire execution unit + /// (executable or shared library that contains the SuperResolution implementation). + /// + /// The allocator should be set before any other factory method is called and + /// should not be changed afterwards. + /// The allocator object must remain valid until all objects created by the factory + /// are destroyed. + VIRTUAL void METHOD(SetMemoryAllocator)(THIS_ + IMemoryAllocator* pAllocator) CONST PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +# define ISuperResolutionFactory_EnumerateVariants(This, ...) CALL_IFACE_METHOD(SuperResolutionFactory, EnumerateVariants, This, __VA_ARGS__) +# define ISuperResolutionFactory_GetSourceSettings(This, ...) CALL_IFACE_METHOD(SuperResolutionFactory, GetSourceSettings, This, __VA_ARGS__) +# define ISuperResolutionFactory_CreateSuperResolution(This, ...) CALL_IFACE_METHOD(SuperResolutionFactory, CreateSuperResolution, This, __VA_ARGS__) +# define ISuperResolutionFactory_SetMessageCallback(This, ...) CALL_IFACE_METHOD(SuperResolutionFactory, SetMessageCallback, This, __VA_ARGS__) +# define ISuperResolutionFactory_SetBreakOnError(This, ...) CALL_IFACE_METHOD(SuperResolutionFactory, SetBreakOnError, This, __VA_ARGS__) +# define ISuperResolutionFactory_SetMemoryAllocator(This, ...) CALL_IFACE_METHOD(SuperResolutionFactory, SetMemoryAllocator, This, __VA_ARGS__) + +#endif + +/// Creates a super resolution factory for the specified render device. + +/// \param [in] pDevice - Render device to create the factory for. +/// \param [out] ppFactory - Address of the memory location where a pointer to the +/// super resolution factory interface will be written. +void DILIGENT_GLOBAL_FUNCTION(CreateSuperResolutionFactory)(IRenderDevice* pDevice, + ISuperResolutionFactory** ppFactory); + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/SuperResolution/interface/SuperResolutionFactoryLoader.h b/Graphics/SuperResolution/interface/SuperResolutionFactoryLoader.h new file mode 100644 index 0000000000..8c98f2c5ff --- /dev/null +++ b/Graphics/SuperResolution/interface/SuperResolutionFactoryLoader.h @@ -0,0 +1,88 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include "SuperResolutionFactory.h" + +#if PLATFORM_ANDROID || PLATFORM_LINUX || PLATFORM_MACOS || PLATFORM_IOS || PLATFORM_TVOS || PLATFORM_WEB || (PLATFORM_WIN32 && !defined(_MSC_VER)) +// https://gcc.gnu.org/wiki/Visibility +# define API_QUALIFIER __attribute__((visibility("default"))) +#elif PLATFORM_WIN32 || PLATFORM_UNIVERSAL_WINDOWS +# define API_QUALIFIER +#else +# error Unsupported platform +#endif + +#if DILIGENT_SUPER_RESOLUTION_SHARED && PLATFORM_WIN32 && defined(_MSC_VER) +# include "../../GraphicsEngine/interface/LoadEngineDll.h" +# define DILIGENT_SUPER_RESOLUTION_EXPLICIT_LOAD 1 +#endif + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +typedef void (*CreateSuperResolutionFactoryType)(IRenderDevice* pDevice, ISuperResolutionFactory** ppFactory); + +#if DILIGENT_SUPER_RESOLUTION_EXPLICIT_LOAD + +inline CreateSuperResolutionFactoryType DILIGENT_GLOBAL_FUNCTION(LoadSuperResolutionFactory)() +{ + static CreateSuperResolutionFactoryType CreateFactoryFunc = NULL; + if (CreateFactoryFunc == NULL) + { + CreateFactoryFunc = (CreateSuperResolutionFactoryType)LoadEngineDll("SuperResolution", "CreateSuperResolutionFactory"); + } + return CreateFactoryFunc; +} + +#else + +API_QUALIFIER +void DILIGENT_GLOBAL_FUNCTION(CreateSuperResolutionFactory)(IRenderDevice* pDevice, + ISuperResolutionFactory** ppFactory); + +#endif + +/// Loads the SuperResolution implementation DLL if necessary and creates a SuperResolution factory +/// for the specified render device. +inline void DILIGENT_GLOBAL_FUNCTION(LoadAndCreateSuperResolutionFactory)(IRenderDevice* pDevice, + ISuperResolutionFactory** ppFactory) +{ + CreateSuperResolutionFactoryType CreateFactoryFunc = NULL; +#if DILIGENT_SUPER_RESOLUTION_EXPLICIT_LOAD + CreateFactoryFunc = DILIGENT_GLOBAL_FUNCTION(LoadSuperResolutionFactory)(); + if (CreateFactoryFunc == NULL) + { + *ppFactory = NULL; + return; + } +#else + CreateFactoryFunc = DILIGENT_GLOBAL_FUNCTION(CreateSuperResolutionFactory); +#endif + CreateFactoryFunc(pDevice, ppFactory); +} + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/SuperResolution/readme.md b/Graphics/SuperResolution/readme.md new file mode 100644 index 0000000000..1435f75c7a --- /dev/null +++ b/Graphics/SuperResolution/readme.md @@ -0,0 +1,2 @@ +# Super Resolution + diff --git a/Graphics/SuperResolution/src/DLLMain.cpp b/Graphics/SuperResolution/src/DLLMain.cpp new file mode 100644 index 0000000000..bdf50328dc --- /dev/null +++ b/Graphics/SuperResolution/src/DLLMain.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include +#include + +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: +#if defined(_DEBUG) || defined(DEBUG) + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} diff --git a/Graphics/SuperResolution/src/SuperResolution.def b/Graphics/SuperResolution/src/SuperResolution.def new file mode 100644 index 0000000000..ffa1fdd26d --- /dev/null +++ b/Graphics/SuperResolution/src/SuperResolution.def @@ -0,0 +1,2 @@ +EXPORTS + CreateSuperResolutionFactory=Diligent_CreateSuperResolutionFactory diff --git a/Graphics/SuperResolution/src/SuperResolutionBackend.cpp b/Graphics/SuperResolution/src/SuperResolutionBackend.cpp new file mode 100644 index 0000000000..fa54c42d6b --- /dev/null +++ b/Graphics/SuperResolution/src/SuperResolutionBackend.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "SuperResolutionBackend.hpp" +#include "Errors.hpp" + +namespace Diligent +{ + +void ValidateSourceSettingsAttribs(const SuperResolutionSourceSettingsAttribs& Attribs) noexcept(false) +{ + if (Attribs.OutputWidth == 0 || Attribs.OutputHeight == 0) + LOG_ERROR_AND_THROW("Output resolution must be greater than zero"); + if (Attribs.OptimizationType >= SUPER_RESOLUTION_OPTIMIZATION_TYPE_COUNT) + LOG_ERROR_AND_THROW("Invalid optimization type"); +} + +} // namespace Diligent diff --git a/Graphics/SuperResolution/src/SuperResolutionBase.cpp b/Graphics/SuperResolution/src/SuperResolutionBase.cpp new file mode 100644 index 0000000000..347b6f13db --- /dev/null +++ b/Graphics/SuperResolution/src/SuperResolutionBase.cpp @@ -0,0 +1,201 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "SuperResolutionBase.hpp" + +namespace Diligent +{ + +namespace +{ + +float HaltonSequence(Uint32 Base, Uint32 Index) +{ + float Result = 0.0f; + float Frac = 1.0f / static_cast(Base); + Uint32 Idx = Index + 1; + while (Idx > 0) + { + Result += Frac * static_cast(Idx % Base); + Idx /= Base; + Frac /= static_cast(Base); + } + return Result; +} + +} // namespace + +void PopulateHaltonJitterPattern(std::vector& JitterPattern, Uint32 PatternSize) +{ + JitterPattern.resize(PatternSize); + for (Uint32 Idx = 0; Idx < PatternSize; ++Idx) + { + JitterPattern[Idx].X = HaltonSequence(2, Idx) - 0.5f; + JitterPattern[Idx].Y = HaltonSequence(3, Idx) - 0.5f; + } +} + +void ValidateSuperResolutionDesc(const SuperResolutionDesc& Desc) noexcept(false) +{ + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.OutputWidth > 0 && Desc.OutputHeight > 0, "Output resolution must be greater than zero"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.OutputFormat != TEX_FORMAT_UNKNOWN, "OutputFormat must not be TEX_FORMAT_UNKNOWN"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.ColorFormat != TEX_FORMAT_UNKNOWN, "ColorFormat must not be TEX_FORMAT_UNKNOWN"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.InputWidth > 0 && Desc.InputHeight > 0, "InputWidth and InputHeight must be greater than zero"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.InputWidth <= Desc.OutputWidth && Desc.InputHeight <= Desc.OutputHeight, + "Input resolution must not exceed output resolution"); +} + +void ValidateTemporalSuperResolutionDesc(const SuperResolutionDesc& Desc) noexcept(false) +{ + ValidateSuperResolutionDesc(Desc); + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.DepthFormat != TEX_FORMAT_UNKNOWN, "DepthFormat must not be TEX_FORMAT_UNKNOWN for temporal upscaling"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.MotionFormat != TEX_FORMAT_UNKNOWN, "MotionFormat must not be TEX_FORMAT_UNKNOWN for temporal upscaling"); +} + +void ValidateExecuteSuperResolutionAttribs(const SuperResolutionDesc& Desc, + const ExecuteSuperResolutionAttribs& Attribs) noexcept(false) +{ + VERIFY_SUPER_RESOLUTION(Desc.Name, Attribs.pContext != nullptr, "Device context must not be null"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Attribs.pColorTextureSRV != nullptr, "Color texture SRV must not be null"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Attribs.pOutputTextureView != nullptr, "Output texture view must not be null"); + + // Validate color texture + if (Attribs.pColorTextureSRV != nullptr) + { + const TextureDesc& TexDesc = Attribs.pColorTextureSRV->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pColorTextureSRV->GetDesc(); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, + "Color texture view '", TexDesc.Name, "' must be TEXTURE_VIEW_SHADER_RESOURCE"); + VERIFY_SUPER_RESOLUTION(Desc.Name, TexDesc.Width >= Desc.InputWidth && TexDesc.Height >= Desc.InputHeight, + "Color texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", Desc.InputWidth, "x", Desc.InputHeight, ")"); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.Format == Desc.ColorFormat, + "Color texture view '", TexDesc.Name, "' format (", GetTextureFormatAttribs(ViewDesc.Format).Name, + ") does not match the expected ColorFormat (", GetTextureFormatAttribs(Desc.ColorFormat).Name, ")"); + } + + // Validate output texture + if (Attribs.pOutputTextureView != nullptr) + { + const TextureDesc& TexDesc = Attribs.pOutputTextureView->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pOutputTextureView->GetDesc(); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET || ViewDesc.ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, + "Output texture view '", TexDesc.Name, "' must be TEXTURE_VIEW_RENDER_TARGET or TEXTURE_VIEW_UNORDERED_ACCESS"); + VERIFY_SUPER_RESOLUTION(Desc.Name, TexDesc.Width == Desc.OutputWidth && TexDesc.Height == Desc.OutputHeight, + "Output texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must match the upscaler output resolution (", Desc.OutputWidth, "x", Desc.OutputHeight, ")"); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.Format == Desc.OutputFormat, + "Output texture view '", TexDesc.Name, "' format (", GetTextureFormatAttribs(ViewDesc.Format).Name, + ") does not match the expected OutputFormat (", GetTextureFormatAttribs(Desc.OutputFormat).Name, ")"); + } +} + +void ValidateTemporalExecuteSuperResolutionAttribs(const SuperResolutionDesc& Desc, + const ExecuteSuperResolutionAttribs& Attribs) noexcept(false) +{ + ValidateExecuteSuperResolutionAttribs(Desc, Attribs); + + VERIFY_SUPER_RESOLUTION(Desc.Name, Attribs.pDepthTextureSRV != nullptr, "Depth texture SRV must not be null for temporal upscaling"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Attribs.pMotionVectorsSRV != nullptr, "Motion vectors SRV must not be null for temporal upscaling"); + VERIFY_SUPER_RESOLUTION(Desc.Name, (Desc.Flags & SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE) != 0 || Attribs.pExposureTextureSRV != nullptr, + "Exposure texture SRV must not be null when SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE is not set"); + + // Validate depth texture + if (Attribs.pDepthTextureSRV != nullptr) + { + const TextureDesc& TexDesc = Attribs.pDepthTextureSRV->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pDepthTextureSRV->GetDesc(); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, + "Depth texture view '", TexDesc.Name, "' must be TEXTURE_VIEW_SHADER_RESOURCE"); + VERIFY_SUPER_RESOLUTION(Desc.Name, TexDesc.Width >= Desc.InputWidth && TexDesc.Height >= Desc.InputHeight, + "Depth texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", Desc.InputWidth, "x", Desc.InputHeight, ")"); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.Format == Desc.DepthFormat, + "Depth texture view '", TexDesc.Name, "' format (", GetTextureFormatAttribs(ViewDesc.Format).Name, + ") does not match the expected DepthFormat (", GetTextureFormatAttribs(Desc.DepthFormat).Name, ")"); + } + + // Validate motion vectors texture + if (Attribs.pMotionVectorsSRV != nullptr) + { + const TextureDesc& TexDesc = Attribs.pMotionVectorsSRV->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pMotionVectorsSRV->GetDesc(); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, + "Motion vectors view '", TexDesc.Name, "' must be TEXTURE_VIEW_SHADER_RESOURCE"); + VERIFY_SUPER_RESOLUTION(Desc.Name, TexDesc.Width >= Desc.InputWidth && TexDesc.Height >= Desc.InputHeight, + "Motion vectors texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", Desc.InputWidth, "x", Desc.InputHeight, ")"); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.Format == Desc.MotionFormat, + "Motion vectors view '", TexDesc.Name, "' format (", GetTextureFormatAttribs(ViewDesc.Format).Name, + ") does not match the expected MotionFormat (", GetTextureFormatAttribs(Desc.MotionFormat).Name, ")"); + } + + // Validate exposure texture + if (Attribs.pExposureTextureSRV != nullptr) + { + const TextureDesc& TexDesc = Attribs.pExposureTextureSRV->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pExposureTextureSRV->GetDesc(); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, + "Exposure texture view '", TexDesc.Name, "' must be TEXTURE_VIEW_SHADER_RESOURCE"); + VERIFY_SUPER_RESOLUTION(Desc.Name, TexDesc.Width == 1 && TexDesc.Height == 1, + "Exposure texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be 1x1"); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.Format == Desc.ExposureFormat, + "Exposure texture view '", TexDesc.Name, "' format (", GetTextureFormatAttribs(ViewDesc.Format).Name, + ") does not match the expected ExposureFormat (", GetTextureFormatAttribs(Desc.ExposureFormat).Name, ")"); + } + + // Validate reactive mask texture + if (Attribs.pReactiveMaskTextureSRV != nullptr) + { + const TextureDesc& TexDesc = Attribs.pReactiveMaskTextureSRV->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pReactiveMaskTextureSRV->GetDesc(); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, + "Reactive mask view '", TexDesc.Name, "' must be TEXTURE_VIEW_SHADER_RESOURCE"); + VERIFY_SUPER_RESOLUTION(Desc.Name, Desc.ReactiveMaskFormat != TEX_FORMAT_UNKNOWN, + "Reactive mask texture '", TexDesc.Name, "' provided but ReactiveMaskFormat was not set in SuperResolutionDesc"); + VERIFY_SUPER_RESOLUTION(Desc.Name, TexDesc.Width >= Desc.InputWidth && TexDesc.Height >= Desc.InputHeight, + "Reactive mask texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", Desc.InputWidth, "x", Desc.InputHeight, ")"); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.Format == Desc.ReactiveMaskFormat, + "Reactive mask view '", TexDesc.Name, "' format (", GetTextureFormatAttribs(ViewDesc.Format).Name, + ") does not match the expected ReactiveMaskFormat (", GetTextureFormatAttribs(Desc.ReactiveMaskFormat).Name, ")"); + } + + // Validate ignore history mask texture + if (Attribs.pIgnoreHistoryMaskTextureSRV != nullptr) + { + const TextureDesc& TexDesc = Attribs.pIgnoreHistoryMaskTextureSRV->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pIgnoreHistoryMaskTextureSRV->GetDesc(); + VERIFY_SUPER_RESOLUTION(Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, + "Ignore history mask view '", TexDesc.Name, "' must be TEXTURE_VIEW_SHADER_RESOURCE"); + VERIFY_SUPER_RESOLUTION(Desc.Name, TexDesc.Width >= Desc.InputWidth && TexDesc.Height >= Desc.InputHeight, + "Ignore history mask texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", Desc.InputWidth, "x", Desc.InputHeight, ")"); + } +} + +} // namespace Diligent diff --git a/Graphics/SuperResolution/src/SuperResolutionDLSS.cpp b/Graphics/SuperResolution/src/SuperResolutionDLSS.cpp new file mode 100644 index 0000000000..ffe4a258a4 --- /dev/null +++ b/Graphics/SuperResolution/src/SuperResolutionDLSS.cpp @@ -0,0 +1,648 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "SuperResolutionBase.hpp" +#include "SuperResolutionDLSS.hpp" +#include "SuperResolutionVariants.hpp" + +#include +#include +#include + +#if D3D12_SUPPORTED +# include +# include "../../GraphicsEngineD3D12/include/pch.h" +# include "RenderDeviceD3D12Impl.hpp" +# include "DeviceContextD3D12Impl.hpp" +# include "TextureD3D12Impl.hpp" +#endif + +#if D3D11_SUPPORTED +# include +# include "../../GraphicsEngineD3D11/include/pch.h" +# include "RenderDeviceD3D11Impl.hpp" +# include "DeviceContextD3D11Impl.hpp" +# include "TextureBaseD3D11.hpp" +#endif + +#if VULKAN_SUPPORTED +# include "../../GraphicsEngineVulkan/include/pch.h" +# include +# include "RenderDeviceVkImpl.hpp" +# include "DeviceContextVkImpl.hpp" +# include "TextureVkImpl.hpp" +# include "TextureViewVkImpl.hpp" +# include "VulkanTypeConversions.hpp" +#endif + +namespace Diligent +{ + +namespace +{ + +NVSDK_NGX_PerfQuality_Value OptimizationTypeToNGXPerfQuality(SUPER_RESOLUTION_OPTIMIZATION_TYPE Type) +{ + switch (Type) + { + // clang-format off + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_QUALITY: return NVSDK_NGX_PerfQuality_Value_MaxQuality; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_HIGH_QUALITY: return NVSDK_NGX_PerfQuality_Value_MaxQuality; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED: return NVSDK_NGX_PerfQuality_Value_Balanced; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_HIGH_PERFORMANCE: return NVSDK_NGX_PerfQuality_Value_MaxPerf; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_PERFORMANCE: return NVSDK_NGX_PerfQuality_Value_UltraPerformance; + default: return NVSDK_NGX_PerfQuality_Value_Balanced; + // clang-format on + } +} + +NVSDK_NGX_Result GetNGXCapabilityParameters(RENDER_DEVICE_TYPE DeviceType, NVSDK_NGX_Parameter** ppParams) +{ + switch (DeviceType) + { + // clang-format off +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: return NVSDK_NGX_D3D12_GetCapabilityParameters(ppParams); +#endif +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: return NVSDK_NGX_D3D11_GetCapabilityParameters(ppParams); +#endif +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: return NVSDK_NGX_VULKAN_GetCapabilityParameters(ppParams); +#endif + default: return NVSDK_NGX_Result_Fail; + // clang-format on + } +} + +Int32 SuperResolutionFlagsToDLSSFeatureFlags(SUPER_RESOLUTION_FLAGS Flags) +{ + Int32 DLSSFlags = NVSDK_NGX_DLSS_Feature_Flags_None; + + if (Flags & SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE) + DLSSFlags |= NVSDK_NGX_DLSS_Feature_Flags_AutoExposure; + if (Flags & SUPER_RESOLUTION_FLAG_ENABLE_SHARPENING) + DLSSFlags |= NVSDK_NGX_DLSS_Feature_Flags_DoSharpening; + + DLSSFlags |= NVSDK_NGX_DLSS_Feature_Flags_MVLowRes; + DLSSFlags |= NVSDK_NGX_DLSS_Feature_Flags_IsHDR; + + return DLSSFlags; +} + +void DestroyNGXParameters(RENDER_DEVICE_TYPE DeviceType, NVSDK_NGX_Parameter* pParams) +{ + switch (DeviceType) + { + // clang-format off +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: NVSDK_NGX_D3D12_DestroyParameters(pParams); break; +#endif +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: NVSDK_NGX_D3D11_DestroyParameters(pParams); break; +#endif +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: NVSDK_NGX_VULKAN_DestroyParameters(pParams); break; +#endif + default: break; + // clang-format on + } +} + +void ReleaseNGXFeature(RENDER_DEVICE_TYPE DeviceType, NVSDK_NGX_Handle* pFeature) +{ + switch (DeviceType) + { + // clang-format off +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: NVSDK_NGX_D3D12_ReleaseFeature(pFeature); break; +#endif +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: NVSDK_NGX_D3D11_ReleaseFeature(pFeature); break; +#endif +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: NVSDK_NGX_VULKAN_ReleaseFeature(pFeature); break; +#endif + default: break; + // clang-format on + } +} + +class SuperResolutionDLSS final : public SuperResolutionBase +{ +public: + SuperResolutionDLSS(IReferenceCounters* pRefCounters, + IRenderDevice* pDevice, + const SuperResolutionDesc& Desc, + NVSDK_NGX_Parameter* pNGXParams); + + ~SuperResolutionDLSS(); + + virtual void DILIGENT_CALL_TYPE Execute(const ExecuteSuperResolutionAttribs& Attribs) override final; + +private: + void CreateFeature(const ExecuteSuperResolutionAttribs& Attribs); + +#if D3D12_SUPPORTED + void ExecuteD3D12(const ExecuteSuperResolutionAttribs& Attribs); +#endif +#if D3D11_SUPPORTED + void ExecuteD3D11(const ExecuteSuperResolutionAttribs& Attribs); +#endif +#if VULKAN_SUPPORTED + void ExecuteVulkan(const ExecuteSuperResolutionAttribs& Attribs); +#endif + + RefCntAutoPtr m_pDevice; + NVSDK_NGX_Handle* m_pDLSSFeature = nullptr; + NVSDK_NGX_Parameter* m_pNGXParams = nullptr; + RENDER_DEVICE_TYPE m_DeviceType; +}; + +SuperResolutionDLSS::SuperResolutionDLSS(IReferenceCounters* pRefCounters, + IRenderDevice* pDevice, + const SuperResolutionDesc& Desc, + NVSDK_NGX_Parameter* pNGXParams) : + SuperResolutionBase{pRefCounters, Desc}, + m_pDevice{pDevice}, + m_pNGXParams{pNGXParams}, + m_DeviceType{pDevice->GetDeviceInfo().Type} +{ + ValidateTemporalSuperResolutionDesc(m_Desc); + + // Use Halton(2,3) jitter pattern + PopulateHaltonJitterPattern(m_JitterPattern, 64); +} + +SuperResolutionDLSS::~SuperResolutionDLSS() +{ + if (m_pDLSSFeature != nullptr) + { + ReleaseNGXFeature(m_DeviceType, m_pDLSSFeature); + m_pDLSSFeature = nullptr; + } +} + +void SuperResolutionDLSS::CreateFeature(const ExecuteSuperResolutionAttribs& Attribs) +{ + Int32 DLSSCreateFeatureFlags = SuperResolutionFlagsToDLSSFeatureFlags(m_Desc.Flags); + if (Attribs.CameraNear > Attribs.CameraFar) + DLSSCreateFeatureFlags |= NVSDK_NGX_DLSS_Feature_Flags_DepthInverted; + + NVSDK_NGX_DLSS_Create_Params DLSSCreateParams = {}; + DLSSCreateParams.Feature.InWidth = m_Desc.InputWidth; + DLSSCreateParams.Feature.InHeight = m_Desc.InputHeight; + DLSSCreateParams.Feature.InTargetWidth = m_Desc.OutputWidth; + DLSSCreateParams.Feature.InTargetHeight = m_Desc.OutputHeight; + DLSSCreateParams.InFeatureCreateFlags = DLSSCreateFeatureFlags; + + NVSDK_NGX_Result Result = NVSDK_NGX_Result_Fail; + + switch (m_DeviceType) + { + // clang-format off +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: + { + ID3D12GraphicsCommandList* pCmdList = ClassPtrCast(Attribs.pContext)->GetD3D12CommandList(); + Result = NGX_D3D12_CREATE_DLSS_EXT(pCmdList, 1, 1, &m_pDLSSFeature, m_pNGXParams, &DLSSCreateParams); + break; + } +#endif +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: + { + ID3D11DeviceContext* pd3d11Ctx = ClassPtrCast(Attribs.pContext)->GetD3D11DeviceContext(); + Result = NGX_D3D11_CREATE_DLSS_EXT(pd3d11Ctx, &m_pDLSSFeature, m_pNGXParams, &DLSSCreateParams); + break; + } +#endif +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: + { + VkCommandBuffer vkCmdBuffer = ClassPtrCast(Attribs.pContext)->GetVkCommandBuffer(); + Result = NGX_VULKAN_CREATE_DLSS_EXT(vkCmdBuffer, 1, 1, &m_pDLSSFeature, m_pNGXParams, &DLSSCreateParams); + break; + } +#endif + default: + LOG_ERROR_AND_THROW("DLSS is not supported on this device type"); + // clang-format on + } + + if (NVSDK_NGX_FAILED(Result)) + LOG_ERROR_AND_THROW("Failed to create DLSS feature. NGX Result: ", static_cast(Result)); +} + +void DILIGENT_CALL_TYPE SuperResolutionDLSS::Execute(const ExecuteSuperResolutionAttribs& Attribs) +{ + ValidateTemporalExecuteSuperResolutionAttribs(m_Desc, Attribs); + + if (m_pDLSSFeature == nullptr) + CreateFeature(Attribs); + + switch (m_DeviceType) + { + // clang-format off +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: ExecuteD3D12(Attribs); break; +#endif +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: ExecuteD3D11(Attribs); break; +#endif +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: ExecuteVulkan(Attribs); break; +#endif + default: LOG_ERROR_MESSAGE("DLSS is not supported on this device type"); break; + // clang-format on + } +} + +#if D3D12_SUPPORTED +void SuperResolutionDLSS::ExecuteD3D12(const ExecuteSuperResolutionAttribs& Attribs) +{ + DeviceContextD3D12Impl* pCtxImpl = ClassPtrCast(Attribs.pContext); + + auto GetD3D12Resource = [](ITextureView* pView) -> ID3D12Resource* { + if (pView != nullptr) + return ClassPtrCast(pView->GetTexture())->GetD3D12Resource(); + return nullptr; + }; + + pCtxImpl->TransitionTextureState(Attribs.pColorTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + pCtxImpl->TransitionTextureState(Attribs.pDepthTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + pCtxImpl->TransitionTextureState(Attribs.pMotionVectorsSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + pCtxImpl->TransitionTextureState(Attribs.pOutputTextureView->GetTexture(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + if (Attribs.pExposureTextureSRV) + pCtxImpl->TransitionTextureState(Attribs.pExposureTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + if (Attribs.pReactiveMaskTextureSRV) + pCtxImpl->TransitionTextureState(Attribs.pReactiveMaskTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + if (Attribs.pIgnoreHistoryMaskTextureSRV) + pCtxImpl->TransitionTextureState(Attribs.pIgnoreHistoryMaskTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + + ID3D12GraphicsCommandList* pCmdList = pCtxImpl->GetD3D12CommandList(); + + NVSDK_NGX_D3D12_DLSS_Eval_Params EvalParams = {}; + EvalParams.Feature.pInColor = GetD3D12Resource(Attribs.pColorTextureSRV); + EvalParams.Feature.pInOutput = GetD3D12Resource(Attribs.pOutputTextureView); + EvalParams.pInDepth = GetD3D12Resource(Attribs.pDepthTextureSRV); + EvalParams.pInMotionVectors = GetD3D12Resource(Attribs.pMotionVectorsSRV); + EvalParams.pInExposureTexture = GetD3D12Resource(Attribs.pExposureTextureSRV); + EvalParams.pInTransparencyMask = GetD3D12Resource(Attribs.pReactiveMaskTextureSRV); + EvalParams.pInBiasCurrentColorMask = GetD3D12Resource(Attribs.pIgnoreHistoryMaskTextureSRV); + EvalParams.Feature.InSharpness = Attribs.Sharpness; + EvalParams.InJitterOffsetX = Attribs.JitterX; + EvalParams.InJitterOffsetY = Attribs.JitterY; + EvalParams.InReset = Attribs.ResetHistory ? 1 : 0; + EvalParams.InMVScaleX = Attribs.MotionVectorScaleX; + EvalParams.InMVScaleY = Attribs.MotionVectorScaleY; + EvalParams.InRenderSubrectDimensions.Width = m_Desc.InputWidth; + EvalParams.InRenderSubrectDimensions.Height = m_Desc.InputHeight; + EvalParams.InPreExposure = Attribs.PreExposure; + EvalParams.InExposureScale = Attribs.ExposureScale; + EvalParams.InIndicatorInvertXAxis = 0; + EvalParams.InIndicatorInvertYAxis = 0; + + NVSDK_NGX_Result Result = NGX_D3D12_EVALUATE_DLSS_EXT(pCmdList, m_pDLSSFeature, m_pNGXParams, &EvalParams); + if (NVSDK_NGX_FAILED(Result)) + LOG_ERROR_MESSAGE("DLSS D3D12 evaluation failed. NGX Result: ", static_cast(Result)); + + pCtxImpl->TransitionTextureState(Attribs.pOutputTextureView->GetTexture(), D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE); +} +#endif + +#if D3D11_SUPPORTED +void SuperResolutionDLSS::ExecuteD3D11(const ExecuteSuperResolutionAttribs& Attribs) +{ + DeviceContextD3D11Impl* pCtxImpl = ClassPtrCast(Attribs.pContext); + + auto GetD3D11Resource = [](ITextureView* pView) -> ID3D11Resource* { + if (pView != nullptr) + return ClassPtrCast(pView->GetTexture())->GetD3D11Texture(); + return nullptr; + }; + + ID3D11DeviceContext* pd3d11DeviceContext = pCtxImpl->GetD3D11DeviceContext(); + + NVSDK_NGX_D3D11_DLSS_Eval_Params EvalParams = {}; + EvalParams.Feature.pInColor = GetD3D11Resource(Attribs.pColorTextureSRV); + EvalParams.Feature.pInOutput = GetD3D11Resource(Attribs.pOutputTextureView); + EvalParams.pInDepth = GetD3D11Resource(Attribs.pDepthTextureSRV); + EvalParams.pInMotionVectors = GetD3D11Resource(Attribs.pMotionVectorsSRV); + EvalParams.pInExposureTexture = GetD3D11Resource(Attribs.pExposureTextureSRV); + EvalParams.pInTransparencyMask = GetD3D11Resource(Attribs.pReactiveMaskTextureSRV); + EvalParams.pInBiasCurrentColorMask = GetD3D11Resource(Attribs.pIgnoreHistoryMaskTextureSRV); + EvalParams.Feature.InSharpness = Attribs.Sharpness; + EvalParams.InJitterOffsetX = Attribs.JitterX; + EvalParams.InJitterOffsetY = Attribs.JitterY; + EvalParams.InReset = Attribs.ResetHistory ? 1 : 0; + EvalParams.InMVScaleX = Attribs.MotionVectorScaleX; + EvalParams.InMVScaleY = Attribs.MotionVectorScaleY; + EvalParams.InRenderSubrectDimensions.Width = m_Desc.InputWidth; + EvalParams.InRenderSubrectDimensions.Height = m_Desc.InputHeight; + EvalParams.InPreExposure = Attribs.PreExposure; + EvalParams.InExposureScale = Attribs.ExposureScale; + + NVSDK_NGX_Result Result = NGX_D3D11_EVALUATE_DLSS_EXT(pd3d11DeviceContext, m_pDLSSFeature, m_pNGXParams, &EvalParams); + if (NVSDK_NGX_FAILED(Result)) + LOG_ERROR_MESSAGE("DLSS D3D11 evaluation failed. NGX Result: ", static_cast(Result)); +} +#endif + +#if VULKAN_SUPPORTED +void SuperResolutionDLSS::ExecuteVulkan(const ExecuteSuperResolutionAttribs& Attribs) +{ + DeviceContextVkImpl* pCtxImpl = ClassPtrCast(Attribs.pContext); + + auto CreateNGXResourceVK = [](ITextureView* pView, VkImageAspectFlags AspectMask, bool bReadWrite) -> NVSDK_NGX_Resource_VK { + TextureVkImpl* pTexVk = ClassPtrCast(pView->GetTexture()); + TextureViewVkImpl* pViewVk = ClassPtrCast(pView); + const TextureDesc& TexDesc = pTexVk->GetDesc(); + + VkImageSubresourceRange SubresourceRange = {}; + SubresourceRange.aspectMask = AspectMask; + SubresourceRange.baseMipLevel = 0; + SubresourceRange.levelCount = 1; + SubresourceRange.baseArrayLayer = 0; + SubresourceRange.layerCount = 1; + + return NVSDK_NGX_Create_ImageView_Resource_VK( + pViewVk->GetVulkanImageView(), + pTexVk->GetVkImage(), + SubresourceRange, + TexFormatToVkFormat(TexDesc.Format), + TexDesc.Width, + TexDesc.Height, + bReadWrite); + }; + + VkCommandBuffer vkCmdBuffer = pCtxImpl->GetVkCommandBuffer(); + + NVSDK_NGX_Resource_VK ColorResource = CreateNGXResourceVK(Attribs.pColorTextureSRV, VK_IMAGE_ASPECT_COLOR_BIT, false); + NVSDK_NGX_Resource_VK OutputResource = CreateNGXResourceVK(Attribs.pOutputTextureView, VK_IMAGE_ASPECT_COLOR_BIT, true); + NVSDK_NGX_Resource_VK DepthResource = CreateNGXResourceVK(Attribs.pDepthTextureSRV, VK_IMAGE_ASPECT_DEPTH_BIT, false); + NVSDK_NGX_Resource_VK MotionResource = CreateNGXResourceVK(Attribs.pMotionVectorsSRV, VK_IMAGE_ASPECT_COLOR_BIT, false); + + NVSDK_NGX_Resource_VK ExposureResource = {}; + if (Attribs.pExposureTextureSRV) + ExposureResource = CreateNGXResourceVK(Attribs.pExposureTextureSRV, VK_IMAGE_ASPECT_COLOR_BIT, false); + + NVSDK_NGX_Resource_VK TransparencyMaskResource = {}; + if (Attribs.pReactiveMaskTextureSRV) + TransparencyMaskResource = CreateNGXResourceVK(Attribs.pReactiveMaskTextureSRV, VK_IMAGE_ASPECT_COLOR_BIT, false); + + NVSDK_NGX_Resource_VK BiasCurrentColorMaskResource = {}; + if (Attribs.pIgnoreHistoryMaskTextureSRV) + BiasCurrentColorMaskResource = CreateNGXResourceVK(Attribs.pIgnoreHistoryMaskTextureSRV, VK_IMAGE_ASPECT_COLOR_BIT, false); + + NVSDK_NGX_VK_DLSS_Eval_Params EvalParams = {}; + EvalParams.Feature.pInColor = &ColorResource; + EvalParams.Feature.pInOutput = &OutputResource; + EvalParams.pInDepth = &DepthResource; + EvalParams.pInMotionVectors = &MotionResource; + EvalParams.pInExposureTexture = Attribs.pExposureTextureSRV ? &ExposureResource : nullptr; + EvalParams.pInTransparencyMask = Attribs.pReactiveMaskTextureSRV ? &TransparencyMaskResource : nullptr; + EvalParams.pInBiasCurrentColorMask = Attribs.pIgnoreHistoryMaskTextureSRV ? &BiasCurrentColorMaskResource : nullptr; + EvalParams.Feature.InSharpness = Attribs.Sharpness; + EvalParams.InJitterOffsetX = Attribs.JitterX; + EvalParams.InJitterOffsetY = Attribs.JitterY; + EvalParams.InReset = Attribs.ResetHistory ? 1 : 0; + EvalParams.InMVScaleX = Attribs.MotionVectorScaleX; + EvalParams.InMVScaleY = Attribs.MotionVectorScaleY; + EvalParams.InRenderSubrectDimensions.Width = m_Desc.InputWidth; + EvalParams.InRenderSubrectDimensions.Height = m_Desc.InputHeight; + EvalParams.InPreExposure = Attribs.PreExposure; + EvalParams.InExposureScale = Attribs.ExposureScale; + + NVSDK_NGX_Result Result = NGX_VULKAN_EVALUATE_DLSS_EXT(vkCmdBuffer, m_pDLSSFeature, m_pNGXParams, &EvalParams); + if (NVSDK_NGX_FAILED(Result)) + LOG_ERROR_MESSAGE("DLSS Vulkan evaluation failed. NGX Result: ", static_cast(Result)); +} +#endif + +} // anonymous namespace + +namespace +{ + +void InitNGX(IRenderDevice* pDevice) +{ + DEV_CHECK_ERR(pDevice != nullptr, "Render device must not be null"); + + const RENDER_DEVICE_TYPE DeviceType = pDevice->GetDeviceInfo().Type; + + NVSDK_NGX_Result Result = NVSDK_NGX_Result_Fail; + + const wchar_t* AppDataPath = L"."; + const char* ProjectId = "a0f57b54-1daf-4934-90ae-c4035c19df04"; + + NVSDK_NGX_FeatureCommonInfo CommonInfo = {}; + CommonInfo.LoggingInfo.LoggingCallback = [](const char* Message, NVSDK_NGX_Logging_Level LoggingLevel, NVSDK_NGX_Feature SourceComponent) { + LOG_INFO_MESSAGE("[NGX] ", Message); + }; + CommonInfo.LoggingInfo.MinimumLoggingLevel = NVSDK_NGX_LOGGING_LEVEL_ON; + + switch (DeviceType) + { +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: + { + ID3D12Device* pd3d12Device = ClassPtrCast(pDevice)->GetD3D12Device(); + Result = NVSDK_NGX_D3D12_Init_with_ProjectID(ProjectId, NVSDK_NGX_ENGINE_TYPE_CUSTOM, "0", AppDataPath, pd3d12Device, &CommonInfo); + break; + } +#endif +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: + { + ID3D11Device* pd3d11Device = ClassPtrCast(pDevice)->GetD3D11Device(); + Result = NVSDK_NGX_D3D11_Init_with_ProjectID(ProjectId, NVSDK_NGX_ENGINE_TYPE_CUSTOM, "0", AppDataPath, pd3d11Device, &CommonInfo); + break; + } +#endif +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: + { + RenderDeviceVkImpl* pDeviceVk = ClassPtrCast(pDevice); + Result = NVSDK_NGX_VULKAN_Init_with_ProjectID(ProjectId, NVSDK_NGX_ENGINE_TYPE_CUSTOM, "0", AppDataPath, + pDeviceVk->GetVkInstance(), + pDeviceVk->GetVkPhysicalDevice(), + pDeviceVk->GetVkDevice()); + break; + } +#endif + default: + return false; + } + + if (NVSDK_NGX_FAILED(Result)) + LOG_ERROR_AND_THROW("NVIDIA NGX initialization failed. Result: ", static_cast(Result)); +} + +void ShutdownNGX(IRenderDevice* pDevice) +{ + switch (pDevice->GetDeviceInfo().Type) + { +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: + NVSDK_NGX_D3D12_Shutdown1(ClassPtrCast(pDevice)->GetD3D12Device()); + break; +#endif +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: + NVSDK_NGX_D3D11_Shutdown1(ClassPtrCast(pDevice)->GetD3D11Device()); + break; +#endif +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: + NVSDK_NGX_VULKAN_Shutdown1(ClassPtrCast(pDevice)->GetVkDevice()); + break; +#endif + default: + break; + } +} + +} // anonymous namespace + +SuperResolutionBackendDLSS::SuperResolutionBackendDLSS(IRenderDevice* pDevice) : + m_pDevice{pDevice} +{ + InitNGX(m_pDevice); + + NVSDK_NGX_Result Result = GetNGXCapabilityParameters(m_pDevice->GetDeviceInfo().Type, &m_pNGXParams); + if (NVSDK_NGX_FAILED(Result) || m_pNGXParams == nullptr) + LOG_ERROR_AND_THROW("Failed to get NGX capability parameters. Result: ", static_cast(Result)); +} + +SuperResolutionBackendDLSS::~SuperResolutionBackendDLSS() +{ + if (m_pNGXParams != nullptr) + DestroyNGXParameters(m_pDevice->GetDeviceInfo().Type, m_pNGXParams); + ShutdownNGX(m_pDevice); +} + +void SuperResolutionBackendDLSS::EnumerateVariants(std::vector& Variants) +{ + DEV_CHECK_ERR(m_pDevice != nullptr, "Render device must not be null"); + DEV_CHECK_ERR(m_pNGXParams != nullptr, "NGX parameters must not be null"); + + Int32 NeedsUpdatedDriver = 0; + NVSDK_NGX_Parameter_GetI(m_pNGXParams, NVSDK_NGX_Parameter_SuperSampling_NeedsUpdatedDriver, &NeedsUpdatedDriver); + if (NeedsUpdatedDriver) + LOG_WARNING_MESSAGE("NVIDIA DLSS requires an updated driver."); + + Int32 DLSSAvailable = 0; + NVSDK_NGX_Result Result = NVSDK_NGX_Parameter_GetI(m_pNGXParams, NVSDK_NGX_Parameter_SuperSampling_Available, &DLSSAvailable); + if (NVSDK_NGX_FAILED(Result)) + { + LOG_WARNING_MESSAGE("Failed to query DLSS availability. Result: ", static_cast(Result)); + return; + } + + if (DLSSAvailable) + { + SuperResolutionInfo Info{}; + Info.Type = SUPER_RESOLUTION_TYPE_TEMPORAL; + Info.TemporalCapFlags = SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_NATIVE | + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_EXPOSURE_SCALE_TEXTURE | + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_IGNORE_HISTORY_MASK | + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_REACTIVE_MASK | + SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_SHARPNESS; + + Uint32 VersionMajor = 0, VersionMinor = 0, VersionPatch = 0; + m_pNGXParams->Get(NVSDK_NGX_Parameter_SuperSampling_FeatureInitResult, &VersionMajor); + // Try to get version via DLL version query + NVSDK_NGX_Parameter_GetUI(m_pNGXParams, "DLSSOptimalSettingsVersion.Major", &VersionMajor); + NVSDK_NGX_Parameter_GetUI(m_pNGXParams, "DLSSOptimalSettingsVersion.Minor", &VersionMinor); + NVSDK_NGX_Parameter_GetUI(m_pNGXParams, "DLSSOptimalSettingsVersion.Patch", &VersionPatch); + + if (VersionMajor > 0) + snprintf(Info.Name, sizeof(Info.Name), "NVIDIA DLSS %u.%u.%u", VersionMajor, VersionMinor, VersionPatch); + else + strncpy_s(Info.Name, sizeof(Info.Name), "NVIDIA DLSS", _TRUNCATE); + + Info.VariantId = VariantId_DLSS; + + Variants.push_back(Info); + LOG_INFO_MESSAGE("NVIDIA DLSS is available: ", Info.Name); + } + else + { + LOG_INFO_MESSAGE("NVIDIA DLSS is not available on this hardware."); + } +} + +void SuperResolutionBackendDLSS::GetSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, + SuperResolutionSourceSettings& Settings) +{ + Settings = {}; + + DEV_CHECK_ERR(m_pDevice != nullptr, "Render device must not be null"); + ValidateSourceSettingsAttribs(Attribs); + + NVSDK_NGX_PerfQuality_Value PerfQuality = OptimizationTypeToNGXPerfQuality(Attribs.OptimizationType); + + // Query optimal settings from NGX + Uint32 OptimalWidth = 0; + Uint32 OptimalHeight = 0; + Uint32 MaxWidth = 0; + Uint32 MaxHeight = 0; + Uint32 MinWidth = 0; + Uint32 MinHeight = 0; + float Sharpness = 0.0f; + + NVSDK_NGX_Result Result = NGX_DLSS_GET_OPTIMAL_SETTINGS( + m_pNGXParams, + Attribs.OutputWidth, Attribs.OutputHeight, + PerfQuality, + &OptimalWidth, &OptimalHeight, + &MaxWidth, &MaxHeight, + &MinWidth, &MinHeight, + &Sharpness); + + if (NVSDK_NGX_SUCCEED(Result) && OptimalWidth > 0 && OptimalHeight > 0) + { + Settings.OptimalInputWidth = OptimalWidth; + Settings.OptimalInputHeight = OptimalHeight; + } + else + { + LOG_WARNING_MESSAGE("Failed to get DLSS optimal settings. Result: ", static_cast(Result)); + } +} + +void SuperResolutionBackendDLSS::CreateSuperResolution(const SuperResolutionDesc& Desc, + ISuperResolution** ppUpscaler) +{ + DEV_CHECK_ERR(m_pDevice != nullptr, "Render device must not be null"); + DEV_CHECK_ERR(ppUpscaler != nullptr, "ppUpscaler must not be null"); + + SuperResolutionDLSS* pUpscaler = NEW_RC_OBJ(GetRawAllocator(), "SuperResolutionDLSS instance", SuperResolutionDLSS)(m_pDevice, Desc, m_pNGXParams); + pUpscaler->QueryInterface(IID_SuperResolution, reinterpret_cast(ppUpscaler)); +} + +} // namespace Diligent diff --git a/Graphics/SuperResolution/src/SuperResolutionDSR.cpp b/Graphics/SuperResolution/src/SuperResolutionDSR.cpp new file mode 100644 index 0000000000..3474918c29 --- /dev/null +++ b/Graphics/SuperResolution/src/SuperResolutionDSR.cpp @@ -0,0 +1,379 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "../../GraphicsEngineD3D12/include/pch.h" +#include + +#include "SuperResolutionBase.hpp" +#include "SuperResolutionDSR.hpp" + +#include "RenderDeviceD3D12Impl.hpp" +#include "DeviceContextD3D12Impl.hpp" +#include "DXGITypeConversions.hpp" + +namespace Diligent +{ + +namespace +{ + +CComPtr CreateDSRDevice(IRenderDevice* pDevice) +{ + HMODULE hD3D12 = GetModuleHandleA("d3d12.dll"); + if (!hD3D12) + { + LOG_WARNING_MESSAGE("d3d12.dll is not loaded. DirectSR features will be disabled."); + return {}; + } + + using D3D12GetInterfaceProcType = HRESULT(WINAPI*)(REFCLSID, REFIID, void**); + D3D12GetInterfaceProcType pfnD3D12GetInterface = reinterpret_cast(GetProcAddress(hD3D12, "D3D12GetInterface")); + if (!pfnD3D12GetInterface) + { + LOG_WARNING_MESSAGE("D3D12GetInterface is not available. DirectSR features will be disabled."); + return {}; + } + + CComPtr pDSRFactory; + if (HRESULT hr = pfnD3D12GetInterface(CLSID_D3D12DSRDeviceFactory, IID_PPV_ARGS(&pDSRFactory)); FAILED(hr)) + { + LOG_WARNING_MESSAGE("Failed to create DirectSR device factory. HRESULT: ", hr); + return {}; + } + + ID3D12Device* pd3d12Device = ClassPtrCast(pDevice)->GetD3D12Device(); + + CComPtr pDSRDevice; + if (HRESULT hr = pDSRFactory->CreateDSRDevice(pd3d12Device, 0, IID_PPV_ARGS(&pDSRDevice)); FAILED(hr)) + { + LOG_WARNING_MESSAGE("Failed to create DirectSR device. HRESULT: ", hr); + return {}; + } + + LOG_INFO_MESSAGE("DirectSR device initialized successfully. ", pDSRDevice->GetNumSuperResVariants(), " upscaler variant(s) found."); + return pDSRDevice; +} + +DSR_SUPERRES_CREATE_ENGINE_FLAGS SuperResolutionFlagsToDSRFlags(SUPER_RESOLUTION_FLAGS Flags) +{ + DSR_SUPERRES_CREATE_ENGINE_FLAGS DSRFlags = DSR_SUPERRES_CREATE_ENGINE_FLAG_NONE; + + if (Flags & SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE) + DSRFlags |= DSR_SUPERRES_CREATE_ENGINE_FLAG_AUTO_EXPOSURE; + if (Flags & SUPER_RESOLUTION_FLAG_ENABLE_SHARPENING) + DSRFlags |= DSR_SUPERRES_CREATE_ENGINE_FLAG_ENABLE_SHARPENING; + + return DSRFlags; +} + +class SuperResolutionDSR final : public SuperResolutionBase +{ +public: + SuperResolutionDSR(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const SuperResolutionDesc& Desc, + IDSRDevice* pDSRDevice); + + ~SuperResolutionDSR(); + + virtual void DILIGENT_CALL_TYPE Execute(const ExecuteSuperResolutionAttribs& Attribs) override final; + +private: + RefCntAutoPtr m_pDevice; + CComPtr m_pDSREngine; + std::vector> m_DSRUpscalers; +}; + +SuperResolutionDSR::SuperResolutionDSR(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const SuperResolutionDesc& Desc, + IDSRDevice* pDSRDevice) : + SuperResolutionBase{pRefCounters, Desc}, + m_pDevice{pDevice}, + m_DSRUpscalers(pDevice->GetCommandQueueCount()) +{ + + ValidateTemporalSuperResolutionDesc(m_Desc); + VERIFY_SUPER_RESOLUTION(m_Desc.Name, Desc.MotionFormat == TEX_FORMAT_RG16_FLOAT, "MotionFormat must be TEX_FORMAT_RG16_FLOAT. Got: ", GetTextureFormatAttribs(Desc.MotionFormat).Name); + VERIFY_SUPER_RESOLUTION(m_Desc.Name, (Desc.Flags & SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE) != 0 || Desc.ExposureFormat != TEX_FORMAT_UNKNOWN, + "ExposureFormat must not be TEX_FORMAT_UNKNOWN when SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE is not set. " + "Either enable auto-exposure or specify a valid ExposureFormat (e.g. TEX_FORMAT_R32_FLOAT)."); + + VERIFY_SUPER_RESOLUTION(m_Desc.Name, pDSRDevice != nullptr, "DirectSR device is not available"); + + DSR_SUPERRES_CREATE_ENGINE_PARAMETERS CreateInfo = {}; + CreateInfo.VariantId = reinterpret_cast(Desc.VariantId); + CreateInfo.TargetFormat = TexFormatToDXGI_Format(Desc.OutputFormat); + CreateInfo.SourceColorFormat = TexFormatToDXGI_Format(Desc.ColorFormat); + CreateInfo.SourceDepthFormat = TexFormatToDXGI_Format(Desc.DepthFormat); + CreateInfo.ExposureScaleFormat = TexFormatToDXGI_Format(Desc.ExposureFormat); + CreateInfo.Flags = SuperResolutionFlagsToDSRFlags(Desc.Flags); + CreateInfo.MaxSourceSize = {Desc.InputWidth, Desc.InputHeight}; + CreateInfo.TargetSize = {Desc.OutputWidth, Desc.OutputHeight}; + + if (HRESULT hr = pDSRDevice->CreateSuperResEngine(&CreateInfo, IID_PPV_ARGS(&m_pDSREngine)); FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create DirectSR super resolution engine. HRESULT: ", hr); + + // Cache the optimal jitter pattern + { + DSR_SIZE SourceSize = {Desc.InputWidth, Desc.InputHeight}; + DSR_SIZE TargetSize = {Desc.OutputWidth, Desc.OutputHeight}; + Uint32 PatternSize = 0; + + if (HRESULT hr = m_pDSREngine->GetOptimalJitterPattern(SourceSize, TargetSize, &PatternSize, nullptr); SUCCEEDED(hr) && PatternSize > 0) + { + std::vector DSRPattern(PatternSize); + if (hr = m_pDSREngine->GetOptimalJitterPattern(SourceSize, TargetSize, &PatternSize, DSRPattern.data()); SUCCEEDED(hr)) + { + m_JitterPattern.resize(PatternSize); + for (Uint32 i = 0; i < PatternSize; ++i) + { + m_JitterPattern[i].X = DSRPattern[i].X; + m_JitterPattern[i].Y = DSRPattern[i].Y; + } + } + } + else + { + PopulateHaltonJitterPattern(m_JitterPattern, 64); + LOG_WARNING_MESSAGE("Failed to get optimal jitter pattern from DirectSR engine. HRESULT: ", hr); + } + } +} + +SuperResolutionDSR::~SuperResolutionDSR() = default; + +void DILIGENT_CALL_TYPE SuperResolutionDSR::Execute(const ExecuteSuperResolutionAttribs& Attribs) +{ + ValidateTemporalExecuteSuperResolutionAttribs(m_Desc, Attribs); + VERIFY_SUPER_RESOLUTION(m_Desc.Name, Attribs.CameraNear > 0, "CameraNear must be greater than zero for temporal upscaling"); + VERIFY_SUPER_RESOLUTION(m_Desc.Name, Attribs.CameraFar > 0, "CameraFar must be greater than zero for temporal upscaling."); + VERIFY_SUPER_RESOLUTION(m_Desc.Name, Attribs.CameraFovAngleVert > 0, "CameraFovAngleVert must be greater than zero for temporal upscaling."); + VERIFY_SUPER_RESOLUTION(m_Desc.Name, Attribs.TimeDeltaInSeconds >= 0, "TimeDeltaInSeconds must be non-negative."); + + DeviceContextD3D12Impl* pCtx = ClassPtrCast(Attribs.pContext); + + const SoftwareQueueIndex QueueId = pCtx->GetCommandQueueId(); + VERIFY_EXPR(static_cast(QueueId) < m_DSRUpscalers.size()); + + // Lazily create an upscaler for this queue on first use. + CComPtr& pDSRUpscaler = m_DSRUpscalers[static_cast(QueueId)]; + if (!pDSRUpscaler) + { + m_pDevice->LockCmdQueueAndRun(QueueId, [&](ICommandQueueD3D12* pCmdQueue) { + if (HRESULT hr = m_pDSREngine->CreateUpscaler(pCmdQueue->GetD3D12CommandQueue(), IID_PPV_ARGS(&pDSRUpscaler)); FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create DirectSR upscaler for queue ", static_cast(QueueId), ". HRESULT: ", hr); + }); + } + + // Validate output texture view type (DirectSR requires UAV) + if (Attribs.pOutputTextureView != nullptr) + { + const TextureDesc& TexDesc = Attribs.pOutputTextureView->GetTexture()->GetDesc(); + const TextureViewDesc& ViewDesc = Attribs.pOutputTextureView->GetDesc(); + VERIFY_SUPER_RESOLUTION(m_Desc.Name, ViewDesc.ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, + "Output texture view '", TexDesc.Name, "' must be TEXTURE_VIEW_UNORDERED_ACCESS"); + } + + auto GetD3D12Resource = [](ITextureView* pView) -> ID3D12Resource* { + if (pView != nullptr) + { + TextureD3D12Impl* pTexD3D12 = ClassPtrCast(pView->GetTexture()); + return pTexD3D12->GetD3D12Resource(); + } + return nullptr; + }; + + DSR_SUPERRES_UPSCALER_EXECUTE_PARAMETERS ExecuteParams = {}; + + ExecuteParams.pTargetTexture = GetD3D12Resource(Attribs.pOutputTextureView); + ExecuteParams.TargetRegion = {0, 0, static_cast(m_Desc.OutputWidth), static_cast(m_Desc.OutputHeight)}; + ExecuteParams.pSourceColorTexture = GetD3D12Resource(Attribs.pColorTextureSRV); + ExecuteParams.SourceColorRegion = {0, 0, static_cast(m_Desc.InputWidth), static_cast(m_Desc.InputHeight)}; + ExecuteParams.pSourceDepthTexture = GetD3D12Resource(Attribs.pDepthTextureSRV); + ExecuteParams.SourceDepthRegion = {0, 0, static_cast(m_Desc.InputWidth), static_cast(m_Desc.InputHeight)}; + ExecuteParams.pMotionVectorsTexture = GetD3D12Resource(Attribs.pMotionVectorsSRV); + ExecuteParams.MotionVectorsRegion = {0, 0, static_cast(m_Desc.InputWidth), static_cast(m_Desc.InputHeight)}; + ExecuteParams.MotionVectorScale = {Attribs.MotionVectorScaleX, Attribs.MotionVectorScaleY}; + ExecuteParams.CameraJitter = {Attribs.JitterX, Attribs.JitterY}; + ExecuteParams.ExposureScale = Attribs.ExposureScale; + ExecuteParams.PreExposure = Attribs.PreExposure; + ExecuteParams.Sharpness = Attribs.Sharpness; + ExecuteParams.CameraNear = Attribs.CameraNear; + ExecuteParams.CameraFar = Attribs.CameraFar; + ExecuteParams.CameraFovAngleVert = Attribs.CameraFovAngleVert; + ExecuteParams.pExposureScaleTexture = GetD3D12Resource(Attribs.pExposureTextureSRV); + ExecuteParams.pIgnoreHistoryMaskTexture = GetD3D12Resource(Attribs.pIgnoreHistoryMaskTextureSRV); + ExecuteParams.IgnoreHistoryMaskRegion = {0, 0, static_cast(m_Desc.InputWidth), static_cast(m_Desc.InputHeight)}; + ExecuteParams.pReactiveMaskTexture = GetD3D12Resource(Attribs.pReactiveMaskTextureSRV); + ExecuteParams.ReactiveMaskRegion = {0, 0, static_cast(m_Desc.InputWidth), static_cast(m_Desc.InputHeight)}; + + DSR_SUPERRES_UPSCALER_EXECUTE_FLAGS Flags = DSR_SUPERRES_UPSCALER_EXECUTE_FLAG_NONE; + if (Attribs.ResetHistory) + Flags |= DSR_SUPERRES_UPSCALER_EXECUTE_FLAG_RESET_HISTORY; + + // Transition all textures to the states expected by DirectSR and flush the context. + // DirectSR submits its own command list(s) to the command queue, so all rendering work must be submitted before DirectSR reads the inputs. + // Input textures must be in D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, output must be in D3D12_RESOURCE_STATE_UNORDERED_ACCESS. + DeviceContextD3D12Impl* pDeviceCtx = ClassPtrCast(Attribs.pContext); + pDeviceCtx->TransitionTextureState(Attribs.pColorTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + pDeviceCtx->TransitionTextureState(Attribs.pDepthTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + pDeviceCtx->TransitionTextureState(Attribs.pMotionVectorsSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + pDeviceCtx->TransitionTextureState(Attribs.pOutputTextureView->GetTexture(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + if (Attribs.pExposureTextureSRV) + pDeviceCtx->TransitionTextureState(Attribs.pExposureTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + if (Attribs.pReactiveMaskTextureSRV) + pDeviceCtx->TransitionTextureState(Attribs.pReactiveMaskTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + if (Attribs.pIgnoreHistoryMaskTextureSRV) + pDeviceCtx->TransitionTextureState(Attribs.pIgnoreHistoryMaskTextureSRV->GetTexture(), D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + pDeviceCtx->Flush(); + + if (HRESULT hr = pDSRUpscaler->Execute(&ExecuteParams, Attribs.TimeDeltaInSeconds, Flags); FAILED(hr)) + LOG_ERROR_MESSAGE("DirectSR Execute failed. HRESULT: ", hr); + + pDeviceCtx->TransitionTextureState(Attribs.pOutputTextureView->GetTexture(), D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE); +} + +} // anonymous namespace + +SuperResolutionBackendDSR::SuperResolutionBackendDSR(IRenderDevice* pDevice) : + m_pDevice{pDevice}, + m_pDSRDevice{CreateDSRDevice(pDevice)} +{ +} + +SuperResolutionBackendDSR::~SuperResolutionBackendDSR() +{ +} + +void SuperResolutionBackendDSR::EnumerateVariants(std::vector& Variants) +{ + if (!m_pDSRDevice) + return; + + static_assert(sizeof(SuperResolutionInfo::VariantId) == sizeof(DSR_SUPERRES_VARIANT_DESC::VariantId), "GUID/INTERFACE_ID size mismatch"); + + const Uint32 DSRNumVariants = m_pDSRDevice->GetNumSuperResVariants(); + for (Uint32 Idx = 0; Idx < DSRNumVariants; ++Idx) + { + DSR_SUPERRES_VARIANT_DESC VariantDesc = {}; + if (FAILED(m_pDSRDevice->GetSuperResVariantDesc(Idx, &VariantDesc))) + continue; + + SuperResolutionInfo Info{}; + Info.Type = SUPER_RESOLUTION_TYPE_TEMPORAL; + + Info.TemporalCapFlags = SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_NATIVE; + if (VariantDesc.Flags & DSR_SUPERRES_VARIANT_FLAG_SUPPORTS_EXPOSURE_SCALE_TEXTURE) + Info.TemporalCapFlags |= SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_EXPOSURE_SCALE_TEXTURE; + if (VariantDesc.Flags & DSR_SUPERRES_VARIANT_FLAG_SUPPORTS_IGNORE_HISTORY_MASK) + Info.TemporalCapFlags |= SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_IGNORE_HISTORY_MASK; + if (VariantDesc.Flags & DSR_SUPERRES_VARIANT_FLAG_SUPPORTS_REACTIVE_MASK) + Info.TemporalCapFlags |= SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_REACTIVE_MASK; + if (VariantDesc.Flags & DSR_SUPERRES_VARIANT_FLAG_SUPPORTS_SHARPNESS) + Info.TemporalCapFlags |= SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_SHARPNESS; + + snprintf(Info.Name, sizeof(Info.Name), "DSR: %s", VariantDesc.VariantName); + memcpy(&Info.VariantId, &VariantDesc.VariantId, sizeof(Info.VariantId)); + + Variants.push_back(Info); + } +} + +void SuperResolutionBackendDSR::GetSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, + SuperResolutionSourceSettings& Settings) +{ + Settings = {}; + + DEV_CHECK_ERR(m_pDSRDevice != nullptr, "DirectSR device must not be null"); + ValidateSourceSettingsAttribs(Attribs); + + DSR_OPTIMIZATION_TYPE DSROptType = DSR_OPTIMIZATION_TYPE_BALANCED; + switch (Attribs.OptimizationType) + { + // clang-format off + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_QUALITY: DSROptType = DSR_OPTIMIZATION_TYPE_MAX_QUALITY; break; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_HIGH_QUALITY: DSROptType = DSR_OPTIMIZATION_TYPE_HIGH_QUALITY; break; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED: DSROptType = DSR_OPTIMIZATION_TYPE_BALANCED; break; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_HIGH_PERFORMANCE: DSROptType = DSR_OPTIMIZATION_TYPE_HIGH_PERFORMANCE; break; + case SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_PERFORMANCE: DSROptType = DSR_OPTIMIZATION_TYPE_MAX_PERFORMANCE; break; + default: break; + // clang-format on + } + + const Uint32 NumVariants = m_pDSRDevice->GetNumSuperResVariants(); + Uint32 VariantIndex = UINT32_MAX; + for (Uint32 Idx = 0; Idx < NumVariants; ++Idx) + { + DSR_SUPERRES_VARIANT_DESC VariantDesc = {}; + if (SUCCEEDED(m_pDSRDevice->GetSuperResVariantDesc(Idx, &VariantDesc))) + { + if (memcmp(&VariantDesc.VariantId, &Attribs.VariantId, sizeof(GUID)) == 0) + { + VariantIndex = Idx; + break; + } + } + } + + if (VariantIndex == UINT32_MAX) + { + LOG_WARNING_MESSAGE("DirectSR variant not found for the specified VariantId"); + return; + } + + DSR_SIZE TargetSize = {Attribs.OutputWidth, Attribs.OutputHeight}; + + DSR_SUPERRES_CREATE_ENGINE_FLAGS DSRCreateFlags = DSR_SUPERRES_CREATE_ENGINE_FLAG_NONE; + if (Attribs.Flags & SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE) + DSRCreateFlags |= DSR_SUPERRES_CREATE_ENGINE_FLAG_AUTO_EXPOSURE; + if (Attribs.Flags & SUPER_RESOLUTION_FLAG_ENABLE_SHARPENING) + DSRCreateFlags |= DSR_SUPERRES_CREATE_ENGINE_FLAG_ENABLE_SHARPENING; + + DSR_SUPERRES_SOURCE_SETTINGS SourceSettings = {}; + if (HRESULT hr = m_pDSRDevice->QuerySuperResSourceSettings(VariantIndex, TargetSize, TexFormatToDXGI_Format(Attribs.OutputFormat), DSROptType, DSRCreateFlags, &SourceSettings); SUCCEEDED(hr)) + { + Settings.OptimalInputWidth = SourceSettings.OptimalSize.Width; + Settings.OptimalInputHeight = SourceSettings.OptimalSize.Height; + } + else + { + LOG_WARNING_MESSAGE("DirectSR QuerySuperResSourceSettings failed. HRESULT: ", hr); + } +} + +void SuperResolutionBackendDSR::CreateSuperResolution(const SuperResolutionDesc& Desc, + ISuperResolution** ppUpscaler) +{ + DEV_CHECK_ERR(m_pDSRDevice != nullptr, "DirectSR device must not be null"); + DEV_CHECK_ERR(m_pDevice != nullptr, "Render device must not be null"); + + RenderDeviceD3D12Impl* pDeviceD3D12 = ClassPtrCast(m_pDevice.RawPtr()); + SuperResolutionDSR* pUpscaler = NEW_RC_OBJ(GetRawAllocator(), "SuperResolutionDSR instance", SuperResolutionDSR)(pDeviceD3D12, Desc, m_pDSRDevice); + pUpscaler->QueryInterface(IID_SuperResolution, reinterpret_cast(ppUpscaler)); +} + +} // namespace Diligent diff --git a/Graphics/SuperResolution/src/SuperResolutionFactory.cpp b/Graphics/SuperResolution/src/SuperResolutionFactory.cpp new file mode 100644 index 0000000000..bd641879ed --- /dev/null +++ b/Graphics/SuperResolution/src/SuperResolutionFactory.cpp @@ -0,0 +1,247 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "SuperResolutionFactory.h" +#include "SuperResolutionFactoryLoader.h" +#include "ObjectBase.hpp" +#include "RefCntAutoPtr.hpp" +#include "EngineMemory.h" +#include "PlatformDebug.hpp" +#include "DebugUtilities.hpp" +#include "SuperResolutionBackend.hpp" + +#include + +#if D3D12_SUPPORTED +# include "SuperResolutionDSR.hpp" +#endif + +#if DLSS_SUPPORTED +# include "SuperResolutionDLSS.hpp" +#endif + +#if METAL_SUPPORTED +# include "SuperResolutionMtl.hpp" +#endif + +namespace Diligent +{ + +namespace +{ + +struct BackendEntry +{ + std::unique_ptr pBackend; + std::vector Variants; +}; + +class SuperResolutionFactoryImpl final : public ObjectBase +{ +public: + using TBase = ObjectBase; + + SuperResolutionFactoryImpl(IReferenceCounters* pRefCounters, IRenderDevice* pDevice); + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_SuperResolutionFactory, TBase) + + virtual void DILIGENT_CALL_TYPE EnumerateVariants(Uint32& NumVariants, SuperResolutionInfo* Variants) override final; + + virtual void DILIGENT_CALL_TYPE GetSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, SuperResolutionSourceSettings& Settings) const override final; + + virtual void DILIGENT_CALL_TYPE CreateSuperResolution(const SuperResolutionDesc& Desc, ISuperResolution** ppUpscaler) override final; + + virtual void DILIGENT_CALL_TYPE SetMessageCallback(DebugMessageCallbackType MessageCallback) const override final; + + virtual void DILIGENT_CALL_TYPE SetBreakOnError(bool BreakOnError) const override final; + + virtual void DILIGENT_CALL_TYPE SetMemoryAllocator(IMemoryAllocator* pAllocator) const override final; + +private: + template + void AddBackend(Args&&... args); + + ISuperResolutionBackend* FindBackend(const INTERFACE_ID& VariantId) const; + + std::vector m_Backends; +}; + +template +void SuperResolutionFactoryImpl::AddBackend(Args&&... args) +{ + BackendEntry& Entry = m_Backends.emplace_back(); + Entry.pBackend = std::make_unique(std::forward(args)...); + Entry.pBackend->EnumerateVariants(Entry.Variants); + if (Entry.Variants.empty()) + m_Backends.pop_back(); +} + + +SuperResolutionFactoryImpl::SuperResolutionFactoryImpl(IReferenceCounters* pRefCounters, IRenderDevice* pDevice) : + TBase{pRefCounters} +{ + +#if DLSS_SUPPORTED + if (pDevice != nullptr) + AddBackend(pDevice); +#endif + +#if D3D12_SUPPORTED + if (pDevice != nullptr && pDevice->GetDeviceInfo().Type == RENDER_DEVICE_TYPE_D3D12) + AddBackend(pDevice); +#endif + +#if METAL_SUPPORTED + if (pDevice != nullptr && pDevice->GetDeviceInfo().Type == RENDER_DEVICE_TYPE_METAL) + AddBackend(pDevice); +#endif +} + +ISuperResolutionBackend* SuperResolutionFactoryImpl::FindBackend(const INTERFACE_ID& VariantId) const +{ + for (const BackendEntry& Entry : m_Backends) + { + for (const SuperResolutionInfo& Info : Entry.Variants) + { + if (Info.VariantId == VariantId) + return Entry.pBackend.get(); + } + } + return nullptr; +} + +void SuperResolutionFactoryImpl::EnumerateVariants(Uint32& NumVariants, SuperResolutionInfo* Variants) +{ + Uint32 Count = 0; + for (const BackendEntry& Entry : m_Backends) + Count += static_cast(Entry.Variants.size()); + + if (Variants == nullptr) + { + NumVariants = Count; + return; + } + + const Uint32 MaxVariants = NumVariants; + NumVariants = 0; + for (const BackendEntry& Entry : m_Backends) + { + for (const SuperResolutionInfo& Info : Entry.Variants) + { + if (NumVariants >= MaxVariants) + return; + Variants[NumVariants++] = Info; + } + } +} + +void SuperResolutionFactoryImpl::GetSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, SuperResolutionSourceSettings& Settings) const +{ + Settings = {}; + + ISuperResolutionBackend* pBackend = FindBackend(Attribs.VariantId); + if (pBackend == nullptr) + { + LOG_WARNING_MESSAGE("Super resolution variant not found for the specified VariantId"); + return; + } + + pBackend->GetSourceSettings(Attribs, Settings); +} + +void SuperResolutionFactoryImpl::CreateSuperResolution(const SuperResolutionDesc& Desc, ISuperResolution** ppUpscaler) +{ + DEV_CHECK_ERR(ppUpscaler != nullptr, "ppUpscaler must not be null"); + if (ppUpscaler == nullptr) + return; + + *ppUpscaler = nullptr; + + ISuperResolutionBackend* pBackend = FindBackend(Desc.VariantId); + if (pBackend == nullptr) + { + LOG_ERROR_MESSAGE("Super resolution variant not found for the specified VariantId. Call EnumerateVariants() to get valid variant IDs."); + return; + } + + try + { + pBackend->CreateSuperResolution(Desc, ppUpscaler); + } + catch (...) + { + LOG_ERROR("Failed to create super resolution upscaler '", (Desc.Name ? Desc.Name : ""), "'"); + } +} + +void SuperResolutionFactoryImpl::SetMessageCallback(DebugMessageCallbackType MessageCallback) const +{ + SetDebugMessageCallback(MessageCallback); +} + +void SuperResolutionFactoryImpl::SetBreakOnError(bool BreakOnError) const +{ + PlatformDebug::SetBreakOnError(BreakOnError); +} + +void SuperResolutionFactoryImpl::SetMemoryAllocator(IMemoryAllocator* pAllocator) const +{ + SetRawAllocator(pAllocator); +} + +} // namespace + + +API_QUALIFIER void CreateSuperResolutionFactory(IRenderDevice* pDevice, ISuperResolutionFactory** ppFactory) +{ + DEV_CHECK_ERR(ppFactory != nullptr, "ppFactory must not be null"); + if (ppFactory == nullptr) + return; + + *ppFactory = nullptr; + + try + { + SuperResolutionFactoryImpl* pFactory = NEW_RC_OBJ(GetRawAllocator(), "SuperResolutionFactoryImpl instance", SuperResolutionFactoryImpl)(pDevice); + pFactory->QueryInterface(IID_SuperResolutionFactory, reinterpret_cast(ppFactory)); + } + catch (...) + { + LOG_ERROR("Failed to create super resolution factory"); + } +} + +} // namespace Diligent + +extern "C" +{ + API_QUALIFIER + void Diligent_CreateSuperResolutionFactory(Diligent::IRenderDevice* pDevice, + Diligent::ISuperResolutionFactory** ppFactory) + { + Diligent::CreateSuperResolutionFactory(pDevice, ppFactory); + } +} diff --git a/Tests/DiligentCoreAPITest/CMakeLists.txt b/Tests/DiligentCoreAPITest/CMakeLists.txt index ef5c7fe764..09d19e1fb8 100644 --- a/Tests/DiligentCoreAPITest/CMakeLists.txt +++ b/Tests/DiligentCoreAPITest/CMakeLists.txt @@ -35,6 +35,11 @@ if(NOT ARCHIVER_SUPPORTED) list(REMOVE_ITEM SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/RenderStateCacheTest.cpp) endif() +if(NOT SUPER_RESOLUTION_SUPPORTED) + list(REMOVE_ITEM SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/SuperResolutionTest.cpp) + list(REMOVE_ITEM SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/c_interface/SuperResolution_C_Test.c) +endif() + if(D3D11_SUPPORTED) file(GLOB D3D11_SOURCE LIST_DIRECTORIES false src/D3D11/*) file(GLOB D3D11_INCLUDE LIST_DIRECTORIES false include/D3D11/*) @@ -114,6 +119,14 @@ PRIVATE Diligent-ShaderTools ) +if(SUPER_RESOLUTION_SUPPORTED) + target_link_libraries(DiligentCoreAPITest PRIVATE Diligent-SuperResolution-static) + if(D3D12_SUPPORTED AND TARGET DirectSR-AgilitySDK) + target_link_libraries(DiligentCoreAPITest PRIVATE DirectSR-AgilitySDK) + copy_directsr_dlls(DiligentCoreAPITest) + endif() +endif() + if(TARGET Diligent-HLSL2GLSLConverterLib) target_link_libraries(DiligentCoreAPITest PRIVATE Diligent-HLSL2GLSLConverterLib) endif() diff --git a/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp new file mode 100644 index 0000000000..cc0593858e --- /dev/null +++ b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp @@ -0,0 +1,423 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "GPUTestingEnvironment.hpp" +#include "GraphicsAccessories.hpp" +#include "SuperResolutionFactory.h" +#include "SuperResolutionFactoryLoader.h" + +#include "gtest/gtest.h" + +using namespace Diligent; +using namespace Diligent::Testing; + +extern "C" +{ + int TestSuperResolutionCInterface(void* pUpscaler); + int TestSuperResolutionFactoryCInterface(void* pFactory); +} + +namespace +{ + +static ISuperResolutionFactory* GetFactory() +{ + auto* pDevice = GPUTestingEnvironment::GetInstance()->GetDevice(); + static RefCntAutoPtr pFactory; + if (!pFactory) + LoadAndCreateSuperResolutionFactory(pDevice, &pFactory); + return pFactory; +} + +static const SuperResolutionInfo* FindVariantByType(const SuperResolutionInfo* pVariants, Uint32 NumVariants, SUPER_RESOLUTION_TYPE Type) +{ + for (Uint32 VariantIdx = 0; VariantIdx < NumVariants; ++VariantIdx) + { + if (pVariants[VariantIdx].Type == Type) + return &pVariants[VariantIdx]; + } + return nullptr; +} + +TEST(SuperResolutionTest, EnumerateVariants) +{ + auto* pFactory = GetFactory(); + ASSERT_NE(pFactory, nullptr); + + Uint32 NumVariants = 0; + pFactory->EnumerateVariants(NumVariants, nullptr); + if (NumVariants == 0) + { + GTEST_SKIP() << "No super resolution variants available on this device"; + } + + std::vector Variants(NumVariants); + pFactory->EnumerateVariants(NumVariants, Variants.data()); + + for (Uint32 VariantIdx = 0; VariantIdx < NumVariants; ++VariantIdx) + { + EXPECT_NE(Variants[VariantIdx].Name[0], '\0') << "Variant " << VariantIdx << " has empty name"; + EXPECT_NE(Variants[VariantIdx].VariantId, IID_Unknown) << "Variant " << VariantIdx << " has unknown UID"; + } +} + +TEST(SuperResolutionTest, QuerySourceSettings) +{ + auto* pFactory = GetFactory(); + ASSERT_NE(pFactory, nullptr); + + Uint32 NumVariants = 0; + pFactory->EnumerateVariants(NumVariants, nullptr); + if (NumVariants == 0) + { + GTEST_SKIP() << "No super resolution variants available on this device"; + } + + std::vector Variants(NumVariants); + pFactory->EnumerateVariants(NumVariants, Variants.data()); + + for (Uint32 VariantIdx = 0; VariantIdx < NumVariants; ++VariantIdx) + { + SuperResolutionSourceSettingsAttribs Attribs; + Attribs.VariantId = Variants[VariantIdx].VariantId; + Attribs.OutputWidth = 1920; + Attribs.OutputHeight = 1080; + Attribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + Attribs.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + Attribs.Flags = SUPER_RESOLUTION_FLAG_NONE; + + SuperResolutionSourceSettings Settings; + pFactory->GetSourceSettings(Attribs, Settings); + + EXPECT_GT(Settings.OptimalInputWidth, 0u) << "Variant " << Variants[VariantIdx].Name; + EXPECT_GT(Settings.OptimalInputHeight, 0u) << "Variant " << Variants[VariantIdx].Name; + EXPECT_LE(Settings.OptimalInputWidth, 1920u) << "Variant " << Variants[VariantIdx].Name; + EXPECT_LE(Settings.OptimalInputHeight, 1080u) << "Variant " << Variants[VariantIdx].Name; + } + + // Test all optimization types produce monotonically decreasing input resolution + // (enum is ordered from MAX_QUALITY=0 to MAX_PERFORMANCE) + { + const auto& Variant = Variants[0]; + + Uint32 PrevWidth = 0; + for (Uint8 OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_QUALITY; OptimizationType < SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_PERFORMANCE; ++OptimizationType) + { + SuperResolutionSourceSettingsAttribs Attribs; + Attribs.VariantId = Variant.VariantId; + Attribs.OutputWidth = 1920; + Attribs.OutputHeight = 1080; + Attribs.OptimizationType = static_cast(OptimizationType); + Attribs.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + Attribs.Flags = SUPER_RESOLUTION_FLAG_NONE; + + SuperResolutionSourceSettings Settings; + pFactory->GetSourceSettings(Attribs, Settings); + + // First iteration: just record. Subsequent: input should decrease or stay same. + if (PrevWidth > 0) + EXPECT_LE(Settings.OptimalInputWidth, PrevWidth) << "OptimizationType " << OptimizationType; + PrevWidth = Settings.OptimalInputWidth; + } + } +} + +TEST(SuperResolutionTest, CreateTemporalUpscaler) +{ + auto* pFactory = GetFactory(); + ASSERT_NE(pFactory, nullptr); + + Uint32 NumVariants = 0; + pFactory->EnumerateVariants(NumVariants, nullptr); + if (NumVariants == 0) + { + GTEST_SKIP() << "No super resolution variants available on this device"; + } + + std::vector Variants(NumVariants); + pFactory->EnumerateVariants(NumVariants, Variants.data()); + + const auto* pTemporalInfo = FindVariantByType(Variants.data(), NumVariants, SUPER_RESOLUTION_TYPE_TEMPORAL); + if (pTemporalInfo == nullptr) + { + GTEST_SKIP() << "Temporal super resolution is not supported by this device"; + } + + GPUTestingEnvironment::ScopedReset EnvironmentAutoReset; + + // Query optimal input resolution + SuperResolutionSourceSettingsAttribs QueryAttribs; + QueryAttribs.VariantId = pTemporalInfo->VariantId; + QueryAttribs.OutputWidth = 1920; + QueryAttribs.OutputHeight = 1080; + QueryAttribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + QueryAttribs.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + QueryAttribs.Flags = SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE; + + SuperResolutionSourceSettings SourceSettings; + pFactory->GetSourceSettings(QueryAttribs, SourceSettings); + ASSERT_GT(SourceSettings.OptimalInputWidth, 0u); + ASSERT_GT(SourceSettings.OptimalInputHeight, 0u); + + SuperResolutionDesc Desc; + Desc.Name = "Test Temporal Upscaler"; + Desc.VariantId = pTemporalInfo->VariantId; + Desc.OutputWidth = QueryAttribs.OutputWidth; + Desc.OutputHeight = QueryAttribs.OutputHeight; + Desc.OutputFormat = QueryAttribs.OutputFormat; + Desc.InputWidth = SourceSettings.OptimalInputWidth; + Desc.InputHeight = SourceSettings.OptimalInputHeight; + Desc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.DepthFormat = TEX_FORMAT_R32_FLOAT; + Desc.MotionFormat = TEX_FORMAT_RG16_FLOAT; + Desc.Flags = QueryAttribs.Flags; + + RefCntAutoPtr pUpscaler; + pFactory->CreateSuperResolution(Desc, &pUpscaler); + ASSERT_NE(pUpscaler, nullptr) << "Failed to create temporal super resolution upscaler"; + + const auto& RetDesc = pUpscaler->GetDesc(); + EXPECT_EQ(RetDesc.VariantId, pTemporalInfo->VariantId); + EXPECT_EQ(RetDesc.OutputWidth, 1920u); + EXPECT_EQ(RetDesc.OutputHeight, 1080u); + EXPECT_EQ(RetDesc.InputWidth, SourceSettings.OptimalInputWidth); + EXPECT_EQ(RetDesc.InputHeight, SourceSettings.OptimalInputHeight); + + // Temporal upscaler should return non-trivial jitter pattern (Halton sequence) + float JitterX = 0.0f, JitterY = 0.0f; + pUpscaler->GetJitterOffset(0, &JitterX, &JitterY); + EXPECT_TRUE(JitterX != 0.0f || JitterY != 0.0f); + + // Verify a few frames produce different jitter values + float PrevJitterX = JitterX, PrevJitterY = JitterY; + pUpscaler->GetJitterOffset(1, &JitterX, &JitterY); + EXPECT_TRUE(JitterX != PrevJitterX || JitterY != PrevJitterY); +} + +TEST(SuperResolutionTest, ExecuteTemporalUpscaler) +{ + auto* pEnv = GPUTestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + auto* pFactory = GetFactory(); + ASSERT_NE(pFactory, nullptr); + + Uint32 NumVariants = 0; + pFactory->EnumerateVariants(NumVariants, nullptr); + if (NumVariants == 0) + { + GTEST_SKIP() << "No super resolution variants available on this device"; + } + + std::vector Variants(NumVariants); + pFactory->EnumerateVariants(NumVariants, Variants.data()); + + const auto* pTemporalInfo = FindVariantByType(Variants.data(), NumVariants, SUPER_RESOLUTION_TYPE_TEMPORAL); + if (pTemporalInfo == nullptr) + { + GTEST_SKIP() << "Temporal super resolution is not supported by this device"; + } + + GPUTestingEnvironment::ScopedReset EnvironmentAutoReset; + + + // Query optimal input resolution + SuperResolutionSourceSettingsAttribs QueryAttribs{}; + QueryAttribs.VariantId = pTemporalInfo->VariantId; + QueryAttribs.OutputWidth = 1920; + QueryAttribs.OutputHeight = 1080; + QueryAttribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + QueryAttribs.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + QueryAttribs.Flags = SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE; + + SuperResolutionSourceSettings SourceSettings{}; + pFactory->GetSourceSettings(QueryAttribs, SourceSettings); + ASSERT_GT(SourceSettings.OptimalInputWidth, 0u); + ASSERT_GT(SourceSettings.OptimalInputHeight, 0u); + + // Create upscaler + SuperResolutionDesc UpscalerDesc{}; + UpscalerDesc.Name = "Test Temporal Execute Upscaler"; + UpscalerDesc.VariantId = pTemporalInfo->VariantId; + UpscalerDesc.OutputWidth = QueryAttribs.OutputWidth; + UpscalerDesc.OutputHeight = QueryAttribs.OutputHeight; + UpscalerDesc.OutputFormat = QueryAttribs.OutputFormat; + UpscalerDesc.InputWidth = SourceSettings.OptimalInputWidth; + UpscalerDesc.InputHeight = SourceSettings.OptimalInputHeight; + UpscalerDesc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + UpscalerDesc.DepthFormat = TEX_FORMAT_R32_FLOAT; + UpscalerDesc.MotionFormat = TEX_FORMAT_RG16_FLOAT; + UpscalerDesc.Flags = QueryAttribs.Flags; + + RefCntAutoPtr pUpscaler; + pFactory->CreateSuperResolution(UpscalerDesc, &pUpscaler); + ASSERT_NE(pUpscaler, nullptr); + + + // Create input color texture + TextureDesc ColorTexDesc; + ColorTexDesc.Name = "SR Color Input"; + ColorTexDesc.Type = RESOURCE_DIM_TEX_2D; + ColorTexDesc.Width = SourceSettings.OptimalInputWidth; + ColorTexDesc.Height = SourceSettings.OptimalInputHeight; + ColorTexDesc.Format = TEX_FORMAT_RGBA16_FLOAT; + ColorTexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET; + ColorTexDesc.Usage = USAGE_DEFAULT; + + RefCntAutoPtr pColorTex; + pDevice->CreateTexture(ColorTexDesc, nullptr, &pColorTex); + ASSERT_NE(pColorTex, nullptr); + + // Create depth texture + TextureDesc DepthTexDesc; + DepthTexDesc.Name = "SR Depth Input"; + DepthTexDesc.Type = RESOURCE_DIM_TEX_2D; + DepthTexDesc.Width = SourceSettings.OptimalInputWidth; + DepthTexDesc.Height = SourceSettings.OptimalInputHeight; + DepthTexDesc.Format = TEX_FORMAT_D32_FLOAT; + DepthTexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_DEPTH_STENCIL; + DepthTexDesc.Usage = USAGE_DEFAULT; + + RefCntAutoPtr pDepthTex; + pDevice->CreateTexture(DepthTexDesc, nullptr, &pDepthTex); + ASSERT_NE(pDepthTex, nullptr); + + // Create motion vectors texture + TextureDesc MotionTexDesc; + MotionTexDesc.Name = "SR Motion Vectors"; + MotionTexDesc.Type = RESOURCE_DIM_TEX_2D; + MotionTexDesc.Width = SourceSettings.OptimalInputWidth; + MotionTexDesc.Height = SourceSettings.OptimalInputHeight; + MotionTexDesc.Format = TEX_FORMAT_RG16_FLOAT; + MotionTexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET; + MotionTexDesc.Usage = USAGE_DEFAULT; + + RefCntAutoPtr pMotionTex; + pDevice->CreateTexture(MotionTexDesc, nullptr, &pMotionTex); + ASSERT_NE(pMotionTex, nullptr); + + // Create output texture + TextureDesc OutputTexDesc{}; + OutputTexDesc.Name = "SR Output"; + OutputTexDesc.Type = RESOURCE_DIM_TEX_2D; + OutputTexDesc.Width = QueryAttribs.OutputWidth; + OutputTexDesc.Height = QueryAttribs.OutputHeight; + OutputTexDesc.Format = TEX_FORMAT_RGBA16_FLOAT; + OutputTexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; + OutputTexDesc.Usage = USAGE_DEFAULT; + + RefCntAutoPtr pOutputTex; + pDevice->CreateTexture(OutputTexDesc, nullptr, &pOutputTex); + ASSERT_NE(pOutputTex, nullptr); + + // Execute temporal upscaling with reset + auto* pContext = pEnv->GetDeviceContext(); + + ExecuteSuperResolutionAttribs Attribs; + Attribs.pContext = pContext; + Attribs.pColorTextureSRV = pColorTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pDepthTextureSRV = pDepthTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pMotionVectorsSRV = pMotionTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pOutputTextureView = pOutputTex->GetDefaultView(TEXTURE_VIEW_UNORDERED_ACCESS); + Attribs.JitterX = 0.0f; + Attribs.JitterY = 0.0f; + Attribs.MotionVectorScaleX = 1.0f; + Attribs.MotionVectorScaleY = 1.0f; + Attribs.ExposureScale = 1.0f; + Attribs.Sharpness = 0.5f; + Attribs.CameraNear = 0.1f; + Attribs.CameraFar = 1000.0f; + Attribs.CameraFovAngleVert = 1.0472f; // ~60 degrees + + Attribs.TimeDeltaInSeconds = 0.016f; + Attribs.ResetHistory = true; + pUpscaler->Execute(Attribs); + + // Execute a second frame without reset + Attribs.JitterX = -0.25f; + Attribs.JitterY = 0.25f; + Attribs.ResetHistory = False; + pUpscaler->Execute(Attribs); + + pContext->Flush(); + pContext->WaitForIdle(); +} + +TEST(SuperResolution_CInterface, Factory) +{ + auto* pFactory = GetFactory(); + ASSERT_NE(pFactory, nullptr); + EXPECT_EQ(TestSuperResolutionFactoryCInterface(pFactory), 0); +} + +TEST(SuperResolution_CInterface, SuperResolution) +{ + auto* pFactory = GetFactory(); + ASSERT_NE(pFactory, nullptr); + + Uint32 NumVariants = 0; + pFactory->EnumerateVariants(NumVariants, nullptr); + if (NumVariants == 0) + { + GTEST_SKIP() << "No super resolution variants available on this device"; + } + + std::vector Variants(NumVariants); + pFactory->EnumerateVariants(NumVariants, Variants.data()); + + GPUTestingEnvironment::ScopedReset EnvironmentAutoReset; + + SuperResolutionSourceSettingsAttribs QueryAttribs; + QueryAttribs.VariantId = Variants[0].VariantId; + QueryAttribs.OutputWidth = 1920; + QueryAttribs.OutputHeight = 1080; + QueryAttribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + QueryAttribs.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + QueryAttribs.Flags = SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE; + + SuperResolutionSourceSettings SourceSettings; + pFactory->GetSourceSettings(QueryAttribs, SourceSettings); + + SuperResolutionDesc Desc; + Desc.Name = "C Interface Test Upscaler"; + Desc.VariantId = Variants[0].VariantId; + Desc.OutputWidth = QueryAttribs.OutputWidth; + Desc.OutputHeight = QueryAttribs.OutputHeight; + Desc.OutputFormat = QueryAttribs.OutputFormat; + Desc.InputWidth = SourceSettings.OptimalInputWidth; + Desc.InputHeight = SourceSettings.OptimalInputHeight; + Desc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.DepthFormat = TEX_FORMAT_R32_FLOAT; + Desc.MotionFormat = TEX_FORMAT_RG16_FLOAT; + Desc.Flags = SUPER_RESOLUTION_FLAG_AUTO_EXPOSURE; + + RefCntAutoPtr pUpscaler; + pFactory->CreateSuperResolution(Desc, &pUpscaler); + ASSERT_NE(pUpscaler, nullptr); + + EXPECT_EQ(TestSuperResolutionCInterface(pUpscaler), 0); +} + +} // namespace diff --git a/Tests/DiligentCoreAPITest/src/c_interface/SuperResolution_C_Test.c b/Tests/DiligentCoreAPITest/src/c_interface/SuperResolution_C_Test.c new file mode 100644 index 0000000000..b7a5c40fd0 --- /dev/null +++ b/Tests/DiligentCoreAPITest/src/c_interface/SuperResolution_C_Test.c @@ -0,0 +1,85 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "SuperResolution.h" +#include "SuperResolutionFactory.h" + +int TestObjectCInterface(struct IObject* pObject); + +int TestSuperResolutionCInterface(struct ISuperResolution* pUpscaler) +{ + IObject* pUnknown = NULL; + ReferenceCounterValueType RefCnt1 = 0, RefCnt2 = 0; + + const SuperResolutionDesc* pUpscalerDesc = NULL; + float JitterX = 0.0f; + float JitterY = 0.0f; + + int num_errors = + TestObjectCInterface((struct IObject*)pUpscaler); + + IObject_QueryInterface(pUpscaler, &IID_Unknown, &pUnknown); + if (pUnknown != NULL) + IObject_Release(pUnknown); + else + ++num_errors; + + RefCnt1 = IObject_AddRef(pUpscaler); + if (RefCnt1 <= 1) + ++num_errors; + RefCnt2 = IObject_Release(pUpscaler); + if (RefCnt2 <= 0) + ++num_errors; + if (RefCnt2 != RefCnt1 - 1) + ++num_errors; + + pUpscalerDesc = ISuperResolution_GetDesc(pUpscaler); + if (pUpscalerDesc == NULL) + ++num_errors; + if (pUpscalerDesc->Name == NULL) + ++num_errors; + if (pUpscalerDesc->InputWidth == 0) + ++num_errors; + if (pUpscalerDesc->InputHeight == 0) + ++num_errors; + + ISuperResolution_GetJitterOffset(pUpscaler, 0, &JitterX, &JitterY); + (void)JitterX; + (void)JitterY; + + return num_errors; +} + +int TestSuperResolutionFactoryCInterface(struct ISuperResolutionFactory* pFactory) +{ + int num_errors = 0; + Uint32 NumVariants = 0; + + ISuperResolutionFactory_EnumerateVariants(pFactory, &NumVariants, NULL); + (void)NumVariants; + + return num_errors; +} diff --git a/Tests/IncludeTest/SuperResolution/SuperResolutionFactoryH_test.c b/Tests/IncludeTest/SuperResolution/SuperResolutionFactoryH_test.c new file mode 100644 index 0000000000..27b6a6a7d2 --- /dev/null +++ b/Tests/IncludeTest/SuperResolution/SuperResolutionFactoryH_test.c @@ -0,0 +1,35 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "DiligentCore/Graphics/SuperResolution/interface/SuperResolutionFactory.h" + +void TestSuperResolutionFactory_CInterface(ISuperResolutionFactory* pSuperResolutionFactory) +{ + ISuperResolutionFactory_EnumerateVariants(pSuperResolutionFactory, (Uint32*)NULL, (SuperResolutionInfo*)NULL); + ISuperResolutionFactory_GetSourceSettings(pSuperResolutionFactory, (const SuperResolutionSourceSettingsAttribs*)NULL, (SuperResolutionSourceSettings*)NULL); + ISuperResolutionFactory_CreateSuperResolution(pSuperResolutionFactory, (const SuperResolutionDesc*)NULL, (ISuperResolution**)NULL); + ISuperResolutionFactory_SetMessageCallback(pSuperResolutionFactory, (DebugMessageCallbackType)NULL); +} diff --git a/Tests/IncludeTest/SuperResolution/SuperResolutionFactoryH_test.cpp b/Tests/IncludeTest/SuperResolution/SuperResolutionFactoryH_test.cpp new file mode 100644 index 0000000000..473932d2c1 --- /dev/null +++ b/Tests/IncludeTest/SuperResolution/SuperResolutionFactoryH_test.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "DiligentCore/Graphics/SuperResolution/interface/SuperResolutionFactory.h" diff --git a/Tests/IncludeTest/SuperResolution/SuperResolutionH_test.c b/Tests/IncludeTest/SuperResolution/SuperResolutionH_test.c new file mode 100644 index 0000000000..60abe3091a --- /dev/null +++ b/Tests/IncludeTest/SuperResolution/SuperResolutionH_test.c @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "DiligentCore/Graphics/SuperResolution/interface/SuperResolution.h" + +void TestSuperResolution_CInterface(ISuperResolution* pUpscaler) +{ + ISuperResolution_GetDesc(pUpscaler); + ISuperResolution_GetJitterOffset(pUpscaler, 0, (float*)NULL, (float*)NULL); + ISuperResolution_Execute(pUpscaler, (const ExecuteSuperResolutionAttribs*)NULL); +} diff --git a/Tests/IncludeTest/SuperResolution/SuperResolutionH_test.cpp b/Tests/IncludeTest/SuperResolution/SuperResolutionH_test.cpp new file mode 100644 index 0000000000..d629afdc83 --- /dev/null +++ b/Tests/IncludeTest/SuperResolution/SuperResolutionH_test.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "DiligentCore/Graphics/SuperResolution/interface/SuperResolution.h"