From a43a3fcbe3e669befbc3c5c8536be995b79a6fa0 Mon Sep 17 00:00:00 2001 From: MikhailGorobets Date: Wed, 4 Mar 2026 14:37:33 +0600 Subject: [PATCH 1/7] Add ISuperResolution interface and SuperResolution device feature --- Graphics/GraphicsEngine/interface/Constants.h | 24 +- .../GraphicsEngine/interface/DeviceContext.h | 17 + .../GraphicsEngine/interface/GraphicsTypes.h | 172 +++++++++- .../GraphicsEngine/interface/RenderDevice.h | 88 ++++-- .../interface/SuperResolution.h | 295 ++++++++++++++++++ 5 files changed, 556 insertions(+), 40 deletions(-) create mode 100644 Graphics/GraphicsEngine/interface/SuperResolution.h diff --git a/Graphics/GraphicsEngine/interface/Constants.h b/Graphics/GraphicsEngine/interface/Constants.h index a54a336cd..f08b557f0 100644 --- a/Graphics/GraphicsEngine/interface/Constants.h +++ b/Graphics/GraphicsEngine/interface/Constants.h @@ -65,15 +65,19 @@ DILIGENT_BEGIN_NAMESPACE(Diligent) /// The maximum number of 4-byte inline constants in a pipeline state. #define DILIGENT_MAX_INLINE_CONSTANTS 64 -static DILIGENT_CONSTEXPR Uint32 MAX_BUFFER_SLOTS = DILIGENT_MAX_BUFFER_SLOTS; -static DILIGENT_CONSTEXPR Uint32 MAX_RENDER_TARGETS = DILIGENT_MAX_RENDER_TARGETS; -static DILIGENT_CONSTEXPR Uint32 MAX_VIEWPORTS = DILIGENT_MAX_VIEWPORTS; -static DILIGENT_CONSTEXPR Uint32 MAX_RESOURCE_SIGNATURES = DILIGENT_MAX_RESOURCE_SIGNATURES; -static DILIGENT_CONSTEXPR Uint32 MAX_ADAPTER_QUEUES = DILIGENT_MAX_ADAPTER_QUEUES; -static DILIGENT_CONSTEXPR Uint32 DEFAULT_ADAPTER_ID = DILIGENT_DEFAULT_ADAPTER_ID; -static DILIGENT_CONSTEXPR Uint8 DEFAULT_QUEUE_ID = DILIGENT_DEFAULT_QUEUE_ID; -static DILIGENT_CONSTEXPR Uint32 MAX_SHADING_RATES = DILIGENT_MAX_SHADING_RATES; -static DILIGENT_CONSTEXPR Uint32 SHADING_RATE_X_SHIFT = DILIGENT_SHADING_RATE_X_SHIFT; -static DILIGENT_CONSTEXPR Uint32 MAX_INLINE_CONSTANTS = DILIGENT_MAX_INLINE_CONSTANTS; +/// The maximum number of super resolution upscaler variants. +#define DILIGENT_MAX_SUPER_RESOLUTION_UPSCALERS 8 + +static DILIGENT_CONSTEXPR Uint32 MAX_BUFFER_SLOTS = DILIGENT_MAX_BUFFER_SLOTS; +static DILIGENT_CONSTEXPR Uint32 MAX_RENDER_TARGETS = DILIGENT_MAX_RENDER_TARGETS; +static DILIGENT_CONSTEXPR Uint32 MAX_VIEWPORTS = DILIGENT_MAX_VIEWPORTS; +static DILIGENT_CONSTEXPR Uint32 MAX_RESOURCE_SIGNATURES = DILIGENT_MAX_RESOURCE_SIGNATURES; +static DILIGENT_CONSTEXPR Uint32 MAX_ADAPTER_QUEUES = DILIGENT_MAX_ADAPTER_QUEUES; +static DILIGENT_CONSTEXPR Uint32 DEFAULT_ADAPTER_ID = DILIGENT_DEFAULT_ADAPTER_ID; +static DILIGENT_CONSTEXPR Uint8 DEFAULT_QUEUE_ID = DILIGENT_DEFAULT_QUEUE_ID; +static DILIGENT_CONSTEXPR Uint32 MAX_SHADING_RATES = DILIGENT_MAX_SHADING_RATES; +static DILIGENT_CONSTEXPR Uint32 SHADING_RATE_X_SHIFT = DILIGENT_SHADING_RATE_X_SHIFT; +static DILIGENT_CONSTEXPR Uint32 MAX_INLINE_CONSTANTS = DILIGENT_MAX_INLINE_CONSTANTS; +static DILIGENT_CONSTEXPR Uint32 MAX_SUPER_RESOLUTION_UPSCALERS = DILIGENT_MAX_SUPER_RESOLUTION_UPSCALERS; DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index f3b073fa0..9b83f4bc4 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -58,6 +58,7 @@ #include "ShaderBindingTable.h" #include "DeviceMemory.h" #include "CommandQueue.h" +#include "SuperResolution.h" DILIGENT_BEGIN_NAMESPACE(Diligent) @@ -3750,6 +3751,21 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject) /// Returns the device context statistics, see Diligent::DeviceContextStats. VIRTUAL const DeviceContextStats REF METHOD(GetStats)(THIS) CONST PURE; + + + /// Executes the hardware super resolution upscaler. + + /// \param [in] Attribs - Upscale operation attributes, see Diligent::ExecuteSuperResolutionAttribs. + /// \param [in] pUpscaler - Super resolution upscaler object to execute. + /// + /// \remarks 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(ExecuteSuperResolution)(THIS_ + const ExecuteSuperResolutionAttribs REF Attribs, + ISuperResolution* pUpscaler) PURE; }; DILIGENT_END_INTERFACE @@ -3829,6 +3845,7 @@ DILIGENT_END_INTERFACE # define IDeviceContext_BindSparseResourceMemory(This, ...) CALL_IFACE_METHOD(DeviceContext, BindSparseResourceMemory, This, __VA_ARGS__) # define IDeviceContext_ClearStats(This) CALL_IFACE_METHOD(DeviceContext, ClearStats, This) # define IDeviceContext_GetStats(This) CALL_IFACE_METHOD(DeviceContext, GetStats, This) +# define IDeviceContext_ExecuteSuperResolution(This, ...) CALL_IFACE_METHOD(DeviceContext, ExecuteSuperResolution, This, __VA_ARGS__) // clang-format on diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 305c8cfac..41eeb0074 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1867,6 +1867,10 @@ struct DeviceFeatures /// Not supported by D3D11, D3D12, OpenGL, or Metal backends. DEVICE_FEATURE_STATE SpecializationConstants DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + /// Indicates if the device supports hardware super resolution (upscaling). + /// MetalFX on Metal, DirectSR on D3D12. + DEVICE_FEATURE_STATE SuperResolution DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED); + #if DILIGENT_CPP_INTERFACE constexpr DeviceFeatures() noexcept {} @@ -1918,11 +1922,12 @@ struct DeviceFeatures Handler(NativeMultiDraw) \ Handler(AsyncShaderCompilation) \ Handler(FormattedBuffers) \ - Handler(SpecializationConstants) + Handler(SpecializationConstants) \ + Handler(SuperResolution) explicit constexpr DeviceFeatures(DEVICE_FEATURE_STATE State) noexcept { - static_assert(sizeof(*this) == 48, "Did you add a new feature to DeviceFeatures? Please add it to ENUMERATE_DEVICE_FEATURES."); + static_assert(sizeof(*this) == 49, "Did you add a new feature to DeviceFeatures? Please add it to ENUMERATE_DEVICE_FEATURES."); #define INIT_FEATURE(Feature) Feature = State; ENUMERATE_DEVICE_FEATURES(INIT_FEATURE) #undef INIT_FEATURE @@ -3263,6 +3268,165 @@ struct SparseResourceProperties typedef struct SparseResourceProperties SparseResourceProperties; +/// Super resolution upscaler type. +DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_UPSCALER_TYPE, Uint8) +{ + /// Spatial upscaling only (single frame, no motion vectors required). + SUPER_RESOLUTION_UPSCALER_TYPE_SPATIAL = 0u, + + /// Temporal upscaling (uses motion vectors and history accumulation). + SUPER_RESOLUTION_UPSCALER_TYPE_TEMPORAL +}; + + +/// 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 +}; + + +/// 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 upscaler variant +struct SuperResolutionInfo +{ + /// Human-readable name of the upscaler variant (e.g. "MetalFX Spatial", "MetalFX Temporal"). + Char Name[128] DEFAULT_INITIALIZER({}); + + /// Unique identifier for this upscaler variant. + /// Pass this VariantId to SuperResolutionDesc when creating an upscaler. + INTERFACE_ID VariantId DEFAULT_INITIALIZER({}); + + /// Upscaler type. Determines which input textures and parameters are required. + SUPER_RESOLUTION_UPSCALER_TYPE Type DEFAULT_INITIALIZER(SUPER_RESOLUTION_UPSCALER_TYPE_SPATIAL); + +#if defined(DILIGENT_SHARP_GEN) + Uint32 CapFlags DEFAULT_INITIALIZER(0); +#else + union + { + /// Capability flags for SUPER_RESOLUTION_UPSCALER_TYPE_SPATIAL. + SUPER_RESOLUTION_SPATIAL_CAP_FLAGS SpatialCapFlags DEFAULT_INITIALIZER(SUPER_RESOLUTION_SPATIAL_CAP_FLAG_NONE); + + /// Capability flags for SUPER_RESOLUTION_UPSCALER_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; + + +/// Super resolution properties, reported via GraphicsAdapterInfo +struct SuperResolutionProperties +{ + /// Array of supported upscaler variants and their capabilities. + SuperResolutionInfo Upscalers[DILIGENT_MAX_SUPER_RESOLUTION_UPSCALERS] DEFAULT_INITIALIZER({}); + + /// The number of valid elements in the Upscalers array. + Uint8 NumUpscalers DEFAULT_INITIALIZER(0); + +#if DILIGENT_CPP_INTERFACE + bool operator==(const SuperResolutionProperties& RHS) const + { + if (NumUpscalers != RHS.NumUpscalers) + return false; + + for (Uint8 i = 0; i < NumUpscalers; ++i) + if (!(Upscalers[i] == RHS.Upscalers[i])) + return false; + + return true; + } +#endif +}; +typedef struct SuperResolutionProperties SuperResolutionProperties; + + /// Command queue properties struct CommandQueueInfo { @@ -3354,6 +3518,9 @@ struct GraphicsAdapterInfo /// Sparse resource properties, see Diligent::SparseResourceProperties. SparseResourceProperties SparseResources; + /// Super resolution upscaler properties, see Diligent::SuperResolutionProperties. + SuperResolutionProperties SuperResolution; + /// Supported device features, see Diligent::DeviceFeatures. /// The feature state indicates: @@ -3400,6 +3567,7 @@ struct GraphicsAdapterInfo ComputeShader == RHS.ComputeShader && DrawCommand == RHS.DrawCommand && SparseResources == RHS.SparseResources && + SuperResolution == RHS.SuperResolution && Features == RHS.Features && memcmp(Description, RHS.Description, sizeof(Description)) == 0; } diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h index 884959104..ec345662d 100644 --- a/Graphics/GraphicsEngine/interface/RenderDevice.h +++ b/Graphics/GraphicsEngine/interface/RenderDevice.h @@ -343,6 +343,21 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) IPipelineStateCache** ppPSOCache) PURE; + /// Creates a new super resolution 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; + + /// Creates a deferred context. /// \param [out] ppContext - Address of the memory location where a pointer to the @@ -394,6 +409,21 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) Uint32 SampleCount, SparseTextureFormatInfo REF FormatInfo) CONST 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(GetSuperResolutionSourceSettings)(THIS_ + const SuperResolutionSourceSettingsAttribs REF Attribs, + SuperResolutionSourceSettings REF Settings) CONST PURE; + + /// Purges device release queues and releases all stale resources. /// This method is automatically called by ISwapChain::Present() of the primary swap chain. /// \param [in] ForceRelease - Forces release of all objects. Use this option with @@ -457,34 +487,36 @@ DILIGENT_END_INTERFACE #if DILIGENT_C_INTERFACE // clang-format off -# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__) -# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__) -# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__) -# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__) -# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__) -# define IRenderDevice_CreateGraphicsPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateGraphicsPipelineState, This, __VA_ARGS__) -# define IRenderDevice_CreateComputePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateComputePipelineState, This, __VA_ARGS__) -# define IRenderDevice_CreateRayTracingPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateRayTracingPipelineState, This, __VA_ARGS__) -# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__) -# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__) -# define IRenderDevice_CreateRenderPass(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateRenderPass, This, __VA_ARGS__) -# define IRenderDevice_CreateFramebuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFramebuffer, This, __VA_ARGS__) -# define IRenderDevice_CreateBLAS(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBLAS, This, __VA_ARGS__) -# define IRenderDevice_CreateTLAS(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTLAS, This, __VA_ARGS__) -# define IRenderDevice_CreateSBT(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSBT, This, __VA_ARGS__) -# define IRenderDevice_CreatePipelineResourceSignature(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineResourceSignature, This, __VA_ARGS__) -# define IRenderDevice_CreateDeviceMemory(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateDeviceMemory, This, __VA_ARGS__) -# define IRenderDevice_CreatePipelineStateCache(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineStateCache, This, __VA_ARGS__) -# define IRenderDevice_CreateDeferredContext(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateDeferredContext, This, __VA_ARGS__) -# define IRenderDevice_GetAdapterInfo(This) CALL_IFACE_METHOD(RenderDevice, GetAdapterInfo, This) -# define IRenderDevice_GetDeviceInfo(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceInfo, This) -# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__) -# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt, This, __VA_ARGS__) -# define IRenderDevice_GetSparseTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetSparseTextureFormatInfo, This, __VA_ARGS__) -# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__) -# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This) -# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This) -# define IRenderDevice_GetShaderCompilationThreadPool(This) CALL_IFACE_METHOD(RenderDevice, GetShaderCompilationThreadPool, This) +# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__) +# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__) +# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__) +# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__) +# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__) +# define IRenderDevice_CreateGraphicsPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateGraphicsPipelineState, This, __VA_ARGS__) +# define IRenderDevice_CreateComputePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateComputePipelineState, This, __VA_ARGS__) +# define IRenderDevice_CreateRayTracingPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateRayTracingPipelineState, This, __VA_ARGS__) +# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__) +# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__) +# define IRenderDevice_CreateRenderPass(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateRenderPass, This, __VA_ARGS__) +# define IRenderDevice_CreateFramebuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFramebuffer, This, __VA_ARGS__) +# define IRenderDevice_CreateBLAS(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBLAS, This, __VA_ARGS__) +# define IRenderDevice_CreateTLAS(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTLAS, This, __VA_ARGS__) +# define IRenderDevice_CreateSBT(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSBT, This, __VA_ARGS__) +# define IRenderDevice_CreatePipelineResourceSignature(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineResourceSignature, This, __VA_ARGS__) +# define IRenderDevice_CreateDeviceMemory(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateDeviceMemory, This, __VA_ARGS__) +# define IRenderDevice_CreatePipelineStateCache(This, ...) CALL_IFACE_METHOD(RenderDevice, CreatePipelineStateCache, This, __VA_ARGS__) +# define IRenderDevice_CreateSuperResolution(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSuperResolution, This, __VA_ARGS__) +# define IRenderDevice_CreateDeferredContext(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateDeferredContext, This, __VA_ARGS__) +# define IRenderDevice_GetAdapterInfo(This) CALL_IFACE_METHOD(RenderDevice, GetAdapterInfo, This) +# define IRenderDevice_GetDeviceInfo(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceInfo, This) +# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__) +# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt, This, __VA_ARGS__) +# define IRenderDevice_GetSparseTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetSparseTextureFormatInfo, This, __VA_ARGS__) +# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__) +# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This) +# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This) +# define IRenderDevice_GetShaderCompilationThreadPool(This) CALL_IFACE_METHOD(RenderDevice, GetShaderCompilationThreadPool, This) +# define IRenderDevice_GetSuperResolutionSourceSettings(This, ...) CALL_IFACE_METHOD(RenderDevice, GetSuperResolutionSourceSettings, This, __VA_ARGS__) // clang-format on #endif diff --git a/Graphics/GraphicsEngine/interface/SuperResolution.h b/Graphics/GraphicsEngine/interface/SuperResolution.h new file mode 100644 index 000000000..4bfae91a2 --- /dev/null +++ b/Graphics/GraphicsEngine/interface/SuperResolution.h @@ -0,0 +1,295 @@ +/* + * 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 "DeviceObject.h" +#include "GraphicsTypes.h" +#include "TextureView.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 + +/// This structure describes the super resolution upscaler object and is part of the creation +/// parameters given to IRenderDevice::CreateSuperResolution(). +struct SuperResolutionDesc DILIGENT_DERIVE(DeviceObjectAttribs) + + /// Unique identifier of the upscaler variant to create. + /// Must match one of the VariantIds reported in SuperResolutionProperties::Upscalers. + INTERFACE_ID VariantId DEFAULT_INITIALIZER({}); + + /// Input (render) width. Must be greater than zero and not exceed OutputWidth. + /// Use IRenderDevice::GetSuperResolutionSourceSettings() 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 IRenderDevice::GetSuperResolutionSourceSettings() 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); + + /// Ignore history mask texture format. + /// Optional. Used for temporal upscaling to indicate regions where temporal history + /// should be completely discarded (binary mask: 0 = use history, 1 = ignore history). + /// Unlike the reactive mask which provides proportional control, this is a binary decision. + TEXTURE_FORMAT IgnoreHistoryMaskFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// When True, the upscaler automatically calculates exposure for each frame. + /// When auto exposure is enabled, the exposure texture in + /// ExecuteSuperResolutionAttribs is ignored. + Bool AutoExposureEnabled DEFAULT_INITIALIZER(True); +}; +typedef struct SuperResolutionDesc SuperResolutionDesc; + + +/// Attributes for querying the optimal source (input) settings for super resolution upscaling. +/// +/// This structure is used by IRenderDevice::GetSuperResolutionSourceSettings(). +struct SuperResolutionSourceSettingsAttribs +{ + /// Unique identifier of the upscaler variant to query. + /// Must match one of the VariantIds reported in SuperResolutionProperties::Upscalers. + 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); + + /// Optimization type controlling the quality/performance trade-off. + SUPER_RESOLUTION_OPTIMIZATION_TYPE OptimizationType DEFAULT_INITIALIZER(SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED); +}; +typedef struct SuperResolutionSourceSettingsAttribs SuperResolutionSourceSettingsAttribs; + + +/// Optimal source (input) settings returned by IRenderDevice::GetSuperResolutionSourceSettings(). +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 upscaler execute attributes + +/// This structure is used by IDeviceContext::ExecuteSuperResolution(). +struct ExecuteSuperResolutionAttribs +{ + /// 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_UPSCALER_TYPE_TEMPORAL). + ITextureView* pDepthTextureSRV DEFAULT_INITIALIZER(nullptr); + + /// Motion vectors texture (shader resource view). + /// Required for temporal upscaling (SUPER_RESOLUTION_UPSCALER_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* pOutputTextureRTV 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::AutoExposureEnabled is True. + 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). + /// Only used when SuperResolutionDesc::IgnoreHistoryMaskFormat != TEX_FORMAT_UNKNOWN. + 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 \ + IDeviceObjectInclusiveMethods; \ + ISuperResolutionMethods SuperResolution + +/// Hardware super resolution upscaler interface. +/// +/// The super resolution upscaler object encapsulates a hardware-accelerated super resolution +/// effect (e.g., MetalFX on Metal, DirectSR on D3D12). +/// It is created via IRenderDevice::CreateSuperResolution() and executed +/// via IDeviceContext::ExecuteSuperResolution(). +DILIGENT_BEGIN_INTERFACE(ISuperResolution, IDeviceObject) +{ +#if DILIGENT_CPP_INTERFACE + /// Returns the super resolution upscaler description used to create the object. + virtual const SuperResolutionDesc& METHOD(GetDesc)() const override = 0; +#endif + + /// 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(GetOptimalJitterPattern)(THIS_ + Uint32 Index, + float* pJitterX, + float* pJitterY) CONST PURE; +}; +DILIGENT_END_INTERFACE + +// clang-format on + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +// clang-format off +# define ISuperResolution_GetDesc(This) (const struct SuperResolutionDesc*)IDeviceObject_GetDesc(This) + +# define ISuperResolution_GetOptimalJitterPattern(This, ...) CALL_IFACE_METHOD(SuperResolution, GetOptimalJitterPattern, This, __VA_ARGS__) + +// clang-format on + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent From fa2f5e8b8baaa43fc05e8ddb522957ec3b48d363 Mon Sep 17 00:00:00 2001 From: MikhailGorobets Date: Wed, 4 Mar 2026 14:37:40 +0600 Subject: [PATCH 2/7] Implement SuperResolution stubs in D3D11, D3D12, Vulkan, OpenGL, and WebGPU backends --- .../include/RenderDeviceBase.hpp | 13 ++++++++++++ .../GraphicsEngine/src/RenderDeviceBase.cpp | 3 ++- .../include/DeviceContextD3D11Impl.hpp | 3 +++ .../include/EngineD3D11ImplTraits.hpp | 6 +++--- .../include/RenderDeviceD3D11Impl.hpp | 8 ++++++++ .../src/DeviceContextD3D11Impl.cpp | 6 ++++++ .../src/EngineFactoryD3D11.cpp | 2 +- .../src/RenderDeviceD3D11Impl.cpp | 18 +++++++++++++++++ .../include/DeviceContextD3D12Impl.hpp | 3 +++ .../include/EngineD3D12ImplTraits.hpp | 2 ++ .../include/RenderDeviceD3D12Impl.hpp | 8 ++++++++ .../src/DeviceContextD3D12Impl.cpp | 6 ++++++ .../src/EngineFactoryD3D12.cpp | 2 +- .../src/RenderDeviceD3D12Impl.cpp | 17 ++++++++++++++++ .../include/DeviceContextGLImpl.hpp | 3 +++ .../include/EngineGLImplTraits.hpp | 5 +++-- .../include/RenderDeviceGLImpl.hpp | 8 ++++++++ .../src/DeviceContextGLImpl.cpp | 6 ++++++ .../src/RenderDeviceGLImpl.cpp | 20 ++++++++++++++++++- .../include/DeviceContextVkImpl.hpp | 3 +++ .../include/EngineVkImplTraits.hpp | 2 ++ .../include/RenderDeviceVkImpl.hpp | 8 ++++++++ .../src/DeviceContextVkImpl.cpp | 6 ++++++ .../src/EngineFactoryVk.cpp | 2 +- .../src/RenderDeviceVkImpl.cpp | 17 ++++++++++++++++ .../src/VulkanTypeConversions.cpp | 2 +- .../include/DeviceContextWebGPUImpl.hpp | 3 +++ .../include/EngineWebGPUImplTraits.hpp | 5 +++-- .../include/RenderDeviceWebGPUImpl.hpp | 8 ++++++++ .../src/DeviceContextWebGPUImpl.cpp | 6 ++++++ .../src/EngineFactoryWebGPU.cpp | 2 +- .../src/RenderDeviceWebGPUImpl.cpp | 20 +++++++++++++++++++ 32 files changed, 209 insertions(+), 14 deletions(-) diff --git a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp index c2aa19f01..00f84bbfb 100644 --- a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp @@ -52,6 +52,7 @@ #include "IndexWrapper.hpp" #include "ThreadPool.hpp" #include "SpinLock.hpp" +#include "SuperResolution.h" namespace Diligent { @@ -119,6 +120,7 @@ class RenderDeviceBase : public ObjectBase + void CreateSuperResolutionImpl(ISuperResolution** ppUpscaler, const SuperResolutionDesc& Desc, const ExtraArgsType&... ExtraArgs) + { + CreateDeviceObject("Super Resolution Upscaler", Desc, ppUpscaler, + [&]() // + { + SuperResolutionImplType* pUpscalerImpl = NEW_RC_OBJ(GetRawAllocator(), "SuperResolution instance", SuperResolutionImplType)(static_cast(this), Desc, ExtraArgs...); + pUpscalerImpl->QueryInterface(IID_SuperResolution, reinterpret_cast(ppUpscaler)); + }); + } + template void CreateDeferredContextImpl(IDeviceContext** ppContext, const ExtraArgsType&... ExtraArgs) { diff --git a/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp b/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp index 4e471599c..5811329bd 100644 --- a/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp @@ -121,9 +121,10 @@ DeviceFeatures EnableDeviceFeatures(const DeviceFeatures& SupportedFeatures, ENABLE_FEATURE(AsyncShaderCompilation, "Async shader compilation is"); ENABLE_FEATURE(FormattedBuffers, "Formatted buffers are"); ENABLE_FEATURE(SpecializationConstants, "Specialization constants are"); + ENABLE_FEATURE(SuperResolution, "Super resolution is"); // clang-format on - ASSERT_SIZEOF(DeviceFeatures, 48, "Did you add a new feature to DeviceFeatures? Please handle its status here (if necessary)."); + ASSERT_SIZEOF(DeviceFeatures, 49, "Did you add a new feature to DeviceFeatures? Please handle its status here (if necessary)."); return EnabledFeatures; } diff --git a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp index 0432485d3..139670d44 100644 --- a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp @@ -284,6 +284,9 @@ class DeviceContextD3D11Impl final : public DeviceContextBase SHADING_RATE_COMBINER PrimitiveCombiner, SHADING_RATE_COMBINER TextureCombiner) override final; + /// Implementation of IDeviceContext::ExecuteSuperResolution() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE ExecuteSuperResolution(const ExecuteSuperResolutionAttribs& Attribs, + ISuperResolution* pUpscaler) override final; /// Implementation of IDeviceContext::BindSparseResourceMemory() in OpenGL backend. virtual void DILIGENT_CALL_TYPE BindSparseResourceMemory(const BindSparseResourceMemoryAttribs& Attribs) override final; diff --git a/Graphics/GraphicsEngineOpenGL/include/EngineGLImplTraits.hpp b/Graphics/GraphicsEngineOpenGL/include/EngineGLImplTraits.hpp index 2d0b30599..26f0ce241 100644 --- a/Graphics/GraphicsEngineOpenGL/include/EngineGLImplTraits.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/EngineGLImplTraits.hpp @@ -69,8 +69,8 @@ class TopLevelASGLImpl; class ShaderBindingTableGLImpl; class PipelineResourceSignatureGLImpl; class DeviceMemoryGLImpl; -class PipelineStateCacheGlImpl -{}; +class PipelineStateCacheGlImpl; +class SuperResolutionGLImpl; class FixedBlockMemoryAllocator; @@ -128,6 +128,7 @@ struct EngineGLImplTraits using PipelineResourceSignatureImplType = PipelineResourceSignatureGLImpl; using DeviceMemoryImplType = DeviceMemoryGLImpl; using PipelineStateCacheImplType = PipelineStateCacheGlImpl; + using SuperResolutionImplType = SuperResolutionGLImpl; using BuffViewObjAllocatorType = FixedBlockMemoryAllocator; using TexViewObjAllocatorType = FixedBlockMemoryAllocator; diff --git a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp index ea7183ba9..24981d619 100644 --- a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp @@ -140,6 +140,14 @@ class RenderDeviceGLImpl : public RenderDeviceBase virtual void DILIGENT_CALL_TYPE CreateSBT(const ShaderBindingTableDesc& Desc, IShaderBindingTable** ppSBT) override final; + /// Implementation of IRenderDevice::CreateSuperResolution() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE CreateSuperResolution(const SuperResolutionDesc& Desc, + ISuperResolution** ppUpscaler) override final; + + /// Implementation of IRenderDevice::GetSuperResolutionSourceSettings() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE GetSuperResolutionSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, + SuperResolutionSourceSettings& Settings) const override final; + /// Implementation of IRenderDevice::CreatePipelineResourceSignature() in OpenGL backend. virtual void DILIGENT_CALL_TYPE CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, IPipelineResourceSignature** ppSignature) override final; diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index 7f6006455..9a34a4069 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -2121,6 +2121,12 @@ void DeviceContextGLImpl::SetShadingRate(SHADING_RATE BaseRate, SHADING_RATE_COM UNSUPPORTED("SetShadingRate is not supported in OpenGL"); } +void DeviceContextGLImpl::ExecuteSuperResolution(const ExecuteSuperResolutionAttribs& Attribs, + ISuperResolution* pUpscaler) +{ + UNSUPPORTED("ExecuteSuperResolution is not supported in OpenGL"); +} + void DeviceContextGLImpl::BindSparseResourceMemory(const BindSparseResourceMemoryAttribs& Attribs) { UNSUPPORTED("BindSparseResourceMemory is not supported in OpenGL"); diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp index 298afaf04..594cca4e6 100644 --- a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp @@ -134,6 +134,10 @@ class ShaderBindingTableGLImpl {}; class DeviceMemoryGLImpl {}; +class PipelineStateCacheGlImpl +{}; +class SuperResolutionGLImpl +{}; static void VerifyEngineGLCreateInfo(const EngineGLCreateInfo& EngineCI) noexcept(false) { @@ -635,6 +639,20 @@ void RenderDeviceGLImpl::CreateSBT(const ShaderBindingTableDesc& Desc, *ppSBT = nullptr; } +void RenderDeviceGLImpl::CreateSuperResolution(const SuperResolutionDesc& Desc, + ISuperResolution** ppUpscaler) +{ + UNSUPPORTED("CreateSuperResolution is not supported in OpenGL"); + *ppUpscaler = nullptr; +} + +void RenderDeviceGLImpl::GetSuperResolutionSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, + SuperResolutionSourceSettings& Settings) const +{ + UNSUPPORTED("GetSuperResolutionSourceSettings is not supported in OpenGL"); + Settings = {}; +} + void RenderDeviceGLImpl::CreateDeviceMemory(const DeviceMemoryCreateInfo& CreateInfo, IDeviceMemory** ppMemory) { UNSUPPORTED("CreateDeviceMemory is not supported in OpenGL"); @@ -1132,7 +1150,7 @@ void RenderDeviceGLImpl::InitAdapterInfo() m_AdapterInfo.Queues[0].TextureCopyGranularity[2] = 1; } - ASSERT_SIZEOF(DeviceFeatures, 48, "Did you add a new feature to DeviceFeatures? Please handle its status here."); + ASSERT_SIZEOF(DeviceFeatures, 49, "Did you add a new feature to DeviceFeatures? Please handle its status here."); } void RenderDeviceGLImpl::FlagSupportedTexFormats() diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index 63086dd04..0788c6b72 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -291,6 +291,9 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBase Date: Wed, 4 Mar 2026 14:37:46 +0600 Subject: [PATCH 3/7] Add SuperResolution support to Archiver --- Graphics/Archiver/include/SerializationDeviceImpl.hpp | 3 +++ Graphics/Archiver/include/SerializationEngineImplTraits.hpp | 1 + 2 files changed, 4 insertions(+) diff --git a/Graphics/Archiver/include/SerializationDeviceImpl.hpp b/Graphics/Archiver/include/SerializationDeviceImpl.hpp index 568c7f753..325e5eebc 100644 --- a/Graphics/Archiver/include/SerializationDeviceImpl.hpp +++ b/Graphics/Archiver/include/SerializationDeviceImpl.hpp @@ -70,11 +70,14 @@ class SerializationDeviceImpl final : public RenderDeviceBase From 6f3da58b8a02d09e62b091a54495e90dfee53458 Mon Sep 17 00:00:00 2001 From: MikhailGorobets Date: Wed, 4 Mar 2026 14:37:52 +0600 Subject: [PATCH 4/7] Add SuperResolution .NET mapping --- Graphics/GraphicsEngine.NET/Mapping.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Graphics/GraphicsEngine.NET/Mapping.xml b/Graphics/GraphicsEngine.NET/Mapping.xml index b0d3b320b..ed9f57378 100644 --- a/Graphics/GraphicsEngine.NET/Mapping.xml +++ b/Graphics/GraphicsEngine.NET/Mapping.xml @@ -55,6 +55,7 @@ + @@ -249,6 +250,7 @@ + @@ -300,6 +302,10 @@ + + + + From e4ef02df63aa8601ee14e03e42032c2089d83b6d Mon Sep 17 00:00:00 2001 From: MikhailGorobets Date: Wed, 4 Mar 2026 14:37:57 +0600 Subject: [PATCH 5/7] Add SuperResolution tests --- .../src/CInterfaceTest.cpp | 10 +- .../src/SuperResolutionTest.cpp | 480 ++++++++++++++++++ .../src/c_interface/RenderDevice_C_Test.c | 54 +- .../src/c_interface/SuperResolution_C_Test.c | 83 +++ .../GraphicsEngine/SuperResolutionH_test.cpp | 27 + 5 files changed, 651 insertions(+), 3 deletions(-) create mode 100644 Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp create mode 100644 Tests/DiligentCoreAPITest/src/c_interface/SuperResolution_C_Test.c create mode 100644 Tests/IncludeTest/GraphicsEngine/SuperResolutionH_test.cpp diff --git a/Tests/DiligentCoreAPITest/src/CInterfaceTest.cpp b/Tests/DiligentCoreAPITest/src/CInterfaceTest.cpp index 56d74604e..ac0318ee6 100644 --- a/Tests/DiligentCoreAPITest/src/CInterfaceTest.cpp +++ b/Tests/DiligentCoreAPITest/src/CInterfaceTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 Diligent Graphics LLC + * Copyright 2019-2026 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,7 @@ extern "C" int TestRenderDeviceCInterface_CreateResourceMapping(void* pRenderDevice); int TestRenderDeviceCInterface_CreateFence(void* pRenderDevice); int TestRenderDeviceCInterface_CreateQuery(void* pRenderDevice); + int TestRenderDeviceCInterface_CreateSuperResolution(void* pRenderDevice); } using namespace Diligent; @@ -53,7 +54,6 @@ TEST(RenderDevice_CInterface, Misc) EXPECT_EQ(TestRenderDeviceCInterface_Misc(pDevice), 0); } - TEST(RenderDevice_CInterface, CreateBuffer) { auto* pDevice = GPUTestingEnvironment::GetInstance()->GetDevice(); @@ -96,4 +96,10 @@ TEST(RenderDevice_CInterface, CreateQuery) EXPECT_EQ(TestRenderDeviceCInterface_CreateQuery(pDevice), 0); } +TEST(RenderDevice_CInterface, CreateSuperResolution) +{ + auto* pDevice = GPUTestingEnvironment::GetInstance()->GetDevice(); + EXPECT_EQ(TestRenderDeviceCInterface_CreateSuperResolution(pDevice), 0); +} + } // namespace diff --git a/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp new file mode 100644 index 000000000..d5f0ba6ff --- /dev/null +++ b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp @@ -0,0 +1,480 @@ +/* + * 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 "gtest/gtest.h" + +using namespace Diligent; +using namespace Diligent::Testing; + +namespace +{ + +static const SuperResolutionInfo* FindUpscalerByType(const SuperResolutionProperties& SRProps, SUPER_RESOLUTION_UPSCALER_TYPE Type) +{ + for (Uint8 i = 0; i < SRProps.NumUpscalers; ++i) + { + if (SRProps.Upscalers[i].Type == Type) + return &SRProps.Upscalers[i]; + } + return nullptr; +} + +TEST(SuperResolutionTest, CheckProperties) +{ + auto* pEnv = GPUTestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + if (!pDevice->GetDeviceInfo().Features.SuperResolution) + { + GTEST_SKIP() << "Super resolution is not supported by this device"; + } + + const auto& SRProps = pDevice->GetAdapterInfo().SuperResolution; + EXPECT_GT(SRProps.NumUpscalers, static_cast(0)); + + for (Uint8 i = 0; i < SRProps.NumUpscalers; ++i) + { + EXPECT_NE(SRProps.Upscalers[i].Name[0], '\0') << "Upscaler " << i << " has empty name"; + EXPECT_NE(SRProps.Upscalers[i].VariantId, IID_Unknown) << "Upscaler " << i << " has unknown UID"; + } +} + +TEST(SuperResolutionTest, QuerySourceSettings) +{ + auto* pEnv = GPUTestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + if (!pDevice->GetDeviceInfo().Features.SuperResolution) + { + GTEST_SKIP() << "Super resolution is not supported by this device"; + } + + const auto& SRProps = pDevice->GetAdapterInfo().SuperResolution; + ASSERT_GT(SRProps.NumUpscalers, static_cast(0)); + + for (Uint8 i = 0; i < SRProps.NumUpscalers; ++i) + { + SuperResolutionSourceSettingsAttribs Attribs; + Attribs.VariantId = SRProps.Upscalers[i].VariantId; + Attribs.OutputWidth = 1920; + Attribs.OutputHeight = 1080; + Attribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + + SuperResolutionSourceSettings Settings; + pDevice->GetSuperResolutionSourceSettings(Attribs, Settings); + + EXPECT_GT(Settings.OptimalInputWidth, 0u) << "Upscaler " << SRProps.Upscalers[i].Name; + EXPECT_GT(Settings.OptimalInputHeight, 0u) << "Upscaler " << SRProps.Upscalers[i].Name; + EXPECT_LE(Settings.OptimalInputWidth, 1920u) << "Upscaler " << SRProps.Upscalers[i].Name; + EXPECT_LE(Settings.OptimalInputHeight, 1080u) << "Upscaler " << SRProps.Upscalers[i].Name; + } + + // Test all optimization types produce monotonically decreasing input resolution + // (enum is ordered from MAX_QUALITY=0 to MAX_PERFORMANCE) + { + const auto& Upscaler = SRProps.Upscalers[0]; + + Uint32 PrevWidth = 0; + for (int opt = static_cast(SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_QUALITY); + opt <= static_cast(SUPER_RESOLUTION_OPTIMIZATION_TYPE_MAX_PERFORMANCE); ++opt) + { + SuperResolutionSourceSettingsAttribs Attribs; + Attribs.VariantId = Upscaler.VariantId; + Attribs.OutputWidth = 1920; + Attribs.OutputHeight = 1080; + Attribs.OptimizationType = static_cast(opt); + + SuperResolutionSourceSettings Settings; + pDevice->GetSuperResolutionSourceSettings(Attribs, Settings); + + // First iteration: just record. Subsequent: input should decrease or stay same. + if (PrevWidth > 0) + EXPECT_LE(Settings.OptimalInputWidth, PrevWidth) << "OptimizationType " << opt; + PrevWidth = Settings.OptimalInputWidth; + } + } +} + +TEST(SuperResolutionTest, CreateSpatialUpscaler) +{ + auto* pEnv = GPUTestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + if (!pDevice->GetDeviceInfo().Features.SuperResolution) + { + GTEST_SKIP() << "Super resolution is not supported by this device"; + } + + const auto& SRProps = pDevice->GetAdapterInfo().SuperResolution; + const auto* pSpatialInfo = FindUpscalerByType(SRProps, SUPER_RESOLUTION_UPSCALER_TYPE_SPATIAL); + if (pSpatialInfo == nullptr) + { + GTEST_SKIP() << "Spatial super resolution is not supported by this device"; + } + + GPUTestingEnvironment::ScopedReset EnvironmentAutoReset; + + // Query optimal input resolution + SuperResolutionSourceSettingsAttribs QueryAttribs; + QueryAttribs.VariantId = pSpatialInfo->VariantId; + QueryAttribs.OutputWidth = 1920; + QueryAttribs.OutputHeight = 1080; + QueryAttribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + + SuperResolutionSourceSettings SourceSettings; + pDevice->GetSuperResolutionSourceSettings(QueryAttribs, SourceSettings); + ASSERT_GT(SourceSettings.OptimalInputWidth, 0u); + ASSERT_GT(SourceSettings.OptimalInputHeight, 0u); + + SuperResolutionDesc Desc; + Desc.Name = "Test Spatial Upscaler"; + Desc.VariantId = pSpatialInfo->VariantId; + Desc.OutputWidth = 1920; + Desc.OutputHeight = 1080; + Desc.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.InputWidth = SourceSettings.OptimalInputWidth; + Desc.InputHeight = SourceSettings.OptimalInputHeight; + + RefCntAutoPtr pUpscaler; + pDevice->CreateSuperResolution(Desc, &pUpscaler); + ASSERT_NE(pUpscaler, nullptr) << "Failed to create spatial super resolution upscaler"; + + const auto& RetDesc = pUpscaler->GetDesc(); + EXPECT_EQ(RetDesc.VariantId, pSpatialInfo->VariantId); + EXPECT_EQ(RetDesc.OutputWidth, 1920u); + EXPECT_EQ(RetDesc.OutputHeight, 1080u); + EXPECT_EQ(RetDesc.InputWidth, SourceSettings.OptimalInputWidth); + EXPECT_EQ(RetDesc.InputHeight, SourceSettings.OptimalInputHeight); + + // Spatial upscaler should return zero jitter + float JitterX = 1.0f, JitterY = 1.0f; + pUpscaler->GetOptimalJitterPattern(0, &JitterX, &JitterY); + EXPECT_EQ(JitterX, 0.0f); + EXPECT_EQ(JitterY, 0.0f); + + pUpscaler->GetOptimalJitterPattern(1, &JitterX, &JitterY); + EXPECT_EQ(JitterX, 0.0f); + EXPECT_EQ(JitterY, 0.0f); +} + +TEST(SuperResolutionTest, CreateTemporalUpscaler) +{ + auto* pEnv = GPUTestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + if (!pDevice->GetDeviceInfo().Features.SuperResolution) + { + GTEST_SKIP() << "Super resolution is not supported by this device"; + } + + const auto& SRProps = pDevice->GetAdapterInfo().SuperResolution; + const auto* pTemporalInfo = FindUpscalerByType(SRProps, SUPER_RESOLUTION_UPSCALER_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; + + SuperResolutionSourceSettings SourceSettings; + pDevice->GetSuperResolutionSourceSettings(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 = 1920; + Desc.OutputHeight = 1080; + Desc.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.DepthFormat = TEX_FORMAT_D32_FLOAT; + Desc.MotionFormat = TEX_FORMAT_RG16_FLOAT; + Desc.InputWidth = SourceSettings.OptimalInputWidth; + Desc.InputHeight = SourceSettings.OptimalInputHeight; + + RefCntAutoPtr pUpscaler; + pDevice->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->GetOptimalJitterPattern(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->GetOptimalJitterPattern(1, &JitterX, &JitterY); + EXPECT_TRUE(JitterX != PrevJitterX || JitterY != PrevJitterY); +} + +TEST(SuperResolutionTest, ExecuteSpatialUpscaler) +{ + auto* pEnv = GPUTestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + if (!pDevice->GetDeviceInfo().Features.SuperResolution) + { + GTEST_SKIP() << "Super resolution is not supported by this device"; + } + + const auto& SRProps = pDevice->GetAdapterInfo().SuperResolution; + const auto* pSpatialInfo = FindUpscalerByType(SRProps, SUPER_RESOLUTION_UPSCALER_TYPE_SPATIAL); + if (pSpatialInfo == nullptr) + { + GTEST_SKIP() << "Spatial super resolution is not supported by this device"; + } + + GPUTestingEnvironment::ScopedReset EnvironmentAutoReset; + + constexpr Uint32 OutputWidth = 256; + constexpr Uint32 OutputHeight = 256; + + // Query optimal input resolution + SuperResolutionSourceSettingsAttribs QueryAttribs; + QueryAttribs.VariantId = pSpatialInfo->VariantId; + QueryAttribs.OutputWidth = OutputWidth; + QueryAttribs.OutputHeight = OutputHeight; + QueryAttribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + + SuperResolutionSourceSettings SourceSettings; + pDevice->GetSuperResolutionSourceSettings(QueryAttribs, SourceSettings); + ASSERT_GT(SourceSettings.OptimalInputWidth, 0u); + ASSERT_GT(SourceSettings.OptimalInputHeight, 0u); + + // Create upscaler + SuperResolutionDesc UpscalerDesc; + UpscalerDesc.Name = "Test Spatial Execute Upscaler"; + UpscalerDesc.VariantId = pSpatialInfo->VariantId; + UpscalerDesc.OutputWidth = OutputWidth; + UpscalerDesc.OutputHeight = OutputHeight; + UpscalerDesc.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + UpscalerDesc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + UpscalerDesc.InputWidth = SourceSettings.OptimalInputWidth; + UpscalerDesc.InputHeight = SourceSettings.OptimalInputHeight; + + RefCntAutoPtr pUpscaler; + pDevice->CreateSuperResolution(UpscalerDesc, &pUpscaler); + ASSERT_NE(pUpscaler, nullptr); + + const Uint32 RenderWidth = SourceSettings.OptimalInputWidth; + const Uint32 RenderHeight = SourceSettings.OptimalInputHeight; + + // Create input color texture + TextureDesc ColorTexDesc; + ColorTexDesc.Name = "SR Color Input"; + ColorTexDesc.Type = RESOURCE_DIM_TEX_2D; + ColorTexDesc.Width = RenderWidth; + ColorTexDesc.Height = RenderHeight; + 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 output texture + TextureDesc OutputTexDesc; + OutputTexDesc.Name = "SR Output"; + OutputTexDesc.Type = RESOURCE_DIM_TEX_2D; + OutputTexDesc.Width = OutputWidth; + OutputTexDesc.Height = OutputHeight; + OutputTexDesc.Format = TEX_FORMAT_RGBA16_FLOAT; + OutputTexDesc.BindFlags = BIND_RENDER_TARGET | BIND_UNORDERED_ACCESS; + OutputTexDesc.Usage = USAGE_DEFAULT; + + RefCntAutoPtr pOutputTex; + pDevice->CreateTexture(OutputTexDesc, nullptr, &pOutputTex); + ASSERT_NE(pOutputTex, nullptr); + + // Execute spatial upscaling + auto* pContext = pEnv->GetDeviceContext(); + + ExecuteSuperResolutionAttribs Attribs; + Attribs.pColorTextureSRV = pColorTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pOutputTextureRTV = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); + + pContext->ExecuteSuperResolution(Attribs, pUpscaler); + pContext->Flush(); + pContext->WaitForIdle(); +} + +TEST(SuperResolutionTest, ExecuteTemporalUpscaler) +{ + auto* pEnv = GPUTestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + if (!pDevice->GetDeviceInfo().Features.SuperResolution) + { + GTEST_SKIP() << "Super resolution is not supported by this device"; + } + + const auto& SRProps = pDevice->GetAdapterInfo().SuperResolution; + const auto* pTemporalInfo = FindUpscalerByType(SRProps, SUPER_RESOLUTION_UPSCALER_TYPE_TEMPORAL); + if (pTemporalInfo == nullptr) + { + GTEST_SKIP() << "Temporal super resolution is not supported by this device"; + } + + GPUTestingEnvironment::ScopedReset EnvironmentAutoReset; + + constexpr Uint32 OutputWidth = 256; + constexpr Uint32 OutputHeight = 256; + + // Query optimal input resolution + SuperResolutionSourceSettingsAttribs QueryAttribs; + QueryAttribs.VariantId = pTemporalInfo->VariantId; + QueryAttribs.OutputWidth = OutputWidth; + QueryAttribs.OutputHeight = OutputHeight; + QueryAttribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + + SuperResolutionSourceSettings SourceSettings; + pDevice->GetSuperResolutionSourceSettings(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 = OutputWidth; + UpscalerDesc.OutputHeight = OutputHeight; + UpscalerDesc.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + UpscalerDesc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + UpscalerDesc.DepthFormat = TEX_FORMAT_D32_FLOAT; + UpscalerDesc.MotionFormat = TEX_FORMAT_RG16_FLOAT; + UpscalerDesc.InputWidth = SourceSettings.OptimalInputWidth; + UpscalerDesc.InputHeight = SourceSettings.OptimalInputHeight; + + RefCntAutoPtr pUpscaler; + pDevice->CreateSuperResolution(UpscalerDesc, &pUpscaler); + ASSERT_NE(pUpscaler, nullptr); + + const Uint32 RenderWidth = SourceSettings.OptimalInputWidth; + const Uint32 RenderHeight = SourceSettings.OptimalInputHeight; + + // Create input color texture + TextureDesc ColorTexDesc; + ColorTexDesc.Name = "SR Color Input"; + ColorTexDesc.Type = RESOURCE_DIM_TEX_2D; + ColorTexDesc.Width = RenderWidth; + ColorTexDesc.Height = RenderHeight; + 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 = RenderWidth; + DepthTexDesc.Height = RenderHeight; + 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 = RenderWidth; + MotionTexDesc.Height = RenderHeight; + 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 = OutputWidth; + OutputTexDesc.Height = OutputHeight; + OutputTexDesc.Format = TEX_FORMAT_RGBA16_FLOAT; + OutputTexDesc.BindFlags = BIND_RENDER_TARGET | 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.pColorTextureSRV = pColorTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pDepthTextureSRV = pDepthTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pMotionVectorsSRV = pMotionTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pOutputTextureRTV = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); + Attribs.JitterX = 0.5f; + Attribs.JitterY = -0.5f; + 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; + pContext->ExecuteSuperResolution(Attribs, pUpscaler); + + // Execute a second frame without reset + Attribs.JitterX = -0.25f; + Attribs.JitterY = 0.25f; + Attribs.ResetHistory = False; + pContext->ExecuteSuperResolution(Attribs, pUpscaler); + + pContext->Flush(); + pContext->WaitForIdle(); +} + +} // namespace diff --git a/Tests/DiligentCoreAPITest/src/c_interface/RenderDevice_C_Test.c b/Tests/DiligentCoreAPITest/src/c_interface/RenderDevice_C_Test.c index 57faf1b86..473d6aa56 100644 --- a/Tests/DiligentCoreAPITest/src/c_interface/RenderDevice_C_Test.c +++ b/Tests/DiligentCoreAPITest/src/c_interface/RenderDevice_C_Test.c @@ -26,8 +26,10 @@ */ #include +#include #include "RenderDevice.h" +#include "SuperResolution.h" int TestObjectCInterface(struct IObject* pObject); @@ -250,7 +252,6 @@ int TestRenderDeviceCInterface_CreateGraphicsPipelineState(struct IRenderDevice* return num_errors; } - int TestRenderDeviceCInterface_CreateFence(struct IRenderDevice* pRenderDevice) { struct FenceDesc fenceDesc; @@ -295,3 +296,54 @@ int TestRenderDeviceCInterface_CreateQuery(struct IRenderDevice* pRenderDevice) return num_errors; } + +int TestRenderDeviceCInterface_CreateSuperResolution(struct IRenderDevice* pRenderDevice) +{ + SuperResolutionDesc Desc; + struct ISuperResolution* pUpscaler = NULL; + struct RenderDeviceInfo DeviceInfo; + struct GraphicsAdapterInfo AdapterInfo; + + int num_errors = 0; + + DeviceInfo = *IRenderDevice_GetDeviceInfo(pRenderDevice); + AdapterInfo = *IRenderDevice_GetAdapterInfo(pRenderDevice); + if (DeviceInfo.Features.SuperResolution) + { + // Test GetSuperResolutionSourceSettings + SuperResolutionSourceSettingsAttribs QueryAttribs; + SuperResolutionSourceSettings SourceSettings; + + memset(&QueryAttribs, 0, sizeof(QueryAttribs)); + QueryAttribs.VariantId = AdapterInfo.SuperResolution.Upscalers[0].VariantId; + QueryAttribs.OutputWidth = 1920; + QueryAttribs.OutputHeight = 1080; + QueryAttribs.OptimizationType = SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED; + + memset(&SourceSettings, 0, sizeof(SourceSettings)); + IRenderDevice_GetSuperResolutionSourceSettings(pRenderDevice, &QueryAttribs, &SourceSettings); + if (SourceSettings.OptimalInputWidth == 0) + ++num_errors; + if (SourceSettings.OptimalInputHeight == 0) + ++num_errors; + + // Test CreateSuperResolution + memset(&Desc, 0, sizeof(Desc)); + Desc._DeviceObjectAttribs.Name = "Test SuperResolution Upscaler"; + Desc.VariantId = AdapterInfo.SuperResolution.Upscalers[0].VariantId; + Desc.OutputWidth = 1920; + Desc.OutputHeight = 1080; + Desc.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; + Desc.InputWidth = SourceSettings.OptimalInputWidth; + Desc.InputHeight = SourceSettings.OptimalInputHeight; + + IRenderDevice_CreateSuperResolution(pRenderDevice, &Desc, &pUpscaler); + if (pUpscaler != NULL) + IObject_Release(pUpscaler); + else + ++num_errors; + } + + return num_errors; +} 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 000000000..141a094cf --- /dev/null +++ b/Tests/DiligentCoreAPITest/src/c_interface/SuperResolution_C_Test.c @@ -0,0 +1,83 @@ +/* + * 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" + +int TestObjectCInterface(struct IObject* pObject); +int TestDeviceObjectCInterface(struct IDeviceObject* pDeviceObject); + +int TestSuperResolutionCInterface(struct ISuperResolution* pUpscaler) +{ + IObject* pUnknown = NULL; + ReferenceCounterValueType RefCnt1 = 0, RefCnt2 = 0; + + DeviceObjectAttribs Desc; + Int32 UniqueId = 0; + const SuperResolutionDesc* pUpscalerDesc = NULL; + float JitterX = 0.0f; + float JitterY = 0.0f; + + int num_errors = + TestObjectCInterface((struct IObject*)pUpscaler) + + TestDeviceObjectCInterface((struct IDeviceObject*)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; + + Desc = *IDeviceObject_GetDesc(pUpscaler); + if (Desc.Name == NULL) + ++num_errors; + + UniqueId = IDeviceObject_GetUniqueID(pUpscaler); + if (UniqueId == 0) + ++num_errors; + + pUpscalerDesc = ISuperResolution_GetDesc(pUpscaler); + if (pUpscalerDesc == NULL) + ++num_errors; + if (pUpscalerDesc->InputWidth == 0) + ++num_errors; + if (pUpscalerDesc->InputHeight == 0) + ++num_errors; + + ISuperResolution_GetOptimalJitterPattern(pUpscaler, 0, &JitterX, &JitterY); + (void)JitterX; + (void)JitterY; + + return num_errors; +} diff --git a/Tests/IncludeTest/GraphicsEngine/SuperResolutionH_test.cpp b/Tests/IncludeTest/GraphicsEngine/SuperResolutionH_test.cpp new file mode 100644 index 000000000..5788fb94b --- /dev/null +++ b/Tests/IncludeTest/GraphicsEngine/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/GraphicsEngine/interface/SuperResolution.h" From c03c96d9fca744663ab3b66332d6c857d15400ee Mon Sep 17 00:00:00 2001 From: MikhailGorobets Date: Wed, 5 Mar 2025 14:26:37 +0600 Subject: [PATCH 6/7] Update SuperResolution API --- .../GraphicsEngine/interface/GraphicsTypes.h | 20 +++++++++++++- .../interface/SuperResolution.h | 26 ++++++++++++++----- .../src/SuperResolutionTest.cpp | 4 +-- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 41eeb0074..cb97c2356 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -3347,10 +3347,28 @@ DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_TEMPORAL_CAP_FLAGS, Uint32) DEFINE_FLAG_ENUM_OPERATORS(SUPER_RESOLUTION_TEMPORAL_CAP_FLAGS) +/// Super resolution creation flags. +DILIGENT_TYPED_ENUM(SUPER_RESOLUTION_CREATE_FLAGS, Uint32) +{ + SUPER_RESOLUTION_CREATE_FLAG_NONE = 0u, + + /// When set, the upscaler automatically calculates exposure for each frame. + /// The exposure texture in ExecuteSuperResolutionAttribs is ignored. + SUPER_RESOLUTION_CREATE_FLAG_AUTO_EXPOSURE = 1u << 0, + + /// When set, enables the sharpening pass in the upscaler. + /// The Sharpness field in ExecuteSuperResolutionAttribs controls the amount. + SUPER_RESOLUTION_CREATE_FLAG_ENABLE_SHARPENING = 1u << 1, + + SUPER_RESOLUTION_CREATE_FLAG_LAST = SUPER_RESOLUTION_CREATE_FLAG_ENABLE_SHARPENING +}; +DEFINE_FLAG_ENUM_OPERATORS(SUPER_RESOLUTION_CREATE_FLAGS) + + /// Information about a supported super resolution upscaler variant struct SuperResolutionInfo { - /// Human-readable name of the upscaler variant (e.g. "MetalFX Spatial", "MetalFX Temporal"). + /// 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. diff --git a/Graphics/GraphicsEngine/interface/SuperResolution.h b/Graphics/GraphicsEngine/interface/SuperResolution.h index 4bfae91a2..3c504a024 100644 --- a/Graphics/GraphicsEngine/interface/SuperResolution.h +++ b/Graphics/GraphicsEngine/interface/SuperResolution.h @@ -89,10 +89,14 @@ struct SuperResolutionDesc DILIGENT_DERIVE(DeviceObjectAttribs) /// Unlike the reactive mask which provides proportional control, this is a binary decision. TEXTURE_FORMAT IgnoreHistoryMaskFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); - /// When True, the upscaler automatically calculates exposure for each frame. - /// When auto exposure is enabled, the exposure texture in - /// ExecuteSuperResolutionAttribs is ignored. - Bool AutoExposureEnabled DEFAULT_INITIALIZER(True); + /// 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_CREATE_FLAGS. + SUPER_RESOLUTION_CREATE_FLAGS Flags DEFAULT_INITIALIZER(SUPER_RESOLUTION_CREATE_FLAG_NONE); }; typedef struct SuperResolutionDesc SuperResolutionDesc; @@ -112,6 +116,16 @@ struct SuperResolutionSourceSettingsAttribs /// 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); + + /// Engine creation flags controlling the super resolution upscaler 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_CREATE_FLAGS Flags DEFAULT_INITIALIZER(SUPER_RESOLUTION_CREATE_FLAG_NONE); + /// Optimization type controlling the quality/performance trade-off. SUPER_RESOLUTION_OPTIMIZATION_TYPE OptimizationType DEFAULT_INITIALIZER(SUPER_RESOLUTION_OPTIMIZATION_TYPE_BALANCED); }; @@ -150,12 +164,12 @@ struct ExecuteSuperResolutionAttribs /// Output (upscaled) texture (unordered access view or render target view). /// Must match SuperResolutionDesc::OutputWidth x OutputHeight. - ITextureView* pOutputTextureRTV DEFAULT_INITIALIZER(nullptr); + 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::AutoExposureEnabled is True. + /// Ignored when SuperResolutionDesc::Flags includes SUPER_RESOLUTION_CREATE_FLAG_AUTO_EXPOSURE. ITextureView* pExposureTextureSRV DEFAULT_INITIALIZER(nullptr); /// Reactive mask texture (shader resource view). diff --git a/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp index d5f0ba6ff..8b592148a 100644 --- a/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp +++ b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp @@ -329,7 +329,7 @@ TEST(SuperResolutionTest, ExecuteSpatialUpscaler) ExecuteSuperResolutionAttribs Attribs; Attribs.pColorTextureSRV = pColorTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); - Attribs.pOutputTextureRTV = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); + Attribs.pOutputTextureView = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); pContext->ExecuteSuperResolution(Attribs, pUpscaler); pContext->Flush(); @@ -452,7 +452,7 @@ TEST(SuperResolutionTest, ExecuteTemporalUpscaler) 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.pOutputTextureRTV = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); + Attribs.pOutputTextureView = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); Attribs.JitterX = 0.5f; Attribs.JitterY = -0.5f; Attribs.MotionVectorScaleX = 1.0f; From d9ee786397a2f5c2217b960a3fee1247bc5c3428 Mon Sep 17 00:00:00 2001 From: MikhailGorobets Date: Fri, 6 Mar 2026 17:59:09 +0600 Subject: [PATCH 7/7] D3D12: Implement ISuperResolution using DirectSR --- Graphics/Archiver/CMakeLists.txt | 2 +- Graphics/GraphicsEngineD3D12/CMakeLists.txt | 15 +- .../include/D3D12Loader.hpp | 9 +- .../include/D3D12TypeConversions.hpp | 2 + .../include/RenderDeviceD3D12Impl.hpp | 6 + .../include/SuperResolutionD3D12Impl.hpp | 70 +++++ Graphics/GraphicsEngineD3D12/include/pch.h | 1 + .../GraphicsEngineD3D12/src/D3D12Loader.cpp | 49 ++-- .../src/D3D12TypeConversions.cpp | 12 + .../src/DeviceContextD3D12Impl.cpp | 14 +- .../src/EngineFactoryD3D12.cpp | 92 ++++++- .../src/RenderDeviceD3D12Impl.cpp | 102 ++++++- .../src/SuperResolutionD3D12Impl.cpp | 257 ++++++++++++++++++ .../src/SuperResolutionTest.cpp | 8 +- 14 files changed, 586 insertions(+), 53 deletions(-) create mode 100644 Graphics/GraphicsEngineD3D12/include/SuperResolutionD3D12Impl.hpp create mode 100644 Graphics/GraphicsEngineD3D12/src/SuperResolutionD3D12Impl.cpp diff --git a/Graphics/Archiver/CMakeLists.txt b/Graphics/Archiver/CMakeLists.txt index 4e20f8de5..b623ac611 100644 --- a/Graphics/Archiver/CMakeLists.txt +++ b/Graphics/Archiver/CMakeLists.txt @@ -118,7 +118,7 @@ if(D3D11_SUPPORTED) endif() if(D3D12_SUPPORTED) - target_link_libraries(Diligent-Archiver-static PRIVATE Diligent-GraphicsEngineD3D12-static) + target_link_libraries(Diligent-Archiver-static PRIVATE Diligent-GraphicsEngineD3D12-static DirectSR-Headers) target_include_directories(Diligent-Archiver-static PRIVATE ../GraphicsEngineD3D12/include) endif() diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt index 61e812cbb..9521b2b30 100644 --- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt @@ -2,6 +2,16 @@ cmake_minimum_required (VERSION 3.11) project(Diligent-GraphicsEngineD3D12 CXX) +include(../../BuildTools/CMake/BuildUtils.cmake) + +# Fetch DirectSR headers and Agility SDK DLLs +FetchContent_DeclareShallowGit(DirectSR-Headers + GIT_REPOSITORY https://github.com/MikhailGorobets/DirectSR-Headers.git + GIT_TAG dev +) +FetchContent_MakeAvailable(DirectSR-Headers) + + set(INCLUDE include/BottomLevelASD3D12Impl.hpp include/BufferD3D12Impl.hpp @@ -44,6 +54,7 @@ set(INCLUDE include/ShaderResourceCacheD3D12.hpp include/ShaderResourcesD3D12.hpp include/ShaderVariableManagerD3D12.hpp + include/SuperResolutionD3D12Impl.hpp include/SwapChainD3D12Impl.hpp include/TextureD3D12Impl.hpp include/TextureViewD3D12Impl.hpp @@ -108,6 +119,7 @@ set(SRC src/ShaderResourceCacheD3D12.cpp src/ShaderResourcesD3D12.cpp src/ShaderVariableManagerD3D12.cpp + src/SuperResolutionD3D12Impl.cpp src/SwapChainD3D12Impl.cpp src/TextureD3D12Impl.cpp src/TextureViewD3D12Impl.cpp @@ -119,7 +131,7 @@ set(DLL_SRC src/GraphicsEngineD3D12.def ) -if(PLATFORM_WIN32) +if(PLATFORM_WIN32 OR PLATFORM_UNIVERSAL_WINDOWS) list(APPEND INCLUDE include/D3D12Loader.hpp) list(APPEND SRC src/D3D12Loader.cpp) set(USE_D3D12_LOADER 1) @@ -194,6 +206,7 @@ PRIVATE Diligent-GraphicsEngineNextGenBase Diligent-TargetPlatform Diligent-ShaderTools + DirectSR-Headers dxgi.lib d3dcompiler.lib PUBLIC diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12Loader.hpp b/Graphics/GraphicsEngineD3D12/include/D3D12Loader.hpp index 7702cf50c..e743636fd 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12Loader.hpp +++ b/Graphics/GraphicsEngineD3D12/include/D3D12Loader.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 Diligent Graphics LLC + * Copyright 2019-2026 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ #include + namespace Diligent { @@ -48,9 +49,15 @@ using D3D12SerializeRootSignatureProcType = HRESULT(WINAPI*)( _Out_ ID3DBlob** ppBlob, _Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorBlob); +using D3D12GetInterfaceProcType = HRESULT(WINAPI*)( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _COM_Outptr_opt_ void** ppvDebug); + extern D3D12CreateDeviceProcType D3D12CreateDevice; extern D3D12GetDebugInterfaceProcType D3D12GetDebugInterface; extern D3D12SerializeRootSignatureProcType D3D12SerializeRootSignature; +extern D3D12GetInterfaceProcType D3D12GetInterface; HMODULE LoadD3D12Dll(const char* DLLPath = "d3d12.dll"); diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp index 19f06e9f7..954464491 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp +++ b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp @@ -114,6 +114,8 @@ D3D12_COMMAND_LIST_TYPE QueueIdToD3D12CommandListType(HardwareQueueIndex Qu COMMAND_QUEUE_TYPE D3D12CommandListTypeToCmdQueueType(D3D12_COMMAND_LIST_TYPE ListType); D3D12_COMMAND_QUEUE_PRIORITY QueuePriorityToD3D12QueuePriority(QUEUE_PRIORITY Priority); +DSR_SUPERRES_CREATE_ENGINE_FLAGS SuperResolutionCreateFlagsToDSRFlags(SUPER_RESOLUTION_CREATE_FLAGS Flags); + static constexpr HardwareQueueIndex D3D12HWQueueIndex_Graphics{Uint8{0}}; static constexpr HardwareQueueIndex D3D12HWQueueIndex_Compute{Uint8{1}}; static constexpr HardwareQueueIndex D3D12HWQueueIndex_Copy{Uint8{2}}; diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index f9cd48a6d..b850f63f8 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -47,6 +47,8 @@ #include "DXCompiler.hpp" #include "RootSignature.hpp" +#include + // The macros below are only defined in Win SDK 19041+ and are missing in 17763 #ifndef D3D12_RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS @@ -223,6 +225,8 @@ class RenderDeviceD3D12Impl final : public RenderDeviceNextGenBase m_pDSRDevice; + #ifdef DILIGENT_DEVELOPMENT Uint32 m_MaxD3D12DeviceVersion = 0; #endif diff --git a/Graphics/GraphicsEngineD3D12/include/SuperResolutionD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/SuperResolutionD3D12Impl.hpp new file mode 100644 index 000000000..4dd82baaa --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/SuperResolutionD3D12Impl.hpp @@ -0,0 +1,70 @@ +/* + * 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 +/// Declaration of Diligent::SuperResolutionD3D12Impl class + +#include "EngineD3D12ImplTraits.hpp" +#include "DeviceObjectBase.hpp" +#include "SuperResolution.h" + +#include + + +namespace Diligent +{ + +class DeviceContextD3D12Impl; + +/// Implementation of the ISuperResolution interface for Direct3D12 backend using DirectSR. +class SuperResolutionD3D12Impl final : public DeviceObjectBase +{ +public: + using TSRUpscalerBase = DeviceObjectBase; + + SuperResolutionD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const SuperResolutionDesc& Desc); + + ~SuperResolutionD3D12Impl(); + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_SuperResolution, TSRUpscalerBase) + + /// Implementation of ISuperResolution::GetOptimalJitterPattern(). + virtual void DILIGENT_CALL_TYPE GetOptimalJitterPattern(Uint32 Index, float* pJitterX, float* pJitterY) const override final; + + /// Encodes the upscaling operation. + void Execute(DeviceContextD3D12Impl& Ctx, const ExecuteSuperResolutionAttribs& Attribs); + +private: + CComPtr m_pDSREngine; + std::vector> m_DSRUpscalers; + std::vector m_JitterPattern; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/pch.h b/Graphics/GraphicsEngineD3D12/include/pch.h index 2167680c3..625190980 100644 --- a/Graphics/GraphicsEngineD3D12/include/pch.h +++ b/Graphics/GraphicsEngineD3D12/include/pch.h @@ -34,6 +34,7 @@ #include "WinHPreface.h" #include +#include #include #if USE_D3D12_LOADER diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12Loader.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12Loader.cpp index 527c5f8e6..da8a3310e 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12Loader.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12Loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 Diligent Graphics LLC + * Copyright 2019-2026 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,43 +39,42 @@ namespace Diligent D3D12CreateDeviceProcType D3D12CreateDevice; D3D12GetDebugInterfaceProcType D3D12GetDebugInterface; D3D12SerializeRootSignatureProcType D3D12SerializeRootSignature; +D3D12GetInterfaceProcType D3D12GetInterface; + +#if PLATFORM_WIN32 +# define LOAD_D3D12_ENTRY_POINT(hModule, Func) \ + Func = reinterpret_cast(GetProcAddress(hModule, #Func)) +#elif PLATFORM_UNIVERSAL_WINDOWS +# define LOAD_D3D12_ENTRY_POINT(hModule, Func) Func = ::Func +#else +# error Unexpected platform +#endif HMODULE LoadD3D12Dll(const char* DLLPath) { #if PLATFORM_WIN32 HMODULE hModule = LoadLibraryA(DLLPath); - if (hModule == NULL) - { return NULL; - } - - bool bAllEntriesLoaded = true; -# define LOAD_D3D12_ENTRY_POINT(Func) \ - do \ - { \ - Func = (Func##ProcType)GetProcAddress(hModule, #Func); \ - if (Func == NULL) \ - { \ - bAllEntriesLoaded = false; \ - LOG_ERROR_MESSAGE("Failed to loader '" #Func "' function from '", DLLPath, "' dll"); \ - } \ - } while (false) -#elif PLATFORM_UNIVERSAL_WINDOWS - HMODULE hModule = (HMODULE)-1; -# define LOAD_D3D12_ENTRY_POINT(Func) Func = ::Func #else -# error Unexpected platform + HMODULE hModule = (HMODULE)-1; #endif - LOAD_D3D12_ENTRY_POINT(D3D12CreateDevice); - LOAD_D3D12_ENTRY_POINT(D3D12GetDebugInterface); - LOAD_D3D12_ENTRY_POINT(D3D12SerializeRootSignature); -#undef LOAD_D3D12_ENTRY_POINT + LOAD_D3D12_ENTRY_POINT(hModule, D3D12CreateDevice); + LOAD_D3D12_ENTRY_POINT(hModule, D3D12GetDebugInterface); + LOAD_D3D12_ENTRY_POINT(hModule, D3D12SerializeRootSignature); + + // D3D12GetInterface is optional (available in newer SDK versions, required for DirectSR). + // On Win32 it may be nullptr on older SDKs; on UWP it is not available in d3d12.lib. + // All call sites handle nullptr gracefully (DirectSR features are disabled at runtime). +#if PLATFORM_WIN32 + LOAD_D3D12_ENTRY_POINT(hModule, D3D12GetInterface); +#endif #if PLATFORM_WIN32 - if (!bAllEntriesLoaded) + if (!D3D12CreateDevice || !D3D12GetDebugInterface || !D3D12SerializeRootSignature) { + LOG_ERROR_MESSAGE("Failed to load one or more entry points from '", DLLPath, "' dll"); FreeLibrary(hModule); return NULL; } diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp index fd5da92f3..4e4384996 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp @@ -1019,4 +1019,16 @@ D3D12_SHADING_RATE_COMBINER ShadingRateCombinerToD3D12ShadingRateCombiner(SHADIN #endif } +DSR_SUPERRES_CREATE_ENGINE_FLAGS SuperResolutionCreateFlagsToDSRFlags(SUPER_RESOLUTION_CREATE_FLAGS Flags) +{ + DSR_SUPERRES_CREATE_ENGINE_FLAGS DSRFlags = DSR_SUPERRES_CREATE_ENGINE_FLAG_NONE; + + if (Flags & SUPER_RESOLUTION_CREATE_FLAG_AUTO_EXPOSURE) + DSRFlags |= DSR_SUPERRES_CREATE_ENGINE_FLAG_AUTO_EXPOSURE; + if (Flags & SUPER_RESOLUTION_CREATE_FLAG_ENABLE_SHARPENING) + DSRFlags |= DSR_SUPERRES_CREATE_ENGINE_FLAG_ENABLE_SHARPENING; + + return DSRFlags; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 3529e50a0..972328eba 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -48,6 +48,7 @@ #include "d3dx12_win.h" #include "D3D12DynamicHeap.hpp" #include "QueryManagerD3D12.hpp" +#include "SuperResolutionD3D12Impl.hpp" #include "DXGITypeConversions.hpp" #include "D3D12TileMappingHelper.hpp" @@ -3351,7 +3352,18 @@ void DeviceContextD3D12Impl::BindSparseResourceMemory(const BindSparseResourceMe void DeviceContextD3D12Impl::ExecuteSuperResolution(const ExecuteSuperResolutionAttribs& Attribs, ISuperResolution* pUpscaler) { - UNSUPPORTED("ExecuteSuperResolution is not supported in DirectX 12"); + DEV_CHECK_ERR(pUpscaler != nullptr, "pUpscaler must not be null"); + + auto* pUpscalerD3D12 = ClassPtrCast(pUpscaler); + + // DirectSR submits its own command list(s) to the command queue + // We must flush the current command list first so that all rendering work producing the input resources (color, depth, motion vectors) is submitted to the GPU before DirectSR reads them. + TransitionOrVerifyTextureState(GetCmdContext(), *ClassPtrCast(Attribs.pOutputTextureView->GetTexture()), RESOURCE_STATE_TRANSITION_MODE_TRANSITION, RESOURCE_STATE_UNORDERED_ACCESS, "OutputTexture before DirectSR"); + + Flush(); + pUpscalerD3D12->Execute(*this, Attribs); + + TransitionOrVerifyTextureState(GetCmdContext(), *ClassPtrCast(Attribs.pOutputTextureView->GetTexture()), RESOURCE_STATE_TRANSITION_MODE_TRANSITION, RESOURCE_STATE_SHADER_RESOURCE, "OutputTexture after DirectSR"); } } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp index f5049991b..9976e929b 100644 --- a/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp @@ -135,6 +135,14 @@ class EngineFactoryD3D12Impl : public EngineFactoryD3DBase> CmdQueueD3D12Refs; CComPtr d3d12Device; std::vector CmdQueues; + GraphicsAdapterInfo AdapterInfo; try { ValidateD3D12CreateInfo(EngineCI); @@ -469,11 +478,9 @@ void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12Creat //d3d12Device->SetStablePowerState(TRUE); #endif - { - CComPtr pDXGIAdapter1 = DXGIAdapterFromD3D12Device(d3d12Device); - const GraphicsAdapterInfo AdapterInfo = GetGraphicsAdapterInfo(d3d12Device, pDXGIAdapter1); - VerifyEngineCreateInfo(EngineCI, AdapterInfo); - } + CComPtr pDXGIAdapter1 = DXGIAdapterFromD3D12Device(d3d12Device); + AdapterInfo = GetGraphicsAdapterInfo(d3d12Device, pDXGIAdapter1); + VerifyEngineCreateInfo(EngineCI, AdapterInfo); // Describe and create the command queue. const auto CreateQueue = [&](const ImmediateContextCreateInfo& ContextCI) // @@ -515,7 +522,7 @@ void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12Creat return; } - AttachToD3D12Device(d3d12Device, static_cast(CmdQueues.size()), CmdQueues.data(), EngineCI, ppDevice, ppContexts); + AttachToD3D12Device(d3d12Device, static_cast(CmdQueues.size()), CmdQueues.data(), EngineCI, AdapterInfo, ppDevice, ppContexts); } @@ -567,6 +574,24 @@ void EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd if (!pd3d12NativeDevice || !ppCommandQueues || !ppDevice || !ppContexts) return; + ID3D12Device* d3d12Device = reinterpret_cast(pd3d12NativeDevice); + CComPtr pDXGIAdapter1 = DXGIAdapterFromD3D12Device(d3d12Device); + + ValidateD3D12CreateInfo(EngineCI); + + const GraphicsAdapterInfo AdapterInfo = GetGraphicsAdapterInfo(pd3d12NativeDevice, pDXGIAdapter1); + + AttachToD3D12Device(d3d12Device, CommandQueueCount, ppCommandQueues, EngineCI, AdapterInfo, ppDevice, ppContexts); +} + +void EngineFactoryD3D12Impl::AttachToD3D12Device(ID3D12Device* d3d12Device, + Uint32 CommandQueueCount, + ICommandQueueD3D12** ppCommandQueues, + const EngineD3D12CreateInfo& EngineCI, + const GraphicsAdapterInfo& AdapterInfo, + IRenderDevice** ppDevice, + IDeviceContext** ppContexts) +{ ImmediateContextCreateInfo DefaultImmediateCtxCI; const Uint32 NumImmediateContexts = EngineCI.NumImmediateContexts > 0 ? EngineCI.NumImmediateContexts : 1; @@ -598,16 +623,11 @@ void EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd } } + VerifyEngineCreateInfo(EngineCI, AdapterInfo); + try { - IMemoryAllocator& RawMemAllocator = GetRawAllocator(); - ID3D12Device* d3d12Device = reinterpret_cast(pd3d12NativeDevice); - CComPtr pDXGIAdapter1 = DXGIAdapterFromD3D12Device(d3d12Device); - - ValidateD3D12CreateInfo(EngineCI); - - const GraphicsAdapterInfo AdapterInfo = GetGraphicsAdapterInfo(pd3d12NativeDevice, pDXGIAdapter1); - VerifyEngineCreateInfo(EngineCI, AdapterInfo); + IMemoryAllocator& RawMemAllocator = GetRawAllocator(); RenderDeviceD3D12Impl* pRenderDeviceD3D12{ NEW_RC_OBJ(RawMemAllocator, "RenderDeviceD3D12Impl instance", RenderDeviceD3D12Impl)(RawMemAllocator, this, EngineCI, AdapterInfo, d3d12Device, CommandQueueCount, ppCommandQueues)}; @@ -1106,6 +1126,50 @@ GraphicsAdapterInfo EngineFactoryD3D12Impl::GetGraphicsAdapterInfo(void* ASSERT_SIZEOF(DrawCommandProps, 12, "Did you add a new member to DrawCommandProperties? Please initialize it here."); } + CComPtr pDSRFactory; + if (HRESULT hr = D3D12GetInterface(CLSID_D3D12DSRDeviceFactory, IID_PPV_ARGS(&pDSRFactory)); SUCCEEDED(hr)) + { + CComPtr pDSRDevice; + if (hr = pDSRFactory->CreateDSRDevice(d3d12Device, 0, IID_PPV_ARGS(&pDSRDevice)); SUCCEEDED(hr)) + { + if (const Uint32 NumVariants = pDSRDevice->GetNumSuperResVariants(); NumVariants > 0) + { + AdapterInfo.Features.SuperResolution = DEVICE_FEATURE_STATE_ENABLED; + + SuperResolutionProperties& SRProps = AdapterInfo.SuperResolution; + + for (Uint32 Idx = 0; Idx < NumVariants && SRProps.NumUpscalers < DILIGENT_MAX_SUPER_RESOLUTION_UPSCALERS; ++Idx) + { + static_assert(sizeof(SuperResolutionInfo::VariantId) == sizeof(DSR_SUPERRES_VARIANT_DESC::VariantId), "GUID/INTERFACE_ID size mismatch"); + + DSR_SUPERRES_VARIANT_DESC VariantDesc = {}; + if (hr = pDSRDevice->GetSuperResVariantDesc(Idx, &VariantDesc); FAILED(hr)) + continue; + + SuperResolutionInfo& Info = SRProps.Upscalers[SRProps.NumUpscalers]; + Info.Type = SUPER_RESOLUTION_UPSCALER_TYPE_TEMPORAL; + 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; + + strncpy_s(Info.Name, sizeof(Info.Name), VariantDesc.VariantName, _TRUNCATE); + memcpy(&Info.VariantId, &VariantDesc.VariantId, sizeof(Info.VariantId)); + + SRProps.NumUpscalers++; + } + } + } + } + else + { + LOG_WARNING_MESSAGE("ID3D12DSRDeviceFactory is not available. Super resolution features will be disabled."); + } + ASSERT_SIZEOF(DeviceFeatures, 49, "Did you add a new feature to DeviceFeatures? Please handle its status here."); return AdapterInfo; diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 407231bab..276a52eb2 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -57,14 +57,13 @@ #include "D3D12TypeConversions.hpp" #include "DXGITypeConversions.hpp" #include "QueryManagerD3D12.hpp" +#include "D3D12Loader.hpp" +#include "SuperResolutionD3D12Impl.hpp" namespace Diligent { -class SuperResolutionD3D12Impl -{}; - namespace { @@ -124,6 +123,31 @@ CComPtr CreateDummyNVApiHeap(ID3D12Device* pd3d12Device) return pNVApiHeap; } +CComPtr CreateDSRDevice(ID3D12Device* pd3d12Device) +{ + if (D3D12GetInterface == nullptr) + return nullptr; + + CComPtr pDSRFactory; + + if (HRESULT hr = D3D12GetInterface(CLSID_D3D12DSRDeviceFactory, IID_PPV_ARGS(&pDSRFactory)); FAILED(hr)) + { + LOG_WARNING_MESSAGE("Failed to create DirectSR device factory. HRESULT: ", hr); + return nullptr; + } + + 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 nullptr; + } + + LOG_INFO_MESSAGE("DirectSR device initialized successfully. ", pDSRDevice->GetNumSuperResVariants(), " upscaler variant(s) found."); + + return pDSRDevice; +} + } // namespace RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCounters, @@ -280,6 +304,8 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo } } + m_pDSRDevice = CreateDSRDevice(m_pd3d12Device); + InitShaderCompilationThreadPool(EngineCI.pAsyncShaderCompilationThreadPool, EngineCI.NumAsyncShaderCompilationThreads); } catch (...) @@ -682,15 +708,79 @@ void RenderDeviceD3D12Impl::CreateSBT(const ShaderBindingTableDesc& Desc, void RenderDeviceD3D12Impl::CreateSuperResolution(const SuperResolutionDesc& Desc, ISuperResolution** ppUpscaler) { - UNSUPPORTED("CreateSuperResolution is not supported in DirectX 12"); - *ppUpscaler = nullptr; + if (m_pDSRDevice) + { + CreateSuperResolutionImpl(ppUpscaler, Desc); + } + else + { + LOG_ERROR_MESSAGE("DirectSR device is not initialized. CreateSuperResolution will return nullptr."); + *ppUpscaler = nullptr; + } } void RenderDeviceD3D12Impl::GetSuperResolutionSourceSettings(const SuperResolutionSourceSettingsAttribs& Attribs, SuperResolutionSourceSettings& Settings) const { - UNSUPPORTED("GetSuperResolutionSourceSettings is not supported in DirectX 12"); Settings = {}; + + if (!m_pDSRDevice) + { + LOG_ERROR_MESSAGE("DirectSR device is not initialized"); + return; + } + + DEV_CHECK_ERR(Attribs.OutputWidth > 0 && Attribs.OutputHeight > 0, "Output resolution must be greater than zero"); + DEV_CHECK_ERR(Attribs.OptimizationType < SUPER_RESOLUTION_OPTIMIZATION_TYPE_COUNT, "Invalid optimization type"); + + 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_SOURCE_SETTINGS SourceSettings = {}; + + const DSR_SUPERRES_CREATE_ENGINE_FLAGS DSRCreateFlags = SuperResolutionCreateFlagsToDSRFlags(Attribs.Flags); + + if (HRESULT Result = m_pDSRDevice->QuerySuperResSourceSettings(VariantIndex, TargetSize, TexFormatToDXGI_Format(Attribs.OutputFormat), DSROptType, DSRCreateFlags, &SourceSettings); SUCCEEDED(Result)) + { + Settings.OptimalInputWidth = SourceSettings.OptimalSize.Width; + Settings.OptimalInputHeight = SourceSettings.OptimalSize.Height; + } + else + { + LOG_WARNING_MESSAGE("DirectSR QuerySuperResSourceSettings failed. HRESULT: ", Result); + } } void RenderDeviceD3D12Impl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, diff --git a/Graphics/GraphicsEngineD3D12/src/SuperResolutionD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/SuperResolutionD3D12Impl.cpp new file mode 100644 index 000000000..5b41d4326 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/SuperResolutionD3D12Impl.cpp @@ -0,0 +1,257 @@ +/* + * 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 "pch.h" + +#include "SuperResolutionD3D12Impl.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "DeviceContextD3D12Impl.hpp" +#include "TextureD3D12Impl.hpp" +#include "TextureViewD3D12Impl.hpp" +#include "DXGITypeConversions.hpp" +#include "D3D12TypeConversions.hpp" +#include "GraphicsAccessories.hpp" +#include "DebugUtilities.hpp" + +namespace Diligent +{ + +SuperResolutionD3D12Impl::SuperResolutionD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const SuperResolutionDesc& Desc) : + TSRUpscalerBase{pRefCounters, pDevice, Desc}, + m_DSRUpscalers(pDevice->GetCommandQueueCount()) +{ + DEV_CHECK_ERR(Desc.OutputWidth > 0 && Desc.OutputHeight > 0, "Output resolution must be greater than zero"); + DEV_CHECK_ERR(Desc.OutputFormat != TEX_FORMAT_UNKNOWN, "OutputFormat must not be TEX_FORMAT_UNKNOWN"); + DEV_CHECK_ERR(Desc.ColorFormat != TEX_FORMAT_UNKNOWN, "ColorFormat must not be TEX_FORMAT_UNKNOWN"); + DEV_CHECK_ERR(Desc.InputWidth > 0 && Desc.InputHeight > 0, "InputWidth and InputHeight must be greater than zero. "); + DEV_CHECK_ERR(Desc.InputWidth <= Desc.OutputWidth && Desc.InputHeight <= Desc.OutputHeight, "Input resolution must not exceed output resolution"); + DEV_CHECK_ERR(Desc.DepthFormat != TEX_FORMAT_UNKNOWN, "DepthFormat must not be TEX_FORMAT_UNKNOWN. DirectSR upscalers are always temporal and require a depth buffer."); + DEV_CHECK_ERR(Desc.MotionFormat != TEX_FORMAT_UNKNOWN, "MotionFormat must not be TEX_FORMAT_UNKNOWN. DirectSR upscalers are always temporal and require motion vectors."); + DEV_CHECK_ERR(Desc.MotionFormat == TEX_FORMAT_RG16_FLOAT, "MotionFormat must be TEX_FORMAT_RG16_FLOAT. Got: ", GetTextureFormatAttribs(Desc.MotionFormat).Name); + + // Validate create flags against variant capabilities + { + const auto& SRProps = pDevice->GetAdapterInfo().SuperResolution; + SUPER_RESOLUTION_TEMPORAL_CAP_FLAGS VariantCapFlags = SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_NONE; + for (Uint8 Idx = 0; Idx < SRProps.NumUpscalers; ++Idx) + { + if (SRProps.Upscalers[Idx].VariantId == Desc.VariantId) + { + VariantCapFlags = SRProps.Upscalers[Idx].TemporalCapFlags; + break; + } + } + + if (Desc.Flags & SUPER_RESOLUTION_CREATE_FLAG_ENABLE_SHARPENING) + { + DEV_CHECK_ERR(VariantCapFlags & SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_SHARPNESS, + "SUPER_RESOLUTION_CREATE_FLAG_ENABLE_SHARPENING is set, but the selected upscaler variant " + "does not report SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_SHARPNESS capability."); + } + + if (Desc.ReactiveMaskFormat != TEX_FORMAT_UNKNOWN) + { + DEV_CHECK_ERR(VariantCapFlags & SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_REACTIVE_MASK, + "ReactiveMaskFormat is set, but the selected upscaler variant " + "does not report SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_REACTIVE_MASK capability."); + } + + if (Desc.IgnoreHistoryMaskFormat != TEX_FORMAT_UNKNOWN) + { + DEV_CHECK_ERR(VariantCapFlags & SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_IGNORE_HISTORY_MASK, + "IgnoreHistoryMaskFormat is set, but the selected upscaler variant " + "does not report SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_IGNORE_HISTORY_MASK capability."); + } + + if (Desc.ExposureFormat != TEX_FORMAT_UNKNOWN) + { + DEV_CHECK_ERR(!(Desc.Flags & SUPER_RESOLUTION_CREATE_FLAG_AUTO_EXPOSURE), + "ExposureFormat is set, but SUPER_RESOLUTION_CREATE_FLAG_AUTO_EXPOSURE is also enabled. " + "Disable auto-exposure to use a custom exposure texture."); + DEV_CHECK_ERR(VariantCapFlags & SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_EXPOSURE_SCALE_TEXTURE, + "ExposureFormat is set, but the selected upscaler variant " + "does not report SUPER_RESOLUTION_TEMPORAL_CAP_FLAG_EXPOSURE_SCALE_TEXTURE capability."); + } + } + + IDSRDevice* pDSRDevice = pDevice->GetDSRDevice(); + DEV_CHECK_ERR(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 = SuperResolutionCreateFlagsToDSRFlags(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) + { + m_JitterPattern.resize(PatternSize); + if (hr = m_pDSREngine->GetOptimalJitterPattern(SourceSize, TargetSize, &PatternSize, m_JitterPattern.data()); FAILED(hr)) + m_JitterPattern.clear(); + } + } +} + +SuperResolutionD3D12Impl::~SuperResolutionD3D12Impl() = default; + +void DILIGENT_CALL_TYPE SuperResolutionD3D12Impl::GetOptimalJitterPattern(Uint32 Index, float* pJitterX, float* pJitterY) const +{ + 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; + } +} + +void SuperResolutionD3D12Impl::Execute(DeviceContextD3D12Impl& Ctx, const ExecuteSuperResolutionAttribs& Attribs) +{ + DEV_CHECK_ERR(Attribs.pColorTextureSRV != nullptr, "Color texture SRV must not be null"); + DEV_CHECK_ERR(Attribs.pOutputTextureView != nullptr, "Output texture view must not be null"); + DEV_CHECK_ERR(Attribs.pDepthTextureSRV != nullptr, "Depth texture SRV must not be null"); + DEV_CHECK_ERR(Attribs.pMotionVectorsSRV != nullptr, "Motion vectors SRV must not be null. DirectSR upscalers are always temporal"); + DEV_CHECK_ERR(Attribs.CameraNear > 0, "CameraNear must be greater than zero for temporal upscaling"); + DEV_CHECK_ERR(Attribs.CameraFar > 0, "CameraFar must be greater than zero for temporal upscaling."); + DEV_CHECK_ERR(Attribs.CameraFovAngleVert > 0, "CameraFovAngleVert must be greater than zero for temporal upscaling."); + DEV_CHECK_ERR(Attribs.TimeDeltaInSeconds >= 0, "TimeDeltaInSeconds must be non-negative."); + + const SoftwareQueueIndex QueueId = Ctx.GetCommandQueueId(); + VERIFY_EXPR(static_cast(QueueId) < m_DSRUpscalers.size()); + + // Lazily create an upscaler for this queue on first use. + auto& 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 color texture + { + const auto& TexDesc = Attribs.pColorTextureSRV->GetTexture()->GetDesc(); + DEV_CHECK_ERR((TexDesc.BindFlags & BIND_SHADER_RESOURCE) != 0, + "Color texture '", TexDesc.Name, "' must have BIND_SHADER_RESOURCE flag"); + DEV_CHECK_ERR(TexDesc.Width >= m_Desc.InputWidth && TexDesc.Height >= m_Desc.InputHeight, + "Color texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", m_Desc.InputWidth, "x", m_Desc.InputHeight, ")"); + } + + // Validate output texture + { + const auto& TexDesc = Attribs.pOutputTextureView->GetTexture()->GetDesc(); + DEV_CHECK_ERR((TexDesc.BindFlags & BIND_UNORDERED_ACCESS) != 0, + "Output texture '", TexDesc.Name, "' must have BIND_UNORDERED_ACCESS flag"); + DEV_CHECK_ERR(TexDesc.Width == m_Desc.OutputWidth && TexDesc.Height == m_Desc.OutputHeight, + "Output texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must match the upscaler output resolution (", m_Desc.OutputWidth, "x", m_Desc.OutputHeight, ")"); + } + + // Validate depth texture + if (Attribs.pDepthTextureSRV != nullptr) + { + const auto& TexDesc = Attribs.pDepthTextureSRV->GetTexture()->GetDesc(); + DEV_CHECK_ERR((TexDesc.BindFlags & BIND_SHADER_RESOURCE) != 0, + "Depth texture '", TexDesc.Name, "' must have BIND_SHADER_RESOURCE flag"); + DEV_CHECK_ERR(TexDesc.Width >= m_Desc.InputWidth && TexDesc.Height >= m_Desc.InputHeight, + "Depth texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", m_Desc.InputWidth, "x", m_Desc.InputHeight, ")"); + } + + // Validate motion vectors texture + if (Attribs.pMotionVectorsSRV != nullptr) + { + const auto& TexDesc = Attribs.pMotionVectorsSRV->GetTexture()->GetDesc(); + DEV_CHECK_ERR((TexDesc.BindFlags & BIND_SHADER_RESOURCE) != 0, + "Motion vectors texture '", TexDesc.Name, "' must have BIND_SHADER_RESOURCE flag"); + DEV_CHECK_ERR(TexDesc.Width >= m_Desc.InputWidth && TexDesc.Height >= m_Desc.InputHeight, + "Motion vectors texture '", TexDesc.Name, "' dimensions (", TexDesc.Width, "x", TexDesc.Height, + ") must be at least the upscaler input resolution (", m_Desc.InputWidth, "x", m_Desc.InputHeight, ")"); + } + + auto GetD3D12Resource = [](ITextureView* pView) -> ID3D12Resource* { + if (pView != nullptr) + { + auto* 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.pReactiveMaskTexture = GetD3D12Resource(Attribs.pReactiveMaskTextureSRV); + + DSR_SUPERRES_UPSCALER_EXECUTE_FLAGS Flags = DSR_SUPERRES_UPSCALER_EXECUTE_FLAG_NONE; + if (Attribs.ResetHistory) + Flags |= DSR_SUPERRES_UPSCALER_EXECUTE_FLAG_RESET_HISTORY; + + if (HRESULT hr = pDSRUpscaler->Execute(&ExecuteParams, Attribs.TimeDeltaInSeconds, Flags); FAILED(hr)) + LOG_ERROR_MESSAGE("DirectSR Execute failed. HRESULT: ", hr); +} + +} // namespace Diligent diff --git a/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp index 8b592148a..0ca5b186a 100644 --- a/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp +++ b/Tests/DiligentCoreAPITest/src/SuperResolutionTest.cpp @@ -218,7 +218,7 @@ TEST(SuperResolutionTest, CreateTemporalUpscaler) Desc.OutputHeight = 1080; Desc.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; Desc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; - Desc.DepthFormat = TEX_FORMAT_D32_FLOAT; + Desc.DepthFormat = TEX_FORMAT_R32_FLOAT; Desc.MotionFormat = TEX_FORMAT_RG16_FLOAT; Desc.InputWidth = SourceSettings.OptimalInputWidth; Desc.InputHeight = SourceSettings.OptimalInputHeight; @@ -328,7 +328,7 @@ TEST(SuperResolutionTest, ExecuteSpatialUpscaler) auto* pContext = pEnv->GetDeviceContext(); ExecuteSuperResolutionAttribs Attribs; - Attribs.pColorTextureSRV = pColorTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); + Attribs.pColorTextureSRV = pColorTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE); Attribs.pOutputTextureView = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); pContext->ExecuteSuperResolution(Attribs, pUpscaler); @@ -377,7 +377,7 @@ TEST(SuperResolutionTest, ExecuteTemporalUpscaler) UpscalerDesc.OutputHeight = OutputHeight; UpscalerDesc.OutputFormat = TEX_FORMAT_RGBA16_FLOAT; UpscalerDesc.ColorFormat = TEX_FORMAT_RGBA16_FLOAT; - UpscalerDesc.DepthFormat = TEX_FORMAT_D32_FLOAT; + UpscalerDesc.DepthFormat = TEX_FORMAT_R32_FLOAT; UpscalerDesc.MotionFormat = TEX_FORMAT_RG16_FLOAT; UpscalerDesc.InputWidth = SourceSettings.OptimalInputWidth; UpscalerDesc.InputHeight = SourceSettings.OptimalInputHeight; @@ -452,7 +452,7 @@ TEST(SuperResolutionTest, ExecuteTemporalUpscaler) 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_RENDER_TARGET); + Attribs.pOutputTextureView = pOutputTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET); Attribs.JitterX = 0.5f; Attribs.JitterY = -0.5f; Attribs.MotionVectorScaleX = 1.0f;