Browse Source

Added Vulkan implementation based on the upgradable FFX API. Works, but FFX doesn't like it when I link to both DX12 and Vulkan libraries, always picking the first over the other. Means Vulkan will break if DX12 is the first library in the linker list, and vice versa.

master
Nico de Poel 11 months ago
parent
commit
b132ce5a2a
  1. 155
      FSR3UnityPlugin.cpp
  2. 25
      FSR3UnityTypes.h

155
FSR3UnityPlugin.cpp

@ -26,6 +26,7 @@ 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 IUnityGraphicsD3D12v7* s_GraphicsD3D12 = 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);
@ -47,7 +48,8 @@ static std::vector<FSR3Feature> 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 ffx::CreateBackendDX12Desc s_BackendDesc{};
static ffx::CreateBackendDX12Desc s_DX12BackendDesc{};
static ffx::CreateBackendVKDesc s_VulkanBackendDesc{};
// 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)
@ -76,20 +78,35 @@ static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType ev
case kUnityGfxDeviceEventInitialize: case kUnityGfxDeviceEventInitialize:
{ {
s_RendererType = s_Graphics->GetRenderer(); s_RendererType = s_Graphics->GetRenderer();
if (s_RendererType != kUnityGfxRendererD3D12)
return;
switch (s_RendererType)
{
case kUnityGfxRendererD3D12:
{
s_GraphicsD3D12 = s_UnityInterfaces->Get<IUnityGraphicsD3D12v7>(); s_GraphicsD3D12 = s_UnityInterfaces->Get<IUnityGraphicsD3D12v7>();
if (s_GraphicsD3D12 == nullptr) if (s_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;
} }
break;
}
case kUnityGfxRendererVulkan:
{
s_GraphicsVulkan = s_UnityInterfaces->Get<IUnityGraphicsVulkan>();
if (s_GraphicsVulkan == nullptr)
{
UNITY_LOG_ERROR(s_Log, "Could not obtain Vulkan Graphics interface!");
return;
}
break;
}
}
break; break;
} }
case kUnityGfxDeviceEventShutdown: case kUnityGfxDeviceEventShutdown:
{ {
s_GraphicsVulkan = nullptr;
s_GraphicsD3D12 = nullptr; s_GraphicsD3D12 = nullptr;
s_RendererType = kUnityGfxRendererNull; s_RendererType = kUnityGfxRendererNull;
break; break;
@ -133,17 +150,36 @@ static void FreeFeatureSlot(uint32_t featureSlot)
memset(&s_Features[featureSlot], 0, sizeof(FSR3Feature)); memset(&s_Features[featureSlot], 0, sizeof(FSR3Feature));
} }
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi()
static PFN_vkVoidFunction GetVulkanDeviceProcAddr(VkDevice device, const char* pName)
{ {
if (s_GraphicsD3D12 == nullptr)
return false;
UnityVulkanInstance instance = s_GraphicsVulkan->Instance();
return instance.getInstanceProcAddr(instance.instance, pName);
}
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi()
{
if (s_GraphicsD3D12 != nullptr)
{
ID3D12Device* device = s_GraphicsD3D12->GetDevice(); ID3D12Device* device = s_GraphicsD3D12->GetDevice();
if (device == nullptr) if (device == nullptr)
return false; return false;
s_BackendDesc.device = device;
s_DX12BackendDesc.device = device;
return true;
}
else if (s_GraphicsVulkan != 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 true; return true;
}
return false;
} }
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi() extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi()
@ -158,7 +194,11 @@ extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi()
} }
} }
s_BackendDesc.device = nullptr;
s_VulkanBackendDesc.vkDevice = nullptr;
s_VulkanBackendDesc.vkPhysicalDevice = nullptr;
s_VulkanBackendDesc.vkDeviceProcAddr = nullptr;
s_DX12BackendDesc.device = 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()
@ -214,12 +254,28 @@ 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_GraphicsD3D12 == nullptr || s_BackendDesc.device == nullptr)
return;
// User rendering code // User rendering code
switch (eventID) switch (eventID)
{ {
@ -245,19 +301,37 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
auto& feature = s_Features[params->featureSlot]; auto& feature = s_Features[params->featureSlot];
ffx::DispatchDescUpscale dispatchUpscale{};
if (s_GraphicsD3D12 != nullptr)
{
UnityGraphicsD3D12RecordingState state; UnityGraphicsD3D12RecordingState state;
s_GraphicsD3D12->CommandRecordingState(&state); s_GraphicsD3D12->CommandRecordingState(&state);
ffx::DispatchDescUpscale dispatchUpscale{};
dispatchUpscale.commandList = state.commandList; dispatchUpscale.commandList = state.commandList;
dispatchUpscale.color = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.colorInput, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ);
dispatchUpscale.depth = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.depth, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ);
dispatchUpscale.motionVectors = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.motionVectors, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ);
dispatchUpscale.exposure = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.exposureTexture, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ);
dispatchUpscale.reactive = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.reactiveMask, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ);
dispatchUpscale.transparencyAndComposition = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.transparencyMask, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ);
dispatchUpscale.output = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.colorOutput, FFX_API_RESOURCE_STATE_UNORDERED_ACCESS);
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);
}
else if (s_GraphicsVulkan != nullptr)
{
UnityVulkanRecordingState state;
s_GraphicsVulkan->CommandRecordingState(&state, kUnityVulkanGraphicsQueueAccess_DontCare);
dispatchUpscale.commandList = state.commandBuffer;
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);
}
dispatchUpscale.jitterOffset.x = params->jitterOffsetX; dispatchUpscale.jitterOffset.x = params->jitterOffsetX;
dispatchUpscale.jitterOffset.y = params->jitterOffsetY; dispatchUpscale.jitterOffset.y = params->jitterOffsetY;
@ -309,7 +383,14 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
createUpscaling.maxRenderSize = { params->maxRenderSizeWidth, params->maxRenderSizeHeight }; createUpscaling.maxRenderSize = { params->maxRenderSizeWidth, params->maxRenderSizeHeight };
createUpscaling.flags = params->flags; createUpscaling.flags = params->flags;
ffx::CreateContext(feature.upscalingContext, nullptr, createUpscaling, s_BackendDesc);
if (s_GraphicsD3D12 != nullptr)
{
ffx::CreateContext(feature.upscalingContext, nullptr, createUpscaling, s_DX12BackendDesc);
}
else if (s_GraphicsVulkan != nullptr)
{
ffx::CreateContext(feature.upscalingContext, nullptr, createUpscaling, s_VulkanBackendDesc);
}
break; break;
} }
} }
@ -317,9 +398,6 @@ 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)
{ {
if (s_GraphicsD3D12 == nullptr)
return;
auto* params = (UnityRenderingExtTextureUpdateParamsV2*)data; auto* params = (UnityRenderingExtTextureUpdateParamsV2*)data;
// userData = (featureId & (int) ushort.MaxValue) << 16 | (textureSlot & (int) short.MaxValue) << 1 | (clearTextureTable ? 1 : 0); // userData = (featureId & (int) ushort.MaxValue) << 16 | (textureSlot & (int) short.MaxValue) << 1 | (clearTextureTable ? 1 : 0);
@ -347,7 +425,32 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data)
{ {
// We organized the texture table struct to be ordered the same as the texture slot enum // 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 // This way we can use the texture slot value simply as a pointer offset into the texture table
*(((intptr_t*)&feature.textureTable) + textureSlot) = (intptr_t)s_GraphicsD3D12->TextureFromNativeTexture((UnityTextureID)params->textureID);
FSR3TextureDesc* textureDesc = ((FSR3TextureDesc*)&feature.textureTable) + textureSlot;
if (s_GraphicsD3D12 != nullptr)
{
textureDesc->image = (intptr_t)s_GraphicsD3D12->TextureFromNativeTexture((UnityTextureID)params->textureID);
}
else if (s_GraphicsVulkan != nullptr)
{
VkAccessFlags accessFlags = (textureSlot == FSR3Textures::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;
}
}
break; break;
} }
} }

25
FSR3UnityTypes.h

@ -59,16 +59,25 @@ struct FSR3CommandExecutionData
uint32_t featureSlot; uint32_t featureSlot;
}; };
struct FSR3TextureDesc
{
intptr_t image;
uint32_t width;
uint32_t height;
uint32_t format;
};
struct FSR3TextureTable struct FSR3TextureTable
{ {
intptr_t colorInput;
intptr_t colorOutput;
intptr_t depth;
intptr_t motionVectors;
intptr_t transparencyMask;
intptr_t exposureTexture;
intptr_t reactiveMask;
intptr_t biasColorMask;
FSR3TextureDesc colorInput;
FSR3TextureDesc colorOutput;
FSR3TextureDesc depth;
FSR3TextureDesc motionVectors;
FSR3TextureDesc transparencyMask;
FSR3TextureDesc exposureTexture;
FSR3TextureDesc reactiveMask;
FSR3TextureDesc biasColorMask;
uint32_t featureSlot; uint32_t featureSlot;
}; };
Loading…
Cancel
Save