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.
267 lines
13 KiB
267 lines
13 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using FidelityFX;
|
|
using FidelityFX.FSR3;
|
|
using UnityEngine.Experimental.Rendering;
|
|
#if UNITY_STANDALONE_WIN
|
|
using AMDUP = UnityEngine.AMD;
|
|
#endif
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition.AMD.FSR3
|
|
{
|
|
/// <summary>
|
|
/// Custom upscaler plugin that uses the open source port of FSR3 to Unity.
|
|
/// This eschews using native plugins, instead using portable code that will work on any platform that supports compute shaders.
|
|
/// </summary>
|
|
public class FSR3UpscalerPlugin: UpscalerPlugin
|
|
{
|
|
public static bool EnableDebugView { get; set; } = false;
|
|
|
|
private Fsr3UpscalerAssets _assets;
|
|
private bool _nativePluginLoaded;
|
|
|
|
public override string name => "FSR 3.1";
|
|
|
|
public override bool isSupported => SystemInfo.supportsComputeShaders;
|
|
|
|
public override bool includesSharpening => true;
|
|
|
|
public override bool supportsAlpha => !_nativePluginLoaded; // Managed Unity port has alpha upscaling built-in, the native AMD implementation doesn't
|
|
|
|
public override bool Load()
|
|
{
|
|
// Guess we're using native plugins after all!
|
|
// On Windows with supported graphics APIs, we use a drop-in replacement for Unity's plugin that implements FSR 3.1 through AMD's upgradable FidelityFX API.
|
|
// This allows AMD's GPU driver to hijack the plugin and transparently upgrade our implementation to FSR4 on supported graphics cards!
|
|
_nativePluginLoaded = false;
|
|
#if false//UNITY_STANDALONE_WIN
|
|
if (!Application.isEditor && SystemInfo.operatingSystemFamily == OperatingSystemFamily.Windows && SystemInfo.graphicsDeviceType is GraphicsDeviceType.Direct3D12 or GraphicsDeviceType.Vulkan)
|
|
{
|
|
try
|
|
{
|
|
if (AMDUP.AMDUnityPlugin.IsLoaded() || AMDUP.AMDUnityPlugin.Load())
|
|
{
|
|
_nativePluginLoaded = AMDUP.GraphicsDevice.device != null || AMDUP.GraphicsDevice.CreateGraphicsDevice() != null;
|
|
if (_nativePluginLoaded)
|
|
return true;
|
|
}
|
|
}
|
|
catch (DllNotFoundException)
|
|
{
|
|
_nativePluginLoaded = false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (_assets != null)
|
|
return true;
|
|
|
|
_assets = Resources.Load<Fsr3UpscalerAssets>("FSR3 Upscaler Assets");
|
|
return _assets != null;
|
|
}
|
|
|
|
public override bool IsLoaded() => _nativePluginLoaded || _assets != null;
|
|
|
|
public override UpscalerContext CreateContext(in FSR2CommandInitializationData initSettings)
|
|
{
|
|
#if UNITY_STANDALONE_WIN
|
|
if (_nativePluginLoaded)
|
|
{
|
|
var context = new FSR3NativeUpscalerContext(in initSettings);
|
|
context.Init();
|
|
return context;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
var context = new FSR3UpscalerContext(in initSettings);
|
|
context.Init(_assets);
|
|
return context;
|
|
}
|
|
}
|
|
|
|
public override void DestroyContext(UpscalerContext context)
|
|
{
|
|
switch (context)
|
|
{
|
|
#if UNITY_STANDALONE_WIN
|
|
case FSR3NativeUpscalerContext nativeContext:
|
|
nativeContext.Destroy();
|
|
break;
|
|
#endif
|
|
case FSR3UpscalerContext managedContext:
|
|
managedContext.Destroy();
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override bool GetRenderResolutionFromQualityMode(FSR2Quality qualityMode, uint displayWidth, uint displayHeight, out uint renderWidth, out uint renderHeight)
|
|
{
|
|
Fsr3Upscaler.GetRenderResolutionFromQualityMode(out int rw, out int rh, (int)displayWidth, (int)displayHeight, (Fsr3Upscaler.QualityMode)((int)qualityMode + 2));
|
|
renderWidth = (uint)rw;
|
|
renderHeight = (uint)rh;
|
|
return true;
|
|
}
|
|
|
|
public override float GetUpscaleRatioFromQualityMode(FSR2Quality qualityMode)
|
|
{
|
|
return Fsr3Upscaler.GetUpscaleRatioFromQualityMode((Fsr3Upscaler.QualityMode)((int)qualityMode + 2));
|
|
}
|
|
}
|
|
|
|
public class FSR3UpscalerContext : UpscalerContext
|
|
{
|
|
private readonly Fsr3UpscalerContext _context = new();
|
|
private readonly Fsr3Upscaler.DispatchDescription _dispatchDescription = new();
|
|
private readonly FSR2CommandInitializationData _initData;
|
|
|
|
private Texture2DArray _clearTextureArray;
|
|
|
|
internal FSR3UpscalerContext(in FSR2CommandInitializationData initSettings)
|
|
{
|
|
_initData = initSettings;
|
|
}
|
|
|
|
internal void Init(Fsr3UpscalerAssets assets)
|
|
{
|
|
Fsr3Upscaler.InitializationFlags flags = 0;
|
|
if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableHighDynamicRange)) flags |= Fsr3Upscaler.InitializationFlags.EnableHighDynamicRange;
|
|
if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDisplayResolutionMotionVectors)) flags |= Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors;
|
|
if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableMotionVectorsJitterCancellation)) flags |= Fsr3Upscaler.InitializationFlags.EnableMotionVectorsJitterCancellation;
|
|
if (_initData.GetFlag(FfxFsr2InitializationFlags.DepthInverted)) flags |= Fsr3Upscaler.InitializationFlags.EnableDepthInverted;
|
|
if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDepthInfinite)) flags |= Fsr3Upscaler.InitializationFlags.EnableDepthInfinite;
|
|
if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableAutoExposure)) flags |= Fsr3Upscaler.InitializationFlags.EnableAutoExposure;
|
|
if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDynamicResolution)) flags |= Fsr3Upscaler.InitializationFlags.EnableDynamicResolution;
|
|
|
|
//Debug.Log($"Initializing FSR3 with max render size: {_initData.maxRenderSizeWidth}x{_initData.maxRenderSizeHeight}, display size: {_initData.displaySizeWidth}x{_initData.displaySizeHeight}, flags: {flags}");
|
|
|
|
_context.Create(new Fsr3Upscaler.ContextDescription
|
|
{
|
|
MaxUpscaleSize = new Vector2Int((int)_initData.displaySizeWidth, (int)_initData.displaySizeHeight),
|
|
MaxRenderSize = new Vector2Int((int)_initData.maxRenderSizeWidth, (int)_initData.maxRenderSizeHeight),
|
|
Flags = flags,
|
|
Shaders = assets.shaders,
|
|
});
|
|
|
|
_clearTextureArray = new Texture2DArray(1, 1, TextureXR.slices, GraphicsFormat.R32G32_SFloat, TextureCreationFlags.None);
|
|
for (int i = 0; i < TextureXR.slices; ++i) _clearTextureArray.SetPixels(new[] { Color.clear, }, i);
|
|
_clearTextureArray.Apply();
|
|
}
|
|
|
|
internal void Destroy()
|
|
{
|
|
CoreUtils.Destroy(_clearTextureArray);
|
|
|
|
_context.Destroy();
|
|
}
|
|
|
|
public override void Execute(CommandBuffer cmd, in FSR2CommandExecutionData executeData, in FSR2TextureTable textures)
|
|
{
|
|
bool useTextureArrays = TextureXR.useTexArray && textures.colorInput.dimension == TextureDimension.Tex2DArray;
|
|
ResourceView clearTexture = useTextureArrays ? new ResourceView(_clearTextureArray) : new ResourceView();
|
|
|
|
_dispatchDescription.Color = new ResourceView(textures.colorInput);
|
|
_dispatchDescription.Depth = new ResourceView(textures.depth);
|
|
_dispatchDescription.MotionVectors = new ResourceView(textures.motionVectors);
|
|
_dispatchDescription.Exposure = textures.exposureTexture != null ? new ResourceView(textures.exposureTexture) : new ResourceView();
|
|
_dispatchDescription.Reactive = textures.biasColorMask != null ? new ResourceView(textures.biasColorMask) : clearTexture;
|
|
_dispatchDescription.TransparencyAndComposition = textures.transparencyMask != null ? new ResourceView(textures.transparencyMask) : clearTexture;
|
|
_dispatchDescription.Output = new ResourceView(textures.colorOutput);
|
|
|
|
_dispatchDescription.JitterOffset = new Vector2(executeData.jitterOffsetX, executeData.jitterOffsetY);
|
|
_dispatchDescription.MotionVectorScale = new Vector2(executeData.MVScaleX, executeData.MVScaleY);
|
|
_dispatchDescription.RenderSize = new Vector2Int((int)executeData.renderSizeWidth, (int)executeData.renderSizeHeight);
|
|
_dispatchDescription.UpscaleSize = new Vector2Int((int)_initData.displaySizeWidth, (int)_initData.displaySizeHeight);
|
|
_dispatchDescription.InputResourceSize = new Vector2Int(textures.colorInput.width, textures.colorInput.height);
|
|
_dispatchDescription.EnableSharpening = executeData.enableSharpening != 0;
|
|
_dispatchDescription.Sharpness = executeData.sharpness;
|
|
_dispatchDescription.FrameTimeDelta = executeData.frameTimeDelta / 1000f;
|
|
_dispatchDescription.PreExposure = executeData.preExposure;
|
|
_dispatchDescription.Reset = executeData.reset != 0;
|
|
_dispatchDescription.CameraNear = executeData.cameraNear;
|
|
_dispatchDescription.CameraFar = executeData.cameraFar;
|
|
_dispatchDescription.CameraFovAngleVertical = executeData.cameraFovAngleVertical;
|
|
_dispatchDescription.ViewSpaceToMetersFactor = 1.0f; // 1 unit is 1 meter in Unity
|
|
_dispatchDescription.Flags = FSR3UpscalerPlugin.EnableDebugView ? Fsr3Upscaler.DispatchFlags.DrawDebugView : 0;
|
|
_dispatchDescription.UseTextureArrays = useTextureArrays;
|
|
|
|
_context.Dispatch(_dispatchDescription, cmd);
|
|
}
|
|
}
|
|
|
|
#if UNITY_STANDALONE_WIN
|
|
public class FSR3NativeUpscalerContext : UpscalerContext
|
|
{
|
|
private AMDUP.FSR2Context _nativeContext;
|
|
private readonly FSR2CommandInitializationData _initData;
|
|
|
|
internal FSR3NativeUpscalerContext(in FSR2CommandInitializationData initSettings)
|
|
{
|
|
_initData = initSettings;
|
|
}
|
|
|
|
internal void Init()
|
|
{
|
|
AMDUP.FSR2CommandInitializationData initSettings = new()
|
|
{
|
|
maxRenderSizeWidth = _initData.maxRenderSizeWidth,
|
|
maxRenderSizeHeight = _initData.maxRenderSizeHeight,
|
|
displaySizeWidth = _initData.displaySizeWidth,
|
|
displaySizeHeight = _initData.displaySizeHeight,
|
|
ffxFsrFlags = (AMDUP.FfxFsr2InitializationFlags)_initData.ffxFsrFlags,
|
|
};
|
|
|
|
CommandBuffer cmd = new();
|
|
_nativeContext = AMDUP.GraphicsDevice.device.CreateFeature(cmd, in initSettings);
|
|
Graphics.ExecuteCommandBuffer(cmd);
|
|
cmd.Release();
|
|
}
|
|
|
|
internal void Destroy()
|
|
{
|
|
if (_nativeContext == null)
|
|
return;
|
|
|
|
CommandBuffer cmd = new();
|
|
AMDUP.GraphicsDevice.device.DestroyFeature(cmd, _nativeContext);
|
|
Graphics.ExecuteCommandBuffer(cmd);
|
|
cmd.Release();
|
|
|
|
_nativeContext = null;
|
|
}
|
|
|
|
public override void Execute(CommandBuffer cmd, in FSR2CommandExecutionData executeData, in FSR2TextureTable textures)
|
|
{
|
|
ref var execData = ref _nativeContext.executeData;
|
|
execData.jitterOffsetX = executeData.jitterOffsetX;
|
|
execData.jitterOffsetY = executeData.jitterOffsetY;
|
|
execData.MVScaleX = executeData.MVScaleX;
|
|
execData.MVScaleY = executeData.MVScaleY;
|
|
execData.renderSizeWidth = executeData.renderSizeWidth;
|
|
execData.renderSizeHeight = executeData.renderSizeHeight;
|
|
execData.enableSharpening = executeData.enableSharpening;
|
|
execData.sharpness = executeData.sharpness;
|
|
execData.frameTimeDelta = executeData.frameTimeDelta;
|
|
execData.preExposure = executeData.preExposure;
|
|
execData.reset = executeData.reset;
|
|
execData.cameraNear = executeData.cameraNear;
|
|
execData.cameraFar = executeData.cameraFar;
|
|
execData.cameraFovAngleVertical = executeData.cameraFovAngleVertical;
|
|
|
|
AMDUP.FSR2TextureTable textureTable = new()
|
|
{
|
|
colorInput = textures.colorInput,
|
|
depth = textures.depth,
|
|
motionVectors = textures.motionVectors,
|
|
exposureTexture = textures.exposureTexture,
|
|
biasColorMask = textures.biasColorMask,
|
|
reactiveMask = textures.reactiveMask,
|
|
transparencyMask = textures.transparencyMask,
|
|
colorOutput = textures.colorOutput,
|
|
};
|
|
|
|
AMDUP.GraphicsDevice.device.ExecuteFSR2(cmd, _nativeContext, in textureTable);
|
|
}
|
|
}
|
|
#endif
|
|
}
|