diff --git a/Graphics/Archiver/include/SerializationDeviceImpl.hpp b/Graphics/Archiver/include/SerializationDeviceImpl.hpp index 568c7f753b..325e5eebcb 100644 --- a/Graphics/Archiver/include/SerializationDeviceImpl.hpp +++ b/Graphics/Archiver/include/SerializationDeviceImpl.hpp @@ -70,11 +70,14 @@ class SerializationDeviceImpl final : public RenderDeviceBase diff --git a/Graphics/GraphicsEngine.NET/Mapping.xml b/Graphics/GraphicsEngine.NET/Mapping.xml index 971c774eec..5e8f6d2f29 100644 --- a/Graphics/GraphicsEngine.NET/Mapping.xml +++ b/Graphics/GraphicsEngine.NET/Mapping.xml @@ -55,6 +55,7 @@ + @@ -248,6 +249,7 @@ + @@ -299,6 +301,10 @@ + + + + diff --git a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp index c2aa19f01f..00f84bbfb8 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/interface/Constants.h b/Graphics/GraphicsEngine/interface/Constants.h index a54a336cd0..f08b557f01 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 f3b073fa0b..9b83f4bc42 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 4ef5a1e49c..684353f500 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1856,6 +1856,10 @@ struct DeviceFeatures /// Indicates if device supports formatted buffers. DEVICE_FEATURE_STATE FormattedBuffers 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 {} @@ -1906,11 +1910,12 @@ struct DeviceFeatures Handler(TextureSubresourceViews) \ Handler(NativeMultiDraw) \ Handler(AsyncShaderCompilation) \ - Handler(FormattedBuffers) + Handler(FormattedBuffers) \ + Handler(SuperResolution) explicit constexpr DeviceFeatures(DEVICE_FEATURE_STATE State) noexcept { - static_assert(sizeof(*this) == 47, "Did you add a new feature to DeviceFeatures? Please add it to ENUMERATE_DEVICE_FEATURES."); + static_assert(sizeof(*this) == 48, "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 @@ -3251,6 +3256,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 { @@ -3342,6 +3506,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: @@ -3388,6 +3555,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 8849591048..ec345662d9 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 0000000000..4bfae91a26 --- /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 diff --git a/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp b/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp index 4839b901a8..bb3730001c 100644 --- a/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderDeviceBase.cpp @@ -120,9 +120,10 @@ DeviceFeatures EnableDeviceFeatures(const DeviceFeatures& SupportedFeatures, ENABLE_FEATURE(NativeMultiDraw, "Native multi-draw commands are"); ENABLE_FEATURE(AsyncShaderCompilation, "Async shader compilation is"); ENABLE_FEATURE(FormattedBuffers, "Formatted buffers are"); + ENABLE_FEATURE(SuperResolution, "Super resolution is"); // clang-format on - ASSERT_SIZEOF(DeviceFeatures, 47, "Did you add a new feature to DeviceFeatures? Please handle its status here (if necessary)."); + ASSERT_SIZEOF(DeviceFeatures, 48, "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 0432485d3f..139670d446 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 2d0b30599f..26f0ce2415 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 ea7183ba95..24981d6197 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 7f60064556..9a34a40699 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 a240ab20e9..f8b7d37096 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"); @@ -1131,7 +1149,7 @@ void RenderDeviceGLImpl::InitAdapterInfo() m_AdapterInfo.Queues[0].TextureCopyGranularity[2] = 1; } - ASSERT_SIZEOF(DeviceFeatures, 47, "Did you add a new feature to DeviceFeatures? Please handle its status here."); + ASSERT_SIZEOF(DeviceFeatures, 48, "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 63086dd047..0788c6b727 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -291,6 +291,9 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBaseGetDevice(); @@ -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 0000000000..d5f0ba6ff9 --- /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 57faf1b861..473d6aa565 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 0000000000..141a094cf3 --- /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 0000000000..5788fb94b5 --- /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"