You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

250 lines
7.1 KiB

#include <stdint.h>
#include <vector>
#include <queue>
#include <mutex>
#include "UnityPluginAPI/IUnityInterface.h"
#include "UnityPluginAPI/IUnityLog.h"
#include "UnityPluginAPI/IUnityGraphics.h"
#include "UnityPluginAPI/IUnityRenderingExtensions.h"
#include <d3d12.h>
#include <dxgi.h>
#include "UnityPluginAPI/IUnityGraphicsD3D12.h"
#include "ffx_api/ffx_upscale.hpp"
#include "ffx_api/dx12/ffx_api_dx12.hpp"
#include "FSR3UnityTypes.h"
static const int32_t BaseEventId = 0;
static IUnityInterfaces* s_UnityInterfaces = nullptr;
static IUnityLog* s_Log = nullptr;
static IUnityGraphics* s_Graphics = nullptr;
static IUnityGraphicsD3D12v7* s_GraphicsD3D12 = nullptr;
static UnityGfxRenderer s_RendererType = kUnityGfxRendererNull;
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType);
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data);
static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data);
struct FSR3Feature
{
ffx::Context upscalingContext;
FSR3TextureTable textureTable;
};
static std::vector<FSR3Feature> s_Features;
static std::queue<uint32_t> s_FeatureSlots;
static std::mutex s_FeatureMutex;
static ffx::CreateBackendDX12Desc s_BackendDesc{};
// Unity plugin load event
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
s_UnityInterfaces = unityInterfaces;
s_Log = unityInterfaces->Get<IUnityLog>();
s_Graphics = unityInterfaces->Get<IUnityGraphics>();
s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
// Run OnGraphicsDeviceEvent(initialize) manually on plugin load
// to not miss the event in case the graphics device is already initialized
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
// Unity plugin unload event
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
}
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
{
switch (eventType)
{
case kUnityGfxDeviceEventInitialize:
{
s_RendererType = s_Graphics->GetRenderer();
if (s_RendererType != kUnityGfxRendererD3D12)
return;
s_GraphicsD3D12 = s_UnityInterfaces->Get<IUnityGraphicsD3D12v7>();
if (s_GraphicsD3D12 == nullptr)
{
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D12 Graphics interface!");
return;
}
break;
}
case kUnityGfxDeviceEventShutdown:
{
s_GraphicsD3D12 = nullptr;
s_RendererType = kUnityGfxRendererNull;
break;
}
case kUnityGfxDeviceEventBeforeReset:
{
break;
}
case kUnityGfxDeviceEventAfterReset:
{
break;
}
};
}
// Thread-safe allocation of FSR3 feature slot
static uint32_t AllocateFeatureSlot()
{
std::lock_guard<std::mutex> lock(s_FeatureMutex);
if (s_FeatureSlots.empty())
{
uint32_t featureSlot = (uint32_t)s_Features.size();
s_Features.push_back(std::move(FSR3Feature()));
return featureSlot;
}
uint32_t featureSlot = s_FeatureSlots.front();
s_FeatureSlots.pop();
return featureSlot;
}
// Thread-safe freeing and clearing of FSR3 feature slot
static void FreeFeatureSlot(uint32_t featureSlot)
{
std::lock_guard<std::mutex> lock(s_FeatureMutex);
s_FeatureSlots.push(featureSlot);
memset(&s_Features[featureSlot], 0, sizeof(FSR3Feature));
}
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi()
{
if (s_GraphicsD3D12 == nullptr)
return false;
ID3D12Device* device = s_GraphicsD3D12->GetDevice();
if (device == nullptr)
return false;
s_BackendDesc.device = device;
return true;
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi()
{
// TODO: destroy any remaining FSR3Contexts?
s_BackendDesc.device = nullptr;
}
extern "C" uint32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetDeviceVersion()
{
return 0x0u;
}
extern "C" UnityRenderingEventAndData UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetRenderEventCallback()
{
return OnRenderEventAndData;
}
extern "C" UnityRenderingEventAndData UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetSetTextureEventCallback()
{
return OnSetTextureEvent;
}
extern "C" uint32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_CreateFeatureSlot()
{
return AllocateFeatureSlot();
}
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetRenderResolutionFromQualityMode(FSR3Quality qualityMode, uint32_t displayWidth, uint32_t displayHeight, uint32_t* renderWidth, uint32_t* renderHeight)
{
// TODO: implement
return false;
}
extern "C" float UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetUpscaleRatioFromQualityMode(FSR3Quality qualityMode)
{
// TODO: implement
return 1.0f;
}
extern "C" int32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetBaseEventId()
{
return BaseEventId;
}
// Plugin function to handle a specific rendering event
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
{
// User rendering code
switch (eventID)
{
case BaseEventId + FSR3PluginEvent::eDestroyFeature:
{
uint32_t featureSlot = (uint32_t)(int64_t)data;
// TODO: destroy FSR3Context at feature slot index
FreeFeatureSlot(featureSlot);
break;
}
case BaseEventId + FSR3PluginEvent::eExecute:
{
auto* params = (FSR3CommandExecutionData*)data;
break;
}
case BaseEventId + FSR3PluginEvent::ePostExecute:
{
auto* params = (FSR3CommandExecutionData*)data;
break;
}
case BaseEventId + FSR3PluginEvent::eInit:
{
if (s_BackendDesc.device == nullptr)
return;
auto* params = (FSR3CommandInitializationData*)data;
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size())
return;
auto& feature = s_Features[params->featureSlot];
ffx::CreateContextDescUpscale createUpscaling;
createUpscaling.maxUpscaleSize = { params->displaySizeWidth, params->displaySizeHeight };
createUpscaling.maxRenderSize = { params->maxRenderSizeWidth, params->maxRenderSizeHeight };
createUpscaling.flags = params->flags;
ffx::CreateContext(feature.upscalingContext, nullptr, createUpscaling, s_BackendDesc);
break;
}
}
}
static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data)
{
auto* params = (UnityRenderingExtTextureUpdateParamsV2*)data;
uint32_t featureSlot = (params->userData >> 16) & 0xFFFF;
uint32_t textureSlot = (params->userData >> 1) & 0x7FFF; // TODO: could just use as numeric index to calculate a pointer offset
uint32_t clearTextureTable = params->userData & 0x1;
// TODO: should be able to just cast params->textureID directly to a D3D12Resource*
// User rendering code
switch (eventID)
{
case kUnityRenderingExtEventUpdateTextureBeginV2:
{
break;
}
case kUnityRenderingExtEventUpdateTextureEndV2:
{
break;
}
}
}