From 19fd96989ea126fc7478fecc4ae17e4e46710053 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Wed, 12 Mar 2025 18:42:47 +0100 Subject: [PATCH] Merged FSR 2.2 implementation for DX11 into the plugin, so that it supports all three major Windows graphics APIs. --- FSR3UnityPlugin.cpp | 119 +++++++++++++++++++++++++++ FSR3UnityPlugin.vcxproj | 4 +- FSR3UnityTypes.h | 2 - UnityPluginAPI/IUnityGraphicsD3D11.h | 27 ++++++ 4 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 UnityPluginAPI/IUnityGraphicsD3D11.h diff --git a/FSR3UnityPlugin.cpp b/FSR3UnityPlugin.cpp index a3bbc3b..d04aa1d 100644 --- a/FSR3UnityPlugin.cpp +++ b/FSR3UnityPlugin.cpp @@ -9,8 +9,10 @@ #include "UnityPluginAPI/IUnityGraphics.h" #include "UnityPluginAPI/IUnityRenderingExtensions.h" +#include #include #include +#include "UnityPluginAPI/IUnityGraphicsD3D11.h" #include "UnityPluginAPI/IUnityGraphicsD3D12.h" #include "UnityPluginAPI/IUnityGraphicsVulkan.h" @@ -19,6 +21,9 @@ #include "ffx_api/dx12/ffx_api_dx12.hpp" #include "ffx_api/vk/ffx_api_vk.hpp" +#include "ffx-fsr2-api/ffx_fsr2.h" +#include "ffx-fsr2-api/dx11/ffx_fsr2_dx11.h" + #include "FSR3UnityTypes.h" static const int32_t BaseEventId = 0; @@ -26,6 +31,7 @@ static const int32_t BaseEventId = 0; static IUnityInterfaces* s_UnityInterfaces = nullptr; static IUnityLog* s_Log = nullptr; static IUnityGraphics* s_Graphics = nullptr; +static IUnityGraphicsD3D11* s_GraphicsD3D11 = nullptr; static IUnityGraphicsD3D12v7* s_GraphicsD3D12 = nullptr; static IUnityGraphicsVulkan* s_GraphicsVulkan = nullptr; static UnityGfxRenderer s_RendererType = kUnityGfxRendererNull; @@ -37,6 +43,8 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data); struct FSR3Feature { ffx::Context upscalingContext; + FfxFsr2Context fsr2Context; + bool isValid; uint32_t upscaleSizeWidth; uint32_t upscaleSizeHeight; @@ -54,6 +62,9 @@ static ffxFunctions s_ffxFunctions{}; static ffx::CreateBackendDX12Desc s_DX12BackendDesc{}; static ffx::CreateBackendVKDesc s_VulkanBackendDesc{}; +static FfxDevice s_DX11Device = nullptr; +static FfxFsr2Interface s_Fsr2Interface; + // Unity plugin load event extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces) { @@ -83,6 +94,16 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev s_RendererType = s_Graphics->GetRenderer(); switch (s_RendererType) { + case kUnityGfxRendererD3D11: + { + s_GraphicsD3D11 = s_UnityInterfaces->Get(); + if (s_GraphicsD3D11 == nullptr) + { + UNITY_LOG_ERROR(s_Log, "Could not obtain D3D11 Graphics interface!"); + return; + } + break; + } case kUnityGfxRendererD3D12: { s_GraphicsD3D12 = s_UnityInterfaces->Get(); @@ -111,6 +132,7 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev { s_GraphicsVulkan = nullptr; s_GraphicsD3D12 = nullptr; + s_GraphicsD3D11 = nullptr; s_RendererType = kUnityGfxRendererNull; break; } @@ -135,6 +157,7 @@ static uint32_t AllocateFeatureSlot() // Create a new feature if there are no free slots uint32_t featureSlot = (uint32_t)s_Features.size(); s_Features.push_back(std::move(FSR3Feature())); + memset(&s_Features[featureSlot], 0, sizeof(FSR3Feature)); return featureSlot; } @@ -180,6 +203,19 @@ static bool LoadFidelityFXLibrary(_In_ LPCWSTR lpLibFileName) extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi() { + if (s_GraphicsD3D11 != nullptr) + { + ID3D11Device* device = s_GraphicsD3D11->GetDevice(); + if (device == nullptr) + return false; + + s_DX11Device = ffxGetDeviceDX11(device); + + size_t scratchBufferSize = ffxFsr2GetScratchMemorySizeDX11(); + void* scratchBuffer = malloc(scratchBufferSize); + ffxFsr2GetInterfaceDX11(&s_Fsr2Interface, device, scratchBuffer, scratchBufferSize); + return true; + } if (s_GraphicsD3D12 != nullptr) { ID3D12Device* device = s_GraphicsD3D12->GetDevice(); @@ -216,6 +252,11 @@ extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi() s_ffxFunctions.DestroyContext(&feature.upscalingContext, nullptr); FreeFeatureSlot(slot); } + else if (feature.isValid) + { + ffxFsr2ContextDestroy(&feature.fsr2Context); + FreeFeatureSlot(slot); + } } if (s_ffxModule != nullptr) @@ -223,12 +264,20 @@ extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi() FreeLibrary(s_ffxModule); s_ffxModule = nullptr; } + + if (s_Fsr2Interface.scratchBuffer != nullptr) + { + free(s_Fsr2Interface.scratchBuffer); + s_Fsr2Interface.scratchBuffer = nullptr; + } s_VulkanBackendDesc.vkDevice = nullptr; s_VulkanBackendDesc.vkPhysicalDevice = nullptr; s_VulkanBackendDesc.vkDeviceProcAddr = nullptr; s_DX12BackendDesc.device = nullptr; + + s_DX11Device = nullptr; } extern "C" uint32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetDeviceVersion() @@ -321,6 +370,11 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) s_ffxFunctions.DestroyContext(&feature.upscalingContext, nullptr); FreeFeatureSlot(featureSlot); } + else if (feature.isValid) + { + ffxFsr2ContextDestroy(&feature.fsr2Context); + FreeFeatureSlot(featureSlot); + } break; } case BaseEventId + FSR3PluginEvent::eExecute: @@ -331,6 +385,52 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) auto& feature = s_Features[params->featureSlot]; + if (s_GraphicsD3D11 != nullptr) + { + // Execute FSR 2.2 on DX11 + FfxFsr2DispatchDescription dispatchDescription{}; + + ID3D11DeviceContext* ctx = nullptr; + s_GraphicsD3D11->GetDevice()->GetImmediateContext(&ctx); + dispatchDescription.commandList = ctx; + + dispatchDescription.color = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.colorInput.image); + dispatchDescription.depth = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.depth.image); + dispatchDescription.motionVectors = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.motionVectors.image); + dispatchDescription.exposure = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.exposureTexture.image); + dispatchDescription.reactive = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.reactiveMask.image); + dispatchDescription.transparencyAndComposition = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.transparencyMask.image); + dispatchDescription.output = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.colorOutput.image, nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS); + + dispatchDescription.jitterOffset.x = params->jitterOffsetX; + dispatchDescription.jitterOffset.y = params->jitterOffsetY; + dispatchDescription.motionVectorScale.x = params->MVScaleX; + dispatchDescription.motionVectorScale.y = params->MVScaleY; + dispatchDescription.reset = params->reset; + dispatchDescription.enableSharpening = params->enableSharpening; + dispatchDescription.sharpness = params->sharpness; + dispatchDescription.frameTimeDelta = params->frameTimeDelta; + dispatchDescription.preExposure = params->preExposure; + dispatchDescription.renderSize.width = params->renderSizeWidth; + dispatchDescription.renderSize.height = params->renderSizeHeight; + dispatchDescription.cameraFovAngleVertical = params->cameraFovAngleVertical; + + if (feature.flags & FFX_FSR2_ENABLE_DEPTH_INVERTED) + { + dispatchDescription.cameraFar = params->cameraNear; + dispatchDescription.cameraNear = params->cameraFar; + } + else + { + dispatchDescription.cameraFar = params->cameraFar; + dispatchDescription.cameraNear = params->cameraNear; + } + + ffxFsr2ContextDispatch(&feature.fsr2Context, &dispatchDescription); + return; + } + + // Execute FSR 3.1 or higher on DX12 and Vulkan ffx::DispatchDescUpscale dispatchUpscale{}; if (s_GraphicsD3D12 != nullptr) @@ -408,6 +508,21 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) feature.upscaleSizeHeight = params->displaySizeHeight; feature.flags = params->flags; + if (s_GraphicsD3D11 != nullptr) + { + // Create an FSR 2.2 context on DX11 + FfxFsr2ContextDescription contextDescription{}; + contextDescription.callbacks = s_Fsr2Interface; + contextDescription.device = s_DX11Device; + contextDescription.displaySize = { params->displaySizeWidth, params->displaySizeHeight }; + contextDescription.maxRenderSize = { params->maxRenderSizeWidth, params->maxRenderSizeHeight }; + contextDescription.flags = params->flags; + + feature.isValid = ffxFsr2ContextCreate(&feature.fsr2Context, &contextDescription) == FFX_OK; + return; + } + + // Create an FSR 3.1 or higher context on DX12 and Vulkan ffx::CreateContextDescUpscale createUpscaling; createUpscaling.maxUpscaleSize = { params->displaySizeWidth, params->displaySizeHeight }; createUpscaling.maxRenderSize = { params->maxRenderSizeWidth, params->maxRenderSizeHeight }; @@ -457,6 +572,10 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data) // This way we can use the texture slot value simply as a pointer offset into the texture table FSR3TextureDesc* textureDesc = ((FSR3TextureDesc*)&feature.textureTable) + textureSlot; + if (s_GraphicsD3D11 != nullptr) + { + textureDesc->image = (intptr_t)s_GraphicsD3D11->TextureFromNativeTexture((UnityTextureID)params->textureID); + } if (s_GraphicsD3D12 != nullptr) { textureDesc->image = (intptr_t)s_GraphicsD3D12->TextureFromNativeTexture((UnityTextureID)params->textureID); diff --git a/FSR3UnityPlugin.vcxproj b/FSR3UnityPlugin.vcxproj index 72d22c9..56260f4 100644 --- a/FSR3UnityPlugin.vcxproj +++ b/FSR3UnityPlugin.vcxproj @@ -124,7 +124,7 @@ Windows true false - $(CoreLibraryDependencies);%(AdditionalDependencies);vulkan-1.lib + $(CoreLibraryDependencies);%(AdditionalDependencies);lib\ffx_fsr2_api\ffx_fsr2_api_x64d.lib;lib\ffx_fsr2_api\ffx_fsr2_api_dx11_x64d.lib;dxguid.lib;vulkan-1.lib %VULKAN_SDK%\Lib;%(AdditionalLibraryDirectories) @@ -146,7 +146,7 @@ true true false - $(CoreLibraryDependencies);%(AdditionalDependencies);vulkan-1.lib + $(CoreLibraryDependencies);%(AdditionalDependencies);lib\ffx_fsr2_api\ffx_fsr2_api_x64.lib;lib\ffx_fsr2_api\ffx_fsr2_api_dx11_x64.lib;dxguid.lib;vulkan-1.lib %VULKAN_SDK%\Lib;%(AdditionalLibraryDirectories) diff --git a/FSR3UnityTypes.h b/FSR3UnityTypes.h index b72993b..0e64eca 100644 --- a/FSR3UnityTypes.h +++ b/FSR3UnityTypes.h @@ -78,6 +78,4 @@ struct FSR3TextureTable FSR3TextureDesc exposureTexture; FSR3TextureDesc reactiveMask; FSR3TextureDesc biasColorMask; - - uint32_t featureSlot; }; diff --git a/UnityPluginAPI/IUnityGraphicsD3D11.h b/UnityPluginAPI/IUnityGraphicsD3D11.h new file mode 100644 index 0000000..b94f6ac --- /dev/null +++ b/UnityPluginAPI/IUnityGraphicsD3D11.h @@ -0,0 +1,27 @@ +// Unity Native Plugin API copyright © 2015 Unity Technologies ApS +// +// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License). +// +// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions. + +#pragma once +#include "IUnityInterface.h" + + +// Should only be used on the rendering thread unless noted otherwise. +UNITY_DECLARE_INTERFACE(IUnityGraphicsD3D11) +{ + ID3D11Device* (UNITY_INTERFACE_API * GetDevice)(); + + ID3D11Resource* (UNITY_INTERFACE_API * TextureFromRenderBuffer)(UnityRenderBuffer buffer); + ID3D11Resource* (UNITY_INTERFACE_API * TextureFromNativeTexture)(UnityTextureID texture); + + ID3D11RenderTargetView* (UNITY_INTERFACE_API * RTVFromRenderBuffer)(UnityRenderBuffer surface); + ID3D11ShaderResourceView* (UNITY_INTERFACE_API * SRVFromNativeTexture)(UnityTextureID texture); + + IDXGISwapChain* (UNITY_INTERFACE_API * GetSwapChain)(); + UINT32(UNITY_INTERFACE_API * GetSyncInterval)(); + UINT(UNITY_INTERFACE_API * GetPresentFlags)(); +}; + +UNITY_REGISTER_INTERFACE_GUID(0xAAB37EF87A87D748ULL, 0xBF76967F07EFB177ULL, IUnityGraphicsD3D11)