|
|
@ -1,74 +1,26 @@ |
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <queue>
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
|
#include "Upscaler.h"
|
|
|
|
|
|
|
|
|
#include "UnityPluginAPI/IUnityInterface.h"
|
|
|
#include "UnityPluginAPI/IUnityInterface.h"
|
|
|
#include "UnityPluginAPI/IUnityLog.h"
|
|
|
#include "UnityPluginAPI/IUnityLog.h"
|
|
|
#include "UnityPluginAPI/IUnityGraphics.h"
|
|
|
#include "UnityPluginAPI/IUnityGraphics.h"
|
|
|
#include "UnityPluginAPI/IUnityRenderingExtensions.h"
|
|
|
#include "UnityPluginAPI/IUnityRenderingExtensions.h"
|
|
|
|
|
|
|
|
|
#include <d3d11.h>
|
|
|
|
|
|
#include <d3d12.h>
|
|
|
|
|
|
#include <dxgi.h>
|
|
|
|
|
|
#include "UnityPluginAPI/IUnityGraphicsD3D11.h"
|
|
|
|
|
|
#include "UnityPluginAPI/IUnityGraphicsD3D12.h"
|
|
|
|
|
|
#include "UnityPluginAPI/IUnityGraphicsVulkan.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "ffx_api/ffx_api_loader.h"
|
|
|
|
|
|
#include "ffx_api/ffx_upscale.hpp"
|
|
|
|
|
|
#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"
|
|
|
|
|
|
|
|
|
#include "FSR2Upscaler_DX11.h"
|
|
|
|
|
|
#include "FSR3Upscaler_DX12.h"
|
|
|
|
|
|
#include "FSR3Upscaler_Vulkan.h"
|
|
|
|
|
|
|
|
|
static const int32_t BaseEventId = 313; |
|
|
static const int32_t BaseEventId = 313; |
|
|
|
|
|
|
|
|
static IUnityInterfaces* s_UnityInterfaces = nullptr; |
|
|
static IUnityInterfaces* s_UnityInterfaces = nullptr; |
|
|
static IUnityLog* s_Log = nullptr; |
|
|
static IUnityLog* s_Log = nullptr; |
|
|
static IUnityGraphics* s_Graphics = 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; |
|
|
static UnityGfxRenderer s_RendererType = kUnityGfxRendererNull; |
|
|
|
|
|
|
|
|
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType); |
|
|
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType); |
|
|
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data); |
|
|
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data); |
|
|
static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data); |
|
|
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; |
|
|
|
|
|
uint32_t flags; |
|
|
|
|
|
|
|
|
|
|
|
uint64_t dispatchFrameValue; |
|
|
|
|
|
|
|
|
|
|
|
FSR3TextureTable textureTable; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static std::vector<FSR3Feature> s_Features; |
|
|
|
|
|
static std::queue<uint32_t> s_FeatureSlots; |
|
|
|
|
|
static std::mutex s_FeatureMutex; |
|
|
|
|
|
|
|
|
|
|
|
static HMODULE s_ffxModule = nullptr; |
|
|
|
|
|
static ffxFunctions s_ffxFunctions{}; |
|
|
|
|
|
static ffx::CreateBackendDX12Desc s_DX12BackendDesc{}; |
|
|
|
|
|
static ffx::CreateBackendVKDesc s_VulkanBackendDesc{}; |
|
|
|
|
|
|
|
|
|
|
|
static FfxDevice s_DX11Device = nullptr; |
|
|
|
|
|
static FfxFsr2Interface s_Fsr2Interface; |
|
|
|
|
|
|
|
|
|
|
|
static HANDLE s_FrameFenceEventHandle = nullptr; |
|
|
|
|
|
|
|
|
static Upscaler* s_Upscaler = 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) |
|
|
@ -92,8 +44,6 @@ extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload() |
|
|
|
|
|
|
|
|
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType) |
|
|
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType) |
|
|
{ |
|
|
{ |
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
|
|
|
|
switch (eventType) |
|
|
switch (eventType) |
|
|
{ |
|
|
{ |
|
|
case kUnityGfxDeviceEventInitialize: |
|
|
case kUnityGfxDeviceEventInitialize: |
|
|
@ -103,44 +53,50 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev |
|
|
{ |
|
|
{ |
|
|
case kUnityGfxRendererD3D11: |
|
|
case kUnityGfxRendererD3D11: |
|
|
{ |
|
|
{ |
|
|
s_GraphicsD3D11 = s_UnityInterfaces->Get<IUnityGraphicsD3D11>(); |
|
|
|
|
|
if (s_GraphicsD3D11 == nullptr) |
|
|
|
|
|
|
|
|
auto* graphicsD3D11 = s_UnityInterfaces->Get<IUnityGraphicsD3D11>(); |
|
|
|
|
|
if (graphicsD3D11 == nullptr) |
|
|
{ |
|
|
{ |
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D11 Graphics interface!"); |
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D11 Graphics interface!"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s_Upscaler = new FSR2Upscaler_DX11(graphicsD3D11); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case kUnityGfxRendererD3D12: |
|
|
case kUnityGfxRendererD3D12: |
|
|
{ |
|
|
{ |
|
|
s_GraphicsD3D12 = s_UnityInterfaces->Get<IUnityGraphicsD3D12v7>(); |
|
|
|
|
|
if (s_GraphicsD3D12 == nullptr) |
|
|
|
|
|
|
|
|
auto* graphicsD3D12 = s_UnityInterfaces->Get<IUnityGraphicsD3D12v7>(); |
|
|
|
|
|
if (graphicsD3D12 == nullptr) |
|
|
{ |
|
|
{ |
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D12 Graphics interface!"); |
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D12 Graphics interface!"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s_Upscaler = new FSR3Upscaler_DX12(s_Log, graphicsD3D12); |
|
|
|
|
|
|
|
|
UnityD3D12PluginEventConfig eventConfig; |
|
|
UnityD3D12PluginEventConfig eventConfig; |
|
|
eventConfig.graphicsQueueAccess = kUnityD3D12GraphicsQueueAccess_DontCare; |
|
|
eventConfig.graphicsQueueAccess = kUnityD3D12GraphicsQueueAccess_DontCare; |
|
|
eventConfig.flags = kUnityD3D12EventConfigFlag_EnsurePreviousFrameSubmission | kUnityD3D12EventConfigFlag_FlushCommandBuffers | kUnityD3D12EventConfigFlag_SyncWorkerThreads | kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState; |
|
|
eventConfig.flags = kUnityD3D12EventConfigFlag_EnsurePreviousFrameSubmission | kUnityD3D12EventConfigFlag_FlushCommandBuffers | kUnityD3D12EventConfigFlag_SyncWorkerThreads | kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState; |
|
|
eventConfig.ensureActiveRenderTextureIsBound = false; |
|
|
eventConfig.ensureActiveRenderTextureIsBound = false; |
|
|
s_GraphicsD3D12->ConfigureEvent(BaseEventId + FSR3PluginEvent::eExecute, &eventConfig); |
|
|
|
|
|
|
|
|
graphicsD3D12->ConfigureEvent(BaseEventId + FSR3PluginEvent::eExecute, &eventConfig); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case kUnityGfxRendererVulkan: |
|
|
case kUnityGfxRendererVulkan: |
|
|
{ |
|
|
{ |
|
|
s_GraphicsVulkan = s_UnityInterfaces->Get<IUnityGraphicsVulkan>(); |
|
|
|
|
|
if (s_GraphicsVulkan == nullptr) |
|
|
|
|
|
|
|
|
auto* graphicsVulkan = s_UnityInterfaces->Get<IUnityGraphicsVulkan>(); |
|
|
|
|
|
if (graphicsVulkan == nullptr) |
|
|
{ |
|
|
{ |
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain Vulkan Graphics interface!"); |
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain Vulkan Graphics interface!"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s_Upscaler = new FSR3Upscaler_Vulkan(s_Log, graphicsVulkan); |
|
|
|
|
|
|
|
|
UnityVulkanPluginEventConfig eventConfig; |
|
|
UnityVulkanPluginEventConfig eventConfig; |
|
|
eventConfig.graphicsQueueAccess = kUnityVulkanGraphicsQueueAccess_DontCare; |
|
|
eventConfig.graphicsQueueAccess = kUnityVulkanGraphicsQueueAccess_DontCare; |
|
|
eventConfig.flags = kUnityVulkanEventConfigFlag_EnsurePreviousFrameSubmission | kUnityVulkanEventConfigFlag_FlushCommandBuffers | kUnityVulkanEventConfigFlag_SyncWorkerThreads | kUnityVulkanEventConfigFlag_ModifiesCommandBuffersState; |
|
|
eventConfig.flags = kUnityVulkanEventConfigFlag_EnsurePreviousFrameSubmission | kUnityVulkanEventConfigFlag_FlushCommandBuffers | kUnityVulkanEventConfigFlag_SyncWorkerThreads | kUnityVulkanEventConfigFlag_ModifiesCommandBuffersState; |
|
|
eventConfig.renderPassPrecondition = kUnityVulkanRenderPass_EnsureInside; |
|
|
eventConfig.renderPassPrecondition = kUnityVulkanRenderPass_EnsureInside; |
|
|
s_GraphicsVulkan->ConfigureEvent(BaseEventId + FSR3PluginEvent::eExecute, &eventConfig); |
|
|
|
|
|
|
|
|
graphicsVulkan->ConfigureEvent(BaseEventId + FSR3PluginEvent::eExecute, &eventConfig); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -149,9 +105,12 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev |
|
|
} |
|
|
} |
|
|
case kUnityGfxDeviceEventShutdown: |
|
|
case kUnityGfxDeviceEventShutdown: |
|
|
{ |
|
|
{ |
|
|
s_GraphicsVulkan = nullptr; |
|
|
|
|
|
s_GraphicsD3D12 = nullptr; |
|
|
|
|
|
s_GraphicsD3D11 = nullptr; |
|
|
|
|
|
|
|
|
if (s_Upscaler != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
delete s_Upscaler; |
|
|
|
|
|
s_Upscaler = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
s_RendererType = kUnityGfxRendererNull; |
|
|
s_RendererType = kUnityGfxRendererNull; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
@ -166,222 +125,22 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint32_t AllocateFeatureSlot() |
|
|
|
|
|
{ |
|
|
|
|
|
if (s_FeatureSlots.empty()) |
|
|
|
|
|
{ |
|
|
|
|
|
// 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; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Reallocate an existing free slot
|
|
|
|
|
|
uint32_t featureSlot = s_FeatureSlots.front(); |
|
|
|
|
|
s_FeatureSlots.pop(); |
|
|
|
|
|
return featureSlot; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void FreeFeatureSlot(uint32_t featureSlot) |
|
|
|
|
|
{ |
|
|
|
|
|
// Prevent duplicate free slots
|
|
|
|
|
|
auto& slots = s_FeatureSlots._Get_container(); |
|
|
|
|
|
if (std::find(slots.begin(), slots.end(), featureSlot) != slots.end()) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
s_FeatureSlots.push(featureSlot); |
|
|
|
|
|
memset(&s_Features[featureSlot], 0, sizeof(FSR3Feature)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool LoadFidelityFXLibrary(_In_ LPCWSTR lpLibFileName) |
|
|
|
|
|
{ |
|
|
|
|
|
s_ffxModule = LoadLibrary(lpLibFileName); |
|
|
|
|
|
if (s_ffxModule == nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
UNITY_LOG_ERROR(s_Log, "Failed to load FidelityFX library!"); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ffxLoadFunctions(&s_ffxFunctions, s_ffxModule); |
|
|
|
|
|
if (s_ffxFunctions.CreateContext == nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
UNITY_LOG_ERROR(s_Log, "Failed to load FidelityFX library functions!"); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check that we can actually create an upscaler with this library
|
|
|
|
|
|
ffx::QueryDescGetVersions versionQuery{}; |
|
|
|
|
|
versionQuery.createDescType = FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE; |
|
|
|
|
|
versionQuery.device = s_DX12BackendDesc.device; |
|
|
|
|
|
uint64_t versionCount = 0; |
|
|
|
|
|
versionQuery.outputCount = &versionCount; |
|
|
|
|
|
s_ffxFunctions.Query(nullptr, &versionQuery.header); |
|
|
|
|
|
|
|
|
|
|
|
if (versionCount == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
UNITY_LOG_ERROR(s_Log, "Failed to load FidelityFX upscaler versions!"); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Obtain the default upscaler version and log its name
|
|
|
|
|
|
std::vector<const char*> versionNames; |
|
|
|
|
|
std::vector<uint64_t> versionIds; |
|
|
|
|
|
versionIds.resize(versionCount); |
|
|
|
|
|
versionNames.resize(versionCount); |
|
|
|
|
|
versionQuery.versionIds = versionIds.data(); |
|
|
|
|
|
versionQuery.versionNames = versionNames.data(); |
|
|
|
|
|
s_ffxFunctions.Query(nullptr, &versionQuery.header); |
|
|
|
|
|
|
|
|
|
|
|
std::stringstream ss; |
|
|
|
|
|
ss << "Loaded FidelityFX upscaler: FSR " << versionNames[0]; |
|
|
|
|
|
UNITY_LOG(s_Log, ss.str().c_str()); |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static PFN_vkVoidFunction GetVulkanDeviceProcAddr(VkDevice device, const char* pName) |
|
|
|
|
|
{ |
|
|
|
|
|
UnityVulkanInstance instance = s_GraphicsVulkan->Instance(); |
|
|
|
|
|
return instance.getInstanceProcAddr(instance.instance, pName); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi() |
|
|
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi() |
|
|
{ |
|
|
{ |
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
else if (s_GraphicsD3D12 != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
ID3D12Device* device = s_GraphicsD3D12->GetDevice(); |
|
|
|
|
|
if (device == nullptr) |
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
s_DX12BackendDesc.device = device; |
|
|
|
|
|
s_FrameFenceEventHandle = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS); |
|
|
|
|
|
|
|
|
|
|
|
return LoadFidelityFXLibrary(TEXT("amd_fidelityfx_dx12.dll")); |
|
|
|
|
|
} |
|
|
|
|
|
else if (s_GraphicsVulkan != nullptr) |
|
|
|
|
|
|
|
|
if (s_Upscaler != nullptr) |
|
|
{ |
|
|
{ |
|
|
UnityVulkanInstance instance = s_GraphicsVulkan->Instance(); |
|
|
|
|
|
if (instance.device == nullptr) |
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
s_VulkanBackendDesc.vkDevice = instance.device; |
|
|
|
|
|
s_VulkanBackendDesc.vkPhysicalDevice = instance.physicalDevice; |
|
|
|
|
|
s_VulkanBackendDesc.vkDeviceProcAddr = &GetVulkanDeviceProcAddr; |
|
|
|
|
|
|
|
|
|
|
|
return LoadFidelityFXLibrary(TEXT("amd_fidelityfx_vk.dll")); |
|
|
|
|
|
|
|
|
return s_Upscaler->Init(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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.upscalingContext == nullptr && !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 (dispatchFrameValue > frameFence->GetCompletedValue()) |
|
|
|
|
|
{ |
|
|
|
|
|
frameFence->SetEventOnCompletion(dispatchFrameValue, s_FrameFenceEventHandle); |
|
|
|
|
|
WaitForSingleObjectEx(s_FrameFenceEventHandle, INFINITE, false); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else if (s_GraphicsVulkan != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
UnityVulkanRecordingState state; |
|
|
|
|
|
s_GraphicsVulkan->CommandRecordingState(&state, kUnityVulkanGraphicsQueueAccess_DontCare); |
|
|
|
|
|
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]; |
|
|
|
|
|
if (feature.upscalingContext != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
s_ffxFunctions.DestroyContext(&feature.upscalingContext, nullptr); |
|
|
|
|
|
FreeFeatureSlot(featureSlot); |
|
|
|
|
|
} |
|
|
|
|
|
else if (feature.isValid) |
|
|
|
|
|
{ |
|
|
|
|
|
ffxFsr2ContextDestroy(&feature.fsr2Context); |
|
|
|
|
|
FreeFeatureSlot(featureSlot); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi() |
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi() |
|
|
{ |
|
|
{ |
|
|
size_t numFeatures = 0; |
|
|
|
|
|
|
|
|
if (s_Upscaler != nullptr) |
|
|
{ |
|
|
{ |
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
numFeatures = s_Features.size(); |
|
|
|
|
|
|
|
|
s_Upscaler->Shutdown(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (uint32_t slot = 0; slot < numFeatures; ++slot) |
|
|
|
|
|
{ |
|
|
|
|
|
DestroyFeature(slot); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
|
|
|
|
if (s_ffxModule != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
FreeLibrary(s_ffxModule); |
|
|
|
|
|
s_ffxModule = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (s_Fsr2Interface.scratchBuffer != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
free(s_Fsr2Interface.scratchBuffer); |
|
|
|
|
|
s_Fsr2Interface.scratchBuffer = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (s_FrameFenceEventHandle != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
CloseHandle(s_FrameFenceEventHandle); |
|
|
|
|
|
s_FrameFenceEventHandle = 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() |
|
|
extern "C" uint32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetDeviceVersion() |
|
|
@ -401,8 +160,12 @@ extern "C" UnityRenderingEventAndData UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API |
|
|
|
|
|
|
|
|
extern "C" uint32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_CreateFeatureSlot() |
|
|
extern "C" uint32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_CreateFeatureSlot() |
|
|
{ |
|
|
{ |
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
return AllocateFeatureSlot(); |
|
|
|
|
|
|
|
|
if (s_Upscaler != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
s_Upscaler->CreateFeatureSlot(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return UINT32_MAX; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
extern "C" float UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetUpscaleRatioFromQualityMode(FSR3Quality qualityMode) |
|
|
extern "C" float UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetUpscaleRatioFromQualityMode(FSR3Quality qualityMode) |
|
|
@ -438,29 +201,10 @@ extern "C" int32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetBaseEvent |
|
|
return BaseEventId; |
|
|
return BaseEventId; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static FfxApiResource GetVulkanTextureResource(UnityVulkanInstance& instance, FSR3TextureDesc& texture, FfxApiResourceState state = FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ) |
|
|
|
|
|
{ |
|
|
|
|
|
FfxApiResourceDescription desc{}; |
|
|
|
|
|
|
|
|
|
|
|
if (texture.image != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
desc.type = FFX_API_RESOURCE_TYPE_TEXTURE2D; |
|
|
|
|
|
desc.format = ffxApiGetSurfaceFormatVK((VkFormat)texture.format); |
|
|
|
|
|
desc.width = texture.width; |
|
|
|
|
|
desc.height = texture.height; |
|
|
|
|
|
desc.depth = 1; |
|
|
|
|
|
desc.mipCount = 1; |
|
|
|
|
|
desc.flags = FFX_API_RESOURCE_FLAGS_NONE; |
|
|
|
|
|
desc.usage = state == FFX_API_RESOURCE_STATE_UNORDERED_ACCESS ? FFX_API_RESOURCE_USAGE_UAV : FFX_API_RESOURCE_USAGE_READ_ONLY; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ffxApiGetResourceVK((void*)texture.image, desc, state); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Plugin function to handle a specific rendering event
|
|
|
// Plugin function to handle a specific rendering event
|
|
|
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
{ |
|
|
{ |
|
|
if (s_DX11Device == nullptr && s_DX12BackendDesc.device == nullptr && s_VulkanBackendDesc.vkDevice == nullptr) |
|
|
|
|
|
|
|
|
if (s_Upscaler == nullptr) |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
// User rendering code
|
|
|
// User rendering code
|
|
|
@ -468,193 +212,26 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
{ |
|
|
{ |
|
|
case BaseEventId + FSR3PluginEvent::eDestroyFeature: |
|
|
case BaseEventId + FSR3PluginEvent::eDestroyFeature: |
|
|
{ |
|
|
{ |
|
|
uint32_t featureSlot = (uint32_t)(int64_t)data; |
|
|
|
|
|
if (featureSlot < 0 || featureSlot >= s_Features.size()) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
DestroyFeature(featureSlot); |
|
|
|
|
|
|
|
|
uint32_t featureSlot = (uint32_t)(intptr_t)data; |
|
|
|
|
|
s_Upscaler->DestroyFeature(featureSlot); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case BaseEventId + FSR3PluginEvent::eExecute: |
|
|
case BaseEventId + FSR3PluginEvent::eExecute: |
|
|
{ |
|
|
{ |
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
|
|
|
|
auto* params = (FSR3CommandExecutionData*)data; |
|
|
|
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size()) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
auto& feature = s_Features[params->featureSlot]; |
|
|
|
|
|
if (feature.upscalingContext == nullptr && !feature.isValid) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
if (dispatchDescription.reactive.resource == nullptr) |
|
|
|
|
|
dispatchDescription.reactive = ffxGetResourceDX11(&feature.fsr2Context, (ID3D11Resource*)feature.textureTable.biasColorMask.image); |
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
{ |
|
|
|
|
|
UnityGraphicsD3D12RecordingState state; |
|
|
|
|
|
s_GraphicsD3D12->CommandRecordingState(&state); |
|
|
|
|
|
dispatchUpscale.commandList = 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(); |
|
|
|
|
|
|
|
|
|
|
|
dispatchUpscale.color = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.colorInput.image, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); |
|
|
|
|
|
dispatchUpscale.depth = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.depth.image, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); |
|
|
|
|
|
dispatchUpscale.motionVectors = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.motionVectors.image, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); |
|
|
|
|
|
dispatchUpscale.exposure = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.exposureTexture.image, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); |
|
|
|
|
|
dispatchUpscale.reactive = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.reactiveMask.image, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); |
|
|
|
|
|
dispatchUpscale.transparencyAndComposition = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.transparencyMask.image, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); |
|
|
|
|
|
dispatchUpscale.output = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.colorOutput.image, FFX_API_RESOURCE_STATE_UNORDERED_ACCESS); |
|
|
|
|
|
|
|
|
|
|
|
if (dispatchUpscale.reactive.resource == nullptr) |
|
|
|
|
|
dispatchUpscale.reactive = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.biasColorMask.image, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); |
|
|
|
|
|
} |
|
|
|
|
|
else if (s_GraphicsVulkan != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
UnityVulkanRecordingState state; |
|
|
|
|
|
s_GraphicsVulkan->CommandRecordingState(&state, kUnityVulkanGraphicsQueueAccess_DontCare); |
|
|
|
|
|
dispatchUpscale.commandList = 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(); |
|
|
|
|
|
dispatchUpscale.color = GetVulkanTextureResource(instance, feature.textureTable.colorInput); |
|
|
|
|
|
dispatchUpscale.depth = GetVulkanTextureResource(instance, feature.textureTable.depth); |
|
|
|
|
|
dispatchUpscale.motionVectors = GetVulkanTextureResource(instance, feature.textureTable.motionVectors); |
|
|
|
|
|
dispatchUpscale.exposure = GetVulkanTextureResource(instance, feature.textureTable.exposureTexture); |
|
|
|
|
|
dispatchUpscale.reactive = GetVulkanTextureResource(instance, feature.textureTable.reactiveMask); |
|
|
|
|
|
dispatchUpscale.transparencyAndComposition = GetVulkanTextureResource(instance, feature.textureTable.transparencyMask); |
|
|
|
|
|
dispatchUpscale.output = GetVulkanTextureResource(instance, feature.textureTable.colorOutput, FFX_API_RESOURCE_STATE_UNORDERED_ACCESS); |
|
|
|
|
|
|
|
|
|
|
|
if (dispatchUpscale.reactive.resource == nullptr) |
|
|
|
|
|
dispatchUpscale.reactive = GetVulkanTextureResource(instance, feature.textureTable.biasColorMask); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
dispatchUpscale.jitterOffset.x = params->jitterOffsetX; |
|
|
|
|
|
dispatchUpscale.jitterOffset.y = params->jitterOffsetY; |
|
|
|
|
|
dispatchUpscale.motionVectorScale.x = params->MVScaleX; |
|
|
|
|
|
dispatchUpscale.motionVectorScale.y = params->MVScaleY; |
|
|
|
|
|
dispatchUpscale.reset = params->reset; |
|
|
|
|
|
dispatchUpscale.enableSharpening = params->enableSharpening; |
|
|
|
|
|
dispatchUpscale.sharpness = params->sharpness; |
|
|
|
|
|
dispatchUpscale.frameTimeDelta = params->frameTimeDelta; |
|
|
|
|
|
dispatchUpscale.preExposure = params->preExposure; |
|
|
|
|
|
dispatchUpscale.renderSize.width = params->renderSizeWidth; |
|
|
|
|
|
dispatchUpscale.renderSize.height = params->renderSizeHeight; |
|
|
|
|
|
dispatchUpscale.upscaleSize.width = feature.upscaleSizeWidth; |
|
|
|
|
|
dispatchUpscale.upscaleSize.height = feature.upscaleSizeHeight; |
|
|
|
|
|
dispatchUpscale.cameraFovAngleVertical = params->cameraFovAngleVertical; |
|
|
|
|
|
|
|
|
|
|
|
if (feature.flags & FFX_UPSCALE_ENABLE_DEPTH_INVERTED) |
|
|
|
|
|
{ |
|
|
|
|
|
dispatchUpscale.cameraFar = params->cameraNear; |
|
|
|
|
|
dispatchUpscale.cameraNear = params->cameraFar; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
dispatchUpscale.cameraFar = params->cameraFar; |
|
|
|
|
|
dispatchUpscale.cameraNear = params->cameraNear; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s_ffxFunctions.Dispatch(&feature.upscalingContext, &dispatchUpscale.header); |
|
|
|
|
|
|
|
|
auto* execData = (FSR3CommandExecutionData*)data; |
|
|
|
|
|
s_Upscaler->Execute(execData); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case BaseEventId + FSR3PluginEvent::ePostExecute: |
|
|
case BaseEventId + FSR3PluginEvent::ePostExecute: |
|
|
{ |
|
|
{ |
|
|
auto* params = (FSR3CommandExecutionData*)data; |
|
|
|
|
|
|
|
|
auto* execData = (FSR3CommandExecutionData*)data; |
|
|
|
|
|
s_Upscaler->PostExecute(execData); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case BaseEventId + FSR3PluginEvent::eInit: |
|
|
case BaseEventId + FSR3PluginEvent::eInit: |
|
|
{ |
|
|
{ |
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
|
|
|
|
auto* params = (FSR3CommandInitializationData*)data; |
|
|
|
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size()) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
auto& feature = s_Features[params->featureSlot]; |
|
|
|
|
|
feature.upscaleSizeWidth = params->displaySizeWidth; |
|
|
|
|
|
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 }; |
|
|
|
|
|
createUpscaling.flags = params->flags; |
|
|
|
|
|
|
|
|
|
|
|
if (s_GraphicsD3D12 != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
s_ffxFunctions.CreateContext(&feature.upscalingContext, ffx::LinkHeaders(createUpscaling.header, s_DX12BackendDesc.header), nullptr); |
|
|
|
|
|
} |
|
|
|
|
|
else if (s_GraphicsVulkan != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
s_ffxFunctions.CreateContext(&feature.upscalingContext, ffx::LinkHeaders(createUpscaling.header, s_VulkanBackendDesc.header), nullptr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
auto* initData = (FSR3CommandInitializationData*)data; |
|
|
|
|
|
s_Upscaler->InitFeature(initData); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -662,7 +239,8 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) |
|
|
|
|
|
|
|
|
static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data) |
|
|
static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data) |
|
|
{ |
|
|
{ |
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex); |
|
|
|
|
|
|
|
|
if (s_Upscaler == nullptr) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
auto* params = (UnityRenderingExtTextureUpdateParamsV2*)data; |
|
|
auto* params = (UnityRenderingExtTextureUpdateParamsV2*)data; |
|
|
|
|
|
|
|
|
@ -671,11 +249,6 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data) |
|
|
uint32_t textureSlot = (params->userData >> 1) & 0x7FFF; |
|
|
uint32_t textureSlot = (params->userData >> 1) & 0x7FFF; |
|
|
uint32_t clearTextureTable = params->userData & 0x1; |
|
|
uint32_t clearTextureTable = params->userData & 0x1; |
|
|
|
|
|
|
|
|
if (featureSlot < 0 || featureSlot >= s_Features.size()) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
auto& feature = s_Features[featureSlot]; |
|
|
|
|
|
|
|
|
|
|
|
// User rendering code
|
|
|
// User rendering code
|
|
|
switch (eventID) |
|
|
switch (eventID) |
|
|
{ |
|
|
{ |
|
|
@ -683,44 +256,13 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data) |
|
|
{ |
|
|
{ |
|
|
if (clearTextureTable) |
|
|
if (clearTextureTable) |
|
|
{ |
|
|
{ |
|
|
memset(&feature.textureTable, 0, sizeof(FSR3TextureTable)); |
|
|
|
|
|
|
|
|
s_Upscaler->ClearTextureTable(featureSlot); |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case kUnityRenderingExtEventUpdateTextureEndV2: |
|
|
case kUnityRenderingExtEventUpdateTextureEndV2: |
|
|
{ |
|
|
{ |
|
|
// We organized the texture table struct to be ordered the same as the texture slot enum
|
|
|
|
|
|
// 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); |
|
|
|
|
|
} |
|
|
|
|
|
else if (s_GraphicsD3D12 != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
textureDesc->image = (intptr_t)s_GraphicsD3D12->TextureFromNativeTexture((UnityTextureID)params->textureID); |
|
|
|
|
|
} |
|
|
|
|
|
else if (s_GraphicsVulkan != nullptr) |
|
|
|
|
|
{ |
|
|
|
|
|
VkAccessFlags accessFlags = (textureSlot == FSR3Texture::tColorOutput) ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_SHADER_READ_BIT; |
|
|
|
|
|
|
|
|
|
|
|
UnityVulkanImage image; |
|
|
|
|
|
if (s_GraphicsVulkan->AccessTextureByID((UnityTextureID)params->textureID, UnityVulkanWholeImage, |
|
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, accessFlags, |
|
|
|
|
|
kUnityVulkanResourceAccess_PipelineBarrier, &image)) |
|
|
|
|
|
{ |
|
|
|
|
|
textureDesc->image = (intptr_t)image.image; |
|
|
|
|
|
textureDesc->width = params->width; |
|
|
|
|
|
textureDesc->height = params->height; |
|
|
|
|
|
textureDesc->format = (uint32_t)image.format; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
textureDesc->image = 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s_Upscaler->SetTextureSlot(featureSlot, textureSlot, (UnityTextureID)params->textureID, params->width, params->height); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|