|
|
|
@ -23,7 +23,7 @@ |
|
|
|
|
|
|
|
#include "FSR2UnityTypes.h"
|
|
|
|
|
|
|
|
static const int32_t BaseEventId = 0; |
|
|
|
static const int32_t BaseEventId = 313; |
|
|
|
|
|
|
|
static IUnityInterfaces* s_UnityInterfaces = nullptr; |
|
|
|
static IUnityLog* s_Log = nullptr; |
|
|
|
@ -106,6 +106,12 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev |
|
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D12 Graphics interface!"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
UnityD3D12PluginEventConfig eventConfig; |
|
|
|
eventConfig.graphicsQueueAccess = kUnityD3D12GraphicsQueueAccess_DontCare; |
|
|
|
eventConfig.flags = kUnityD3D12EventConfigFlag_EnsurePreviousFrameSubmission | kUnityD3D12EventConfigFlag_FlushCommandBuffers | kUnityD3D12EventConfigFlag_SyncWorkerThreads | kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState; |
|
|
|
eventConfig.ensureActiveRenderTextureIsBound = false; |
|
|
|
s_GraphicsD3D12->ConfigureEvent(BaseEventId + FSR2PluginEvent::eExecute, &eventConfig); |
|
|
|
break; |
|
|
|
} |
|
|
|
case kUnityGfxRendererVulkan: |
|
|
|
@ -116,6 +122,12 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev |
|
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain Vulkan Graphics interface!"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
UnityVulkanPluginEventConfig eventConfig; |
|
|
|
eventConfig.graphicsQueueAccess = kUnityVulkanGraphicsQueueAccess_DontCare; |
|
|
|
eventConfig.flags = kUnityVulkanEventConfigFlag_EnsurePreviousFrameSubmission | kUnityVulkanEventConfigFlag_FlushCommandBuffers | kUnityVulkanEventConfigFlag_SyncWorkerThreads | kUnityVulkanEventConfigFlag_ModifiesCommandBuffersState; |
|
|
|
eventConfig.renderPassPrecondition = kUnityVulkanRenderPass_EnsureInside; |
|
|
|
s_GraphicsVulkan->ConfigureEvent(BaseEventId + FSR2PluginEvent::eExecute, &eventConfig); |
|
|
|
break; |
|
|
|
} |
|
|
|
}; |
|
|
|
@ -225,18 +237,27 @@ extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi() |
|
|
|
|
|
|
|
static void DestroyFeature(uint32_t featureSlot) |
|
|
|
{ |
|
|
|
uint64_t dispatchFrameValue = 0; |
|
|
|
{ |
|
|
|
// We need to lock the features list while we're accessing it, but we also can't hold the lock while blocking the main/render thread at the same time.
|
|
|
|
// Otherwise we're very likely to create a deadlock. So instead we only lock for as long as is necessary to grab the data we need from the feature.
|
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
auto& feature = s_Features[featureSlot]; |
|
|
|
if (!feature.isValid) |
|
|
|
return; |
|
|
|
|
|
|
|
dispatchFrameValue = feature.dispatchFrameValue; |
|
|
|
} |
|
|
|
|
|
|
|
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()) |
|
|
|
if (dispatchFrameValue > frameFence->GetCompletedValue()) |
|
|
|
{ |
|
|
|
frameFence->SetEventOnCompletion(feature.dispatchFrameValue, s_FrameFenceEventHandle); |
|
|
|
frameFence->SetEventOnCompletion(dispatchFrameValue, s_FrameFenceEventHandle); |
|
|
|
WaitForSingleObjectEx(s_FrameFenceEventHandle, INFINITE, false); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -244,26 +265,35 @@ static void DestroyFeature(uint32_t featureSlot) |
|
|
|
{ |
|
|
|
UnityVulkanRecordingState state; |
|
|
|
s_GraphicsVulkan->CommandRecordingState(&state, kUnityVulkanGraphicsQueueAccess_DontCare); |
|
|
|
if (feature.dispatchFrameValue > state.safeFrameNumber) |
|
|
|
if (dispatchFrameValue > state.safeFrameNumber) |
|
|
|
{ |
|
|
|
UnityVulkanInstance instance = s_GraphicsVulkan->Instance(); |
|
|
|
vkQueueWaitIdle(instance.graphicsQueue); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
auto& feature = s_Features[featureSlot]; |
|
|
|
ffxFsr2ContextDestroy(&feature.upscalingContext); |
|
|
|
FreeFeatureSlot(featureSlot); |
|
|
|
} |
|
|
|
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi() |
|
|
|
{ |
|
|
|
size_t numFeatures = 0; |
|
|
|
{ |
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
numFeatures = s_Features.size(); |
|
|
|
} |
|
|
|
|
|
|
|
for (uint32_t slot = 0; slot < s_Features.size(); ++slot) |
|
|
|
for (uint32_t slot = 0; slot < numFeatures; ++slot) |
|
|
|
{ |
|
|
|
DestroyFeature(slot); |
|
|
|
} |
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
if (s_Fsr2Interface.scratchBuffer != nullptr) |
|
|
|
{ |
|
|
|
free(s_Fsr2Interface.scratchBuffer); |
|
|
|
@ -367,8 +397,6 @@ static void DestroyVulkanImageView(UnityVulkanInstance& instance, FSR2TextureDes |
|
|
|
// Plugin function to handle a specific rendering event
|
|
|
|
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
|
{ |
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
if (s_Device == nullptr) |
|
|
|
return; |
|
|
|
|
|
|
|
@ -386,6 +414,8 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
|
} |
|
|
|
case BaseEventId + FSR2PluginEvent::eExecute: |
|
|
|
{ |
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
auto* params = (FSR2CommandExecutionData*)data; |
|
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size()) |
|
|
|
return; |
|
|
|
@ -484,6 +514,8 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
|
} |
|
|
|
case BaseEventId + FSR2PluginEvent::ePostExecute: |
|
|
|
{ |
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
auto* params = (FSR2CommandExecutionData*)data; |
|
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size()) |
|
|
|
return; |
|
|
|
@ -506,6 +538,8 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
|
} |
|
|
|
case BaseEventId + FSR2PluginEvent::eInit: |
|
|
|
{ |
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
auto* params = (FSR2CommandInitializationData*)data; |
|
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size()) |
|
|
|
return; |
|
|
|
|