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.
591 lines
23 KiB
591 lines
23 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 <d3d11.h>
|
|
#include <d3d12.h>
|
|
#include <dxgi.h>
|
|
#include "UnityPluginAPI/IUnityGraphicsD3D11.h"
|
|
#include "UnityPluginAPI/IUnityGraphicsD3D12.h"
|
|
#include "UnityPluginAPI/IUnityGraphicsVulkan.h"
|
|
|
|
#include "ffx-fsr2-api/ffx_fsr2.h"
|
|
#include "ffx-fsr2-api/dx11/ffx_fsr2_dx11.h"
|
|
#include "ffx-fsr2-api/dx12/ffx_fsr2_dx12.h"
|
|
#include "ffx-fsr2-api/vk/ffx_fsr2_vk.h"
|
|
|
|
#include "FSR2UnityTypes.h"
|
|
|
|
static const int32_t BaseEventId = 0;
|
|
|
|
static IUnityInterfaces* s_UnityInterfaces = nullptr;
|
|
static IUnityLog* s_Log = nullptr;
|
|
static IUnityGraphics* s_Graphics = nullptr;
|
|
static IUnityGraphicsD3D11* s_GraphicsD3D11 = nullptr;
|
|
static IUnityGraphicsD3D12v7* s_GraphicsD3D12 = nullptr;
|
|
static IUnityGraphicsVulkanV2* s_GraphicsVulkan = nullptr;
|
|
static UnityGfxRenderer s_RendererType = kUnityGfxRendererNull;
|
|
|
|
static FfxDevice s_Device = nullptr;
|
|
static FfxFsr2Interface s_Fsr2Interface;
|
|
|
|
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 FSR2Feature
|
|
{
|
|
FfxFsr2Context upscalingContext;
|
|
uint32_t flags;
|
|
bool isValid;
|
|
|
|
uint64_t dispatchFrameValue;
|
|
|
|
FSR2TextureTable textureTable;
|
|
};
|
|
|
|
static std::vector<FSR2Feature> s_Features;
|
|
static std::queue<uint32_t> s_FeatureSlots;
|
|
static std::mutex s_FeatureMutex;
|
|
|
|
static HANDLE s_FrameFenceEventHandle = nullptr;
|
|
|
|
// 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)
|
|
{
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex);
|
|
|
|
switch (eventType)
|
|
{
|
|
case kUnityGfxDeviceEventInitialize:
|
|
{
|
|
s_RendererType = s_Graphics->GetRenderer();
|
|
switch (s_RendererType)
|
|
{
|
|
case kUnityGfxRendererD3D11:
|
|
{
|
|
s_GraphicsD3D11 = s_UnityInterfaces->Get<IUnityGraphicsD3D11>();
|
|
if (s_GraphicsD3D11 == nullptr)
|
|
{
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D11 Graphics interface!");
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case kUnityGfxRendererD3D12:
|
|
{
|
|
s_GraphicsD3D12 = s_UnityInterfaces->Get<IUnityGraphicsD3D12v7>();
|
|
if (s_GraphicsD3D12 == nullptr)
|
|
{
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain D3D12 Graphics interface!");
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case kUnityGfxRendererVulkan:
|
|
{
|
|
s_GraphicsVulkan = s_UnityInterfaces->Get<IUnityGraphicsVulkanV2>();
|
|
if (s_GraphicsVulkan == nullptr)
|
|
{
|
|
UNITY_LOG_ERROR(s_Log, "Could not obtain Vulkan Graphics interface!");
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
};
|
|
|
|
break;
|
|
}
|
|
case kUnityGfxDeviceEventShutdown:
|
|
{
|
|
s_GraphicsVulkan = nullptr;
|
|
s_GraphicsD3D12 = nullptr;
|
|
s_GraphicsD3D11 = nullptr;
|
|
s_RendererType = kUnityGfxRendererNull;
|
|
break;
|
|
}
|
|
case kUnityGfxDeviceEventBeforeReset:
|
|
{
|
|
break;
|
|
}
|
|
case kUnityGfxDeviceEventAfterReset:
|
|
{
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
|
|
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(FSR2Feature()));
|
|
memset(&s_Features[featureSlot], 0, sizeof(FSR2Feature));
|
|
return featureSlot;
|
|
}
|
|
|
|
// Reallocate an existing free slot
|
|
uint32_t featureSlot = s_FeatureSlots.front();
|
|
s_FeatureSlots.pop();
|
|
return featureSlot;
|
|
}
|
|
|
|
static void FreeFeatureSlot(uint32_t featureSlot)
|
|
{
|
|
s_FeatureSlots.push(featureSlot);
|
|
memset(&s_Features[featureSlot], 0, sizeof(FSR2Feature));
|
|
}
|
|
|
|
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()
|
|
{
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex);
|
|
|
|
if (s_GraphicsD3D11 != nullptr)
|
|
{
|
|
ID3D11Device* device = s_GraphicsD3D11->GetDevice();
|
|
if (device == nullptr)
|
|
return false;
|
|
|
|
s_Device = 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_Device = ffxGetDeviceDX12(device);
|
|
s_FrameFenceEventHandle = CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
|
|
|
|
size_t scratchBufferSize = ffxFsr2GetScratchMemorySizeDX12();
|
|
void* scratchBuffer = malloc(scratchBufferSize);
|
|
ffxFsr2GetInterfaceDX12(&s_Fsr2Interface, device, scratchBuffer, scratchBufferSize);
|
|
return true;
|
|
}
|
|
else if (s_GraphicsVulkan != nullptr)
|
|
{
|
|
UnityVulkanInstance instance = s_GraphicsVulkan->Instance();
|
|
if (instance.device == nullptr)
|
|
return false;
|
|
|
|
s_Device = ffxGetDeviceVK(instance.device);
|
|
|
|
size_t scratchBufferSize = ffxFsr2GetScratchMemorySizeVK(instance.physicalDevice);
|
|
void* scratchBuffer = malloc(scratchBufferSize);
|
|
ffxFsr2GetInterfaceVK(&s_Fsr2Interface, scratchBuffer, scratchBufferSize, instance.physicalDevice, &GetVulkanDeviceProcAddr);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void DestroyFeature(uint32_t featureSlot)
|
|
{
|
|
auto& feature = s_Features[featureSlot];
|
|
|
|
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())
|
|
{
|
|
frameFence->SetEventOnCompletion(feature.dispatchFrameValue, s_FrameFenceEventHandle);
|
|
WaitForSingleObjectEx(s_FrameFenceEventHandle, INFINITE, false);
|
|
}
|
|
}
|
|
else if (s_GraphicsVulkan != nullptr)
|
|
{
|
|
UnityVulkanRecordingState state;
|
|
s_GraphicsVulkan->CommandRecordingState(&state, kUnityVulkanGraphicsQueueAccess_DontCare);
|
|
if (feature.dispatchFrameValue > state.safeFrameNumber)
|
|
{
|
|
UnityVulkanInstance instance = s_GraphicsVulkan->Instance();
|
|
vkQueueWaitIdle(instance.graphicsQueue);
|
|
}
|
|
}
|
|
|
|
if (feature.isValid)
|
|
{
|
|
ffxFsr2ContextDestroy(&feature.upscalingContext);
|
|
FreeFeatureSlot(featureSlot);
|
|
}
|
|
}
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi()
|
|
{
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex);
|
|
|
|
for (uint32_t slot = 0; slot < s_Features.size(); ++slot)
|
|
{
|
|
DestroyFeature(slot);
|
|
}
|
|
|
|
if (s_Fsr2Interface.scratchBuffer != nullptr)
|
|
{
|
|
free(s_Fsr2Interface.scratchBuffer);
|
|
s_Fsr2Interface.scratchBuffer = nullptr;
|
|
}
|
|
|
|
if (s_FrameFenceEventHandle != nullptr)
|
|
{
|
|
CloseHandle(s_FrameFenceEventHandle);
|
|
s_FrameFenceEventHandle = nullptr;
|
|
}
|
|
|
|
s_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()
|
|
{
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex);
|
|
return AllocateFeatureSlot();
|
|
}
|
|
|
|
extern "C" float UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetUpscaleRatioFromQualityMode(FSR2Quality qualityMode)
|
|
{
|
|
switch (qualityMode)
|
|
{
|
|
case FSR2Quality::qQuality:
|
|
return 1.5f;
|
|
case FSR2Quality::qBalanced:
|
|
return 1.7f;
|
|
case FSR2Quality::qPerformance:
|
|
return 2.0f;
|
|
case FSR2Quality::qUltraPerformance:
|
|
return 3.0f;
|
|
default:
|
|
return 1.0f;
|
|
}
|
|
}
|
|
|
|
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetRenderResolutionFromQualityMode(FSR2Quality qualityMode, uint32_t displayWidth, uint32_t displayHeight, uint32_t* renderWidth, uint32_t* renderHeight)
|
|
{
|
|
if (renderWidth == nullptr || renderHeight == nullptr)
|
|
return false;
|
|
|
|
float ratio = AMDUP_GetUpscaleRatioFromQualityMode(qualityMode);
|
|
*renderWidth = (uint32_t)roundf(displayWidth / ratio);
|
|
*renderHeight = (uint32_t)roundf(displayHeight / ratio);
|
|
return true;
|
|
}
|
|
|
|
extern "C" int32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetBaseEventId()
|
|
{
|
|
return BaseEventId;
|
|
}
|
|
|
|
static FfxResource GetVulkanTextureResource(UnityVulkanInstance& instance, FSR2Feature& feature, FSR2TextureDesc& texture, FfxResourceStates state = FFX_RESOURCE_STATE_COMPUTE_READ)
|
|
{
|
|
VkImageView imageView = nullptr;
|
|
|
|
if (texture.image != 0)
|
|
{
|
|
VkImageViewCreateInfo createInfo{};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
createInfo.image = (VkImage)texture.image;
|
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
createInfo.format = (VkFormat)texture.format;
|
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
createInfo.subresourceRange.levelCount = 1;
|
|
createInfo.subresourceRange.layerCount = 1;
|
|
|
|
vkCreateImageView(instance.device, &createInfo, nullptr, &imageView);
|
|
}
|
|
|
|
texture.view = (intptr_t)imageView;
|
|
return ffxGetTextureResourceVK(&feature.upscalingContext, (VkImage)texture.image, imageView, texture.width, texture.height, (VkFormat)texture.format, nullptr, state);
|
|
}
|
|
|
|
static void DestroyVulkanImageView(UnityVulkanInstance& instance, FSR2TextureDesc& texture)
|
|
{
|
|
if (texture.view == 0)
|
|
return;
|
|
|
|
vkDestroyImageView(instance.device, (VkImageView)texture.view, nullptr);
|
|
texture.view = 0;
|
|
}
|
|
|
|
// 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;
|
|
|
|
// User rendering code
|
|
switch (eventID)
|
|
{
|
|
case BaseEventId + FSR2PluginEvent::eDestroyFeature:
|
|
{
|
|
uint32_t featureSlot = (uint32_t)(int64_t)data;
|
|
if (featureSlot < 0 || featureSlot >= s_Features.size())
|
|
return;
|
|
|
|
DestroyFeature(featureSlot);
|
|
break;
|
|
}
|
|
case BaseEventId + FSR2PluginEvent::eExecute:
|
|
{
|
|
auto* params = (FSR2CommandExecutionData*)data;
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size())
|
|
return;
|
|
|
|
auto& feature = s_Features[params->featureSlot];
|
|
if (!feature.isValid)
|
|
return;
|
|
|
|
FfxFsr2DispatchDescription dispatchDescription{};
|
|
|
|
if (s_GraphicsD3D11 != nullptr)
|
|
{
|
|
ID3D11DeviceContext* ctx = nullptr;
|
|
s_GraphicsD3D11->GetDevice()->GetImmediateContext(&ctx);
|
|
dispatchDescription.commandList = ctx;
|
|
|
|
dispatchDescription.color = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.colorInput.image);
|
|
dispatchDescription.depth = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.depth.image);
|
|
dispatchDescription.motionVectors = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.motionVectors.image);
|
|
dispatchDescription.exposure = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.exposureTexture.image);
|
|
dispatchDescription.reactive = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.reactiveMask.image);
|
|
dispatchDescription.transparencyAndComposition = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.transparencyMask.image);
|
|
dispatchDescription.output = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.colorOutput.image, nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS);
|
|
|
|
if (dispatchDescription.reactive.resource == nullptr)
|
|
dispatchDescription.reactive = ffxGetResourceDX11(&feature.upscalingContext, (ID3D11Resource*)feature.textureTable.biasColorMask.image);
|
|
}
|
|
else if (s_GraphicsD3D12 != nullptr)
|
|
{
|
|
UnityGraphicsD3D12RecordingState state;
|
|
s_GraphicsD3D12->CommandRecordingState(&state);
|
|
dispatchDescription.commandList = ffxGetCommandListDX12(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();
|
|
|
|
dispatchDescription.color = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.colorInput.image);
|
|
dispatchDescription.depth = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.depth.image);
|
|
dispatchDescription.motionVectors = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.motionVectors.image);
|
|
dispatchDescription.exposure = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.exposureTexture.image);
|
|
dispatchDescription.reactive = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.reactiveMask.image);
|
|
dispatchDescription.transparencyAndComposition = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.transparencyMask.image);
|
|
dispatchDescription.output = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.colorOutput.image, nullptr, FFX_RESOURCE_STATE_UNORDERED_ACCESS);
|
|
|
|
if (dispatchDescription.reactive.resource == nullptr)
|
|
dispatchDescription.reactive = ffxGetResourceDX12(&feature.upscalingContext, (ID3D12Resource*)feature.textureTable.biasColorMask.image);
|
|
}
|
|
else if (s_GraphicsVulkan != nullptr)
|
|
{
|
|
UnityVulkanRecordingState state;
|
|
s_GraphicsVulkan->CommandRecordingState(&state, kUnityVulkanGraphicsQueueAccess_DontCare);
|
|
dispatchDescription.commandList = ffxGetCommandListVK(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();
|
|
dispatchDescription.color = GetVulkanTextureResource(instance, feature, feature.textureTable.colorInput);
|
|
dispatchDescription.depth = GetVulkanTextureResource(instance, feature, feature.textureTable.depth);
|
|
dispatchDescription.motionVectors = GetVulkanTextureResource(instance, feature, feature.textureTable.motionVectors);
|
|
dispatchDescription.exposure = GetVulkanTextureResource(instance, feature, feature.textureTable.exposureTexture);
|
|
dispatchDescription.reactive = GetVulkanTextureResource(instance, feature, feature.textureTable.reactiveMask);
|
|
dispatchDescription.transparencyAndComposition = GetVulkanTextureResource(instance, feature, feature.textureTable.transparencyMask);
|
|
dispatchDescription.output = GetVulkanTextureResource(instance, feature, feature.textureTable.colorOutput, FFX_RESOURCE_STATE_UNORDERED_ACCESS);
|
|
|
|
if (dispatchDescription.reactive.resource == nullptr)
|
|
dispatchDescription.reactive = GetVulkanTextureResource(instance, feature, feature.textureTable.biasColorMask);
|
|
}
|
|
|
|
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.upscalingContext, &dispatchDescription);
|
|
break;
|
|
}
|
|
case BaseEventId + FSR2PluginEvent::ePostExecute:
|
|
{
|
|
auto* params = (FSR2CommandExecutionData*)data;
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size())
|
|
return;
|
|
|
|
auto& feature = s_Features[params->featureSlot];
|
|
|
|
if (s_GraphicsVulkan != nullptr)
|
|
{
|
|
UnityVulkanInstance instance = s_GraphicsVulkan->Instance();
|
|
DestroyVulkanImageView(instance, feature.textureTable.colorInput);
|
|
DestroyVulkanImageView(instance, feature.textureTable.depth);
|
|
DestroyVulkanImageView(instance, feature.textureTable.motionVectors);
|
|
DestroyVulkanImageView(instance, feature.textureTable.exposureTexture);
|
|
DestroyVulkanImageView(instance, feature.textureTable.reactiveMask);
|
|
DestroyVulkanImageView(instance, feature.textureTable.transparencyMask);
|
|
DestroyVulkanImageView(instance, feature.textureTable.colorOutput);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BaseEventId + FSR2PluginEvent::eInit:
|
|
{
|
|
auto* params = (FSR2CommandInitializationData*)data;
|
|
if (params->featureSlot < 0 || params->featureSlot >= s_Features.size())
|
|
return;
|
|
|
|
auto& feature = s_Features[params->featureSlot];
|
|
feature.flags = params->flags;
|
|
|
|
FfxFsr2ContextDescription contextDescription{};
|
|
contextDescription.callbacks = s_Fsr2Interface;
|
|
contextDescription.device = s_Device;
|
|
contextDescription.displaySize = { params->displaySizeWidth, params->displaySizeHeight };
|
|
contextDescription.maxRenderSize = { params->maxRenderSizeWidth, params->maxRenderSizeHeight };
|
|
contextDescription.flags = params->flags;
|
|
|
|
feature.isValid = ffxFsr2ContextCreate(&feature.upscalingContext, &contextDescription) == FFX_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data)
|
|
{
|
|
std::lock_guard<std::mutex> lock(s_FeatureMutex);
|
|
|
|
auto* params = (UnityRenderingExtTextureUpdateParamsV2*)data;
|
|
|
|
// userData = (featureId & (int) ushort.MaxValue) << 16 | (textureSlot & (int) short.MaxValue) << 1 | (clearTextureTable ? 1 : 0);
|
|
uint32_t featureSlot = (params->userData >> 16) & 0xFFFF;
|
|
uint32_t textureSlot = (params->userData >> 1) & 0x7FFF;
|
|
uint32_t clearTextureTable = params->userData & 0x1;
|
|
|
|
if (featureSlot < 0 || featureSlot >= s_Features.size())
|
|
return;
|
|
|
|
auto& feature = s_Features[featureSlot];
|
|
|
|
// User rendering code
|
|
switch (eventID)
|
|
{
|
|
case kUnityRenderingExtEventUpdateTextureBeginV2:
|
|
{
|
|
if (clearTextureTable)
|
|
{
|
|
memset(&feature.textureTable, 0, sizeof(FSR2TextureTable));
|
|
}
|
|
break;
|
|
}
|
|
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
|
|
FSR2TextureDesc* textureDesc = ((FSR2TextureDesc*)&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 == FSR2Textures::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->view = 0;
|
|
textureDesc->width = params->width;
|
|
textureDesc->height = params->height;
|
|
textureDesc->format = (uint32_t)image.format;
|
|
}
|
|
else
|
|
{
|
|
textureDesc->image = 0;
|
|
textureDesc->view = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|