diff --git a/FSR3UnityPlugin.cpp b/FSR3UnityPlugin.cpp
index 17a44cd..5c2c378 100644
--- a/FSR3UnityPlugin.cpp
+++ b/FSR3UnityPlugin.cpp
@@ -703,7 +703,7 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data)
}
else if (s_GraphicsVulkan != nullptr)
{
- VkAccessFlags accessFlags = (textureSlot == FSR3Textures::tColorOutput) ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_SHADER_READ_BIT;
+ 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,
diff --git a/FSR3UnityPlugin.vcxproj b/FSR3UnityPlugin.vcxproj
index 9227741..2db3e3b 100644
--- a/FSR3UnityPlugin.vcxproj
+++ b/FSR3UnityPlugin.vcxproj
@@ -153,11 +153,13 @@
+
+
diff --git a/FSR3UnityPlugin.vcxproj.filters b/FSR3UnityPlugin.vcxproj.filters
index 5f054da..5f71fbd 100644
--- a/FSR3UnityPlugin.vcxproj.filters
+++ b/FSR3UnityPlugin.vcxproj.filters
@@ -21,6 +21,9 @@
Source Files
+
+ Source Files
+
@@ -35,5 +38,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/FSR3UnityTypes.h b/FSR3UnityTypes.h
index 0e64eca..4f0a463 100644
--- a/FSR3UnityTypes.h
+++ b/FSR3UnityTypes.h
@@ -16,7 +16,7 @@ enum FSR3Quality: int32_t
qUltraPerformance
};
-enum FSR3Textures: int32_t
+enum FSR3Texture: int32_t
{
tColorInput,
tColorOutput,
diff --git a/FSR3Upscaler_DX12.cpp b/FSR3Upscaler_DX12.cpp
index 6dfd6d8..ce4e790 100644
--- a/FSR3Upscaler_DX12.cpp
+++ b/FSR3Upscaler_DX12.cpp
@@ -25,9 +25,9 @@ bool FSR3Upscaler_DX12::InitFeature(FSR3Feature_FFX& feature, const FSR3CommandI
return FFX_API_RETURN_OK == m_ffxFunctions.CreateContext(&feature.upscalingContext, ffx::LinkHeaders(createUpscaling.header, m_DX12BackendDesc.header), nullptr);
}
-void FSR3Upscaler_DX12::SetTexture(FSR3TextureDesc* textureDesc, UnityTextureID textureID)
+void FSR3Upscaler_DX12::SetTexture(FSR3Texture textureType, UnityTextureID textureID, const UnityRenderingExtTextureUpdateParamsV2* params, FSR3TextureDesc* outTextureDesc)
{
- textureDesc->image = (intptr_t)m_GraphicsDevice->TextureFromNativeTexture(textureID);
+ outTextureDesc->image = (intptr_t)m_GraphicsDevice->TextureFromNativeTexture(textureID);
}
void FSR3Upscaler_DX12::Execute(FSR3Feature_FFX& feature, const FSR3CommandExecutionData* execData)
@@ -81,11 +81,6 @@ void FSR3Upscaler_DX12::Execute(FSR3Feature_FFX& feature, const FSR3CommandExecu
m_ffxFunctions.Dispatch(&feature.upscalingContext, &dispatchUpscale.header);
}
-bool FSR3Upscaler_DX12::IsValidFeature(FSR3Feature_FFX& feature)
-{
- return feature.upscalingContext != nullptr;
-}
-
void FSR3Upscaler_DX12::AwaitEndOfFrame(uint64_t frameValue)
{
// 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.
@@ -97,11 +92,6 @@ void FSR3Upscaler_DX12::AwaitEndOfFrame(uint64_t frameValue)
}
}
-void FSR3Upscaler_DX12::DestroyContext(FSR3Feature_FFX& feature)
-{
- m_ffxFunctions.DestroyContext(&feature.upscalingContext, nullptr);
-}
-
void FSR3Upscaler_DX12::DoShutdown()
{
FSR3Upscaler_FFXBase::DoShutdown();
diff --git a/FSR3Upscaler_DX12.h b/FSR3Upscaler_DX12.h
index e82cdc7..9fdc70b 100644
--- a/FSR3Upscaler_DX12.h
+++ b/FSR3Upscaler_DX12.h
@@ -18,15 +18,11 @@ public:
bool Init() override;
protected:
- bool IsValidFeature(FSR3Feature_FFX& feature) override;
-
bool InitFeature(FSR3Feature_FFX& feature, const FSR3CommandInitializationData* initData) override;
- void SetTexture(FSR3TextureDesc* textureDesc, UnityTextureID textureID) override;
+ void SetTexture(FSR3Texture textureType, UnityTextureID textureID, const UnityRenderingExtTextureUpdateParamsV2* params, FSR3TextureDesc* outTextureDesc) override;
void Execute(FSR3Feature_FFX& feature, const FSR3CommandExecutionData* execData) override;
void AwaitEndOfFrame(uint64_t frameValue) override;
- void DestroyContext(FSR3Feature_FFX& feature) override;
-
void DoShutdown() override;
private:
diff --git a/FSR3Upscaler_FFXBase.h b/FSR3Upscaler_FFXBase.h
index 5666306..7a85c25 100644
--- a/FSR3Upscaler_FFXBase.h
+++ b/FSR3Upscaler_FFXBase.h
@@ -77,6 +77,16 @@ protected:
return true;
}
+ bool IsValidFeature(FSR3Feature_FFX& feature) override
+ {
+ return feature.upscalingContext != nullptr;
+ }
+
+ void DestroyContext(FSR3Feature_FFX& feature) override
+ {
+ m_ffxFunctions.DestroyContext(&feature.upscalingContext, nullptr);
+ }
+
void DoShutdown() override
{
if (m_ffxModule != nullptr)
diff --git a/FSR3Upscaler_Vulkan.cpp b/FSR3Upscaler_Vulkan.cpp
new file mode 100644
index 0000000..cd0b8ce
--- /dev/null
+++ b/FSR3Upscaler_Vulkan.cpp
@@ -0,0 +1,149 @@
+#include "FSR3Upscaler_Vulkan.h"
+
+static VkInstance s_VulkanInstance;
+static PFN_vkGetInstanceProcAddr s_GetInstanceProcAddr;
+
+static PFN_vkVoidFunction GetVulkanDeviceProcAddr(VkDevice device, const char* pName)
+{
+ if (s_GetInstanceProcAddr == nullptr)
+ return nullptr;
+
+ return s_GetInstanceProcAddr(s_VulkanInstance, pName);
+}
+
+bool FSR3Upscaler_Vulkan::Init()
+{
+ UnityVulkanInstance instance = m_GraphicsDevice->Instance();
+ if (instance.device == nullptr)
+ return false;
+
+ s_VulkanInstance = instance.instance;
+ s_GetInstanceProcAddr = instance.getInstanceProcAddr;
+
+ m_VulkanBackendDesc.vkDevice = instance.device;
+ m_VulkanBackendDesc.vkPhysicalDevice = instance.physicalDevice;
+ m_VulkanBackendDesc.vkDeviceProcAddr = &GetVulkanDeviceProcAddr;
+
+ return LoadFidelityFXLibrary(TEXT("amd_fidelityfx_vk.dll"), nullptr);
+}
+
+bool FSR3Upscaler_Vulkan::InitFeature(FSR3Feature_FFX& feature, const FSR3CommandInitializationData* initData)
+{
+ ffx::CreateContextDescUpscale createUpscaling;
+ createUpscaling.maxUpscaleSize = { initData->displaySizeWidth, initData->displaySizeHeight };
+ createUpscaling.maxRenderSize = { initData->maxRenderSizeWidth, initData->maxRenderSizeHeight };
+ createUpscaling.flags = initData->flags;
+
+ return FFX_API_RETURN_OK == m_ffxFunctions.CreateContext(&feature.upscalingContext, ffx::LinkHeaders(createUpscaling.header, m_VulkanBackendDesc.header), nullptr);
+}
+
+void FSR3Upscaler_Vulkan::SetTexture(FSR3Texture textureType, UnityTextureID textureID, const UnityRenderingExtTextureUpdateParamsV2* params, FSR3TextureDesc* outTextureDesc)
+{
+ VkAccessFlags accessFlags = (textureType == FSR3Texture::tColorOutput) ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_SHADER_READ_BIT;
+
+ UnityVulkanImage image;
+ if (m_GraphicsDevice->AccessTextureByID(textureID, UnityVulkanWholeImage,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, accessFlags,
+ kUnityVulkanResourceAccess_PipelineBarrier, &image))
+ {
+ outTextureDesc->image = (intptr_t)image.image;
+ outTextureDesc->width = params->width;
+ outTextureDesc->height = params->height;
+ outTextureDesc->format = (uint32_t)image.format;
+ }
+ else
+ {
+ outTextureDesc->image = 0;
+ }
+}
+
+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);
+}
+
+void FSR3Upscaler_Vulkan::Execute(FSR3Feature_FFX& feature, const FSR3CommandExecutionData* execData)
+{
+ ffx::DispatchDescUpscale dispatchUpscale{};
+
+ UnityVulkanRecordingState state;
+ m_GraphicsDevice->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 = m_GraphicsDevice->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 = execData->jitterOffsetX;
+ dispatchUpscale.jitterOffset.y = execData->jitterOffsetY;
+ dispatchUpscale.motionVectorScale.x = execData->MVScaleX;
+ dispatchUpscale.motionVectorScale.y = execData->MVScaleY;
+ dispatchUpscale.reset = execData->reset;
+ dispatchUpscale.enableSharpening = execData->enableSharpening;
+ dispatchUpscale.sharpness = execData->sharpness;
+ dispatchUpscale.frameTimeDelta = execData->frameTimeDelta;
+ dispatchUpscale.preExposure = execData->preExposure;
+ dispatchUpscale.renderSize.width = execData->renderSizeWidth;
+ dispatchUpscale.renderSize.height = execData->renderSizeHeight;
+ dispatchUpscale.upscaleSize.width = feature.upscaleSizeWidth;
+ dispatchUpscale.upscaleSize.height = feature.upscaleSizeHeight;
+ dispatchUpscale.cameraFovAngleVertical = execData->cameraFovAngleVertical;
+
+ if (feature.flags & FFX_UPSCALE_ENABLE_DEPTH_INVERTED)
+ {
+ dispatchUpscale.cameraFar = execData->cameraNear;
+ dispatchUpscale.cameraNear = execData->cameraFar;
+ }
+ else
+ {
+ dispatchUpscale.cameraFar = execData->cameraFar;
+ dispatchUpscale.cameraNear = execData->cameraNear;
+ }
+
+ m_ffxFunctions.Dispatch(&feature.upscalingContext, &dispatchUpscale.header);
+}
+
+void FSR3Upscaler_Vulkan::AwaitEndOfFrame(uint64_t frameValue)
+{
+ UnityVulkanRecordingState state;
+ m_GraphicsDevice->CommandRecordingState(&state, kUnityVulkanGraphicsQueueAccess_DontCare);
+ if (frameValue > state.safeFrameNumber)
+ {
+ UnityVulkanInstance instance = m_GraphicsDevice->Instance();
+ vkQueueWaitIdle(instance.graphicsQueue);
+ }
+}
+
+void FSR3Upscaler_Vulkan::DoShutdown()
+{
+ FSR3Upscaler_FFXBase::DoShutdown();
+
+ m_VulkanBackendDesc.vkDevice = nullptr;
+ m_VulkanBackendDesc.vkPhysicalDevice = nullptr;
+ m_VulkanBackendDesc.vkDeviceProcAddr = nullptr;
+}
diff --git a/FSR3Upscaler_Vulkan.h b/FSR3Upscaler_Vulkan.h
new file mode 100644
index 0000000..f3eb4f3
--- /dev/null
+++ b/FSR3Upscaler_Vulkan.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "FSR3Upscaler_FFXBase.h"
+
+#include "ffx_api/ffx_upscale.hpp"
+#include "ffx_api/vk/ffx_api_vk.hpp"
+
+#include "UnityPluginAPI/IUnityGraphicsVulkan.h"
+
+class FSR3Upscaler_Vulkan : FSR3Upscaler_FFXBase
+{
+public:
+ FSR3Upscaler_Vulkan(IUnityInterfaces* unityInterfaces, IUnityGraphicsVulkan* graphicsDevice) :
+ FSR3Upscaler_FFXBase(unityInterfaces),
+ m_GraphicsDevice(graphicsDevice), m_VulkanBackendDesc()
+ {
+ }
+
+ bool Init() override;
+
+protected:
+ bool InitFeature(FSR3Feature_FFX& feature, const FSR3CommandInitializationData* initData) override;
+ void SetTexture(FSR3Texture textureType, UnityTextureID textureID, const UnityRenderingExtTextureUpdateParamsV2* params, FSR3TextureDesc* outTextureDesc) override;
+ void Execute(FSR3Feature_FFX& feature, const FSR3CommandExecutionData* execData) override;
+
+ void AwaitEndOfFrame(uint64_t frameValue) override;
+ void DoShutdown() override;
+
+private:
+ IUnityGraphicsVulkan* m_GraphicsDevice;
+ ffx::CreateBackendVKDesc m_VulkanBackendDesc;
+};
diff --git a/UpscalerGraphicsDevice.h b/UpscalerGraphicsDevice.h
index e737d14..b15a08d 100644
--- a/UpscalerGraphicsDevice.h
+++ b/UpscalerGraphicsDevice.h
@@ -6,6 +6,7 @@
#include
#include "UnityPluginAPI/IUnityInterface.h"
+#include "UnityPluginAPI/IUnityRenderingExtensions.h"
#include "FSR3UnityTypes.h"
@@ -87,7 +88,7 @@ public:
memset(&m_Features[featureSlot].textureTable, 0, sizeof(FSR3TextureTable));
}
- virtual void SetTextureSlot(uint32_t featureSlot, uint32_t textureSlot, UnityTextureID textureID)
+ virtual void SetTextureSlot(uint32_t featureSlot, uint32_t textureSlot, UnityTextureID textureID, const UnityRenderingExtTextureUpdateParamsV2* params)
{
if (featureSlot < 0 || featureSlot >= m_Features.size())
return;
@@ -95,7 +96,7 @@ public:
// 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*)&m_Features[featureSlot].textureTable) + textureSlot;
- SetTexture(textureDesc, textureID);
+ SetTexture((FSR3Texture)textureSlot, textureID, params, textureDesc);
}
virtual void Execute(const FSR3CommandExecutionData* execData)
@@ -132,7 +133,7 @@ protected:
virtual bool IsValidFeature(TFeature& feature) = 0;
virtual bool InitFeature(TFeature& feature, const FSR3CommandInitializationData* initData) = 0;
- virtual void SetTexture(FSR3TextureDesc* textureDesc, UnityTextureID textureID) = 0;
+ virtual void SetTexture(FSR3Texture textureType, UnityTextureID textureID, const UnityRenderingExtTextureUpdateParamsV2* params, FSR3TextureDesc* outTextureDesc) = 0;
virtual void Execute(TFeature& feature, const FSR3CommandExecutionData* execData) = 0;
virtual void PostExecute(TFeature& feature, const FSR3CommandExecutionData* execData) { }