@ -46,6 +46,8 @@ struct FSR2Feature
uint32_t flags ;
uint32_t flags ;
bool isValid ;
bool isValid ;
uint64_t dispatchFrameValue ;
FSR2TextureTable textureTable ;
FSR2TextureTable textureTable ;
} ;
} ;
@ -53,6 +55,8 @@ static std::vector<FSR2Feature> s_Features;
static std : : queue < uint32_t > s_FeatureSlots ;
static std : : queue < uint32_t > s_FeatureSlots ;
static std : : mutex s_FeatureMutex ;
static std : : mutex s_FeatureMutex ;
static HANDLE s_FrameFenceEventHandle = nullptr ;
// Unity plugin load event
// Unity plugin load event
extern " C " void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad ( IUnityInterfaces * unityInterfaces )
extern " C " void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad ( IUnityInterfaces * unityInterfaces )
{
{
@ -190,6 +194,7 @@ extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi()
return false ;
return false ;
s_Device = ffxGetDeviceDX12 ( device ) ;
s_Device = ffxGetDeviceDX12 ( device ) ;
s_FrameFenceEventHandle = CreateEventEx ( nullptr , nullptr , 0 , EVENT_ALL_ACCESS ) ;
size_t scratchBufferSize = ffxFsr2GetScratchMemorySizeDX12 ( ) ;
size_t scratchBufferSize = ffxFsr2GetScratchMemorySizeDX12 ( ) ;
void * scratchBuffer = malloc ( scratchBufferSize ) ;
void * scratchBuffer = malloc ( scratchBufferSize ) ;
@ -216,6 +221,29 @@ extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi()
static void DestroyFeature ( uint32_t featureSlot )
static void DestroyFeature ( uint32_t featureSlot )
{
{
auto & feature = s_Features [ featureSlot ] ;
auto & feature = s_Features [ featureSlot ] ;
if ( s_GraphicsD3D12 ! = nullptr )
{
// If there's still an upscale dispatch executing on the current frame, wait until rendering is finished before destroying its context.
// Thanks to https://alextardif.com/D3D11To12P1.html for explaining how fences work and how to make the CPU wait for a command queue to complete.
ID3D12Fence * frameFence = s_GraphicsD3D12 - > GetFrameFence ( ) ;
if ( feature . dispatchFrameValue > frameFence - > GetCompletedValue ( ) )
{
frameFence - > SetEventOnCompletion ( feature . dispatchFrameValue , s_FrameFenceEventHandle ) ;
WaitForSingleObjectEx ( s_FrameFenceEventHandle , INFINITE , false ) ;
}
}
else if ( s_GraphicsVulkan ! = nullptr )
{
UnityVulkanRecordingState state ;
s_GraphicsVulkan - > CommandRecordingState ( & state , kUnityVulkanGraphicsQueueAccess_DontCare ) ;
if ( feature . dispatchFrameValue > state . safeFrameNumber )
{
UnityVulkanInstance instance = s_GraphicsVulkan - > Instance ( ) ;
vkQueueWaitIdle ( instance . graphicsQueue ) ;
}
}
if ( feature . isValid )
if ( feature . isValid )
{
{
ffxFsr2ContextDestroy ( & feature . upscalingContext ) ;
ffxFsr2ContextDestroy ( & feature . upscalingContext ) ;
@ -237,6 +265,12 @@ extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi()
free ( s_Fsr2Interface . scratchBuffer ) ;
free ( s_Fsr2Interface . scratchBuffer ) ;
s_Fsr2Interface . scratchBuffer = nullptr ;
s_Fsr2Interface . scratchBuffer = nullptr ;
}
}
if ( s_FrameFenceEventHandle ! = nullptr )
{
CloseHandle ( s_FrameFenceEventHandle ) ;
s_FrameFenceEventHandle = nullptr ;
}
s_Device = nullptr ;
s_Device = nullptr ;
}
}
@ -378,6 +412,9 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
s_GraphicsD3D12 - > CommandRecordingState ( & state ) ;
s_GraphicsD3D12 - > CommandRecordingState ( & state ) ;
dispatchDescription . commandList = ffxGetCommandListDX12 ( state . commandList ) ;
dispatchDescription . commandList = ffxGetCommandListDX12 ( state . commandList ) ;
// Keep track of which frame this dispatch is happening on, so we can verify when it's finished
feature . dispatchFrameValue = s_GraphicsD3D12 - > GetNextFrameFenceValue ( ) ;
dispatchDescription . color = ffxGetResourceDX12 ( & feature . upscalingContext , ( ID3D12Resource * ) feature . textureTable . colorInput . image ) ;
dispatchDescription . color = ffxGetResourceDX12 ( & feature . upscalingContext , ( ID3D12Resource * ) feature . textureTable . colorInput . image ) ;
dispatchDescription . depth = ffxGetResourceDX12 ( & feature . upscalingContext , ( ID3D12Resource * ) feature . textureTable . depth . image ) ;
dispatchDescription . depth = ffxGetResourceDX12 ( & feature . upscalingContext , ( ID3D12Resource * ) feature . textureTable . depth . image ) ;
dispatchDescription . motionVectors = ffxGetResourceDX12 ( & feature . upscalingContext , ( ID3D12Resource * ) feature . textureTable . motionVectors . image ) ;
dispatchDescription . motionVectors = ffxGetResourceDX12 ( & feature . upscalingContext , ( ID3D12Resource * ) feature . textureTable . motionVectors . image ) ;
@ -392,6 +429,9 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
s_GraphicsVulkan - > CommandRecordingState ( & state , kUnityVulkanGraphicsQueueAccess_DontCare ) ;
s_GraphicsVulkan - > CommandRecordingState ( & state , kUnityVulkanGraphicsQueueAccess_DontCare ) ;
dispatchDescription . commandList = ffxGetCommandListVK ( state . commandBuffer ) ;
dispatchDescription . commandList = ffxGetCommandListVK ( state . commandBuffer ) ;
// Keep track of which frame this dispatch is happening on, so we can verify when it's finished
feature . dispatchFrameValue = state . currentFrameNumber ;
UnityVulkanInstance instance = s_GraphicsVulkan - > Instance ( ) ;
UnityVulkanInstance instance = s_GraphicsVulkan - > Instance ( ) ;
dispatchDescription . color = GetVulkanTextureResource ( instance , feature , feature . textureTable . colorInput ) ;
dispatchDescription . color = GetVulkanTextureResource ( instance , feature , feature . textureTable . colorInput ) ;
dispatchDescription . depth = GetVulkanTextureResource ( instance , feature , feature . textureTable . depth ) ;
dispatchDescription . depth = GetVulkanTextureResource ( instance , feature , feature . textureTable . depth ) ;