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.
 
 
 
 

304 lines
12 KiB

using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
#if ENABLE_UPSCALER_FRAMEWORK && ENABLE_AMD && ENABLE_AMD_MODULE
using UnityEngine.AMD;
#endif
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if ENABLE_UPSCALER_FRAMEWORK && ENABLE_AMD && ENABLE_AMD_MODULE
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
static class RegisterFSR2
{
static RegisterFSR2() => UpscalerRegistry.Register<FSR2IUpscaler, FSR2Options>(FSR2IUpscaler.UPSCALER_NAME);
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void InitRuntime() => UpscalerRegistry.Register<FSR2IUpscaler, FSR2Options>(FSR2IUpscaler.UPSCALER_NAME);
}
public class FSR2IUpscaler : AbstractUpscaler
{
public static readonly string UPSCALER_NAME = "FSR2 (IUpscaler)";
#region FSR2_UTILITIES
static bool CheckFSR2FeatureAvailable()
{
// check plugin availability
if (!UnityEngine.AMD.AMDUnityPlugin.IsLoaded())
{
Debug.LogWarning("AMDUnityPlugin not loaded.");
return false;
}
// check plugin version
// if (s_ExpectedDeviceVersion != UnityEngine.AMD.GraphicsDevice.version)
// {
// Debug.LogWarning("Cannot instantiate AMD device because the version HDRP expects does not match the backend version.");
// return false;
// }
// check device
UnityEngine.AMD.GraphicsDevice device = UnityEngine.AMD.GraphicsDevice.CreateGraphicsDevice();
if (device == null)
{
Debug.LogWarning("AMDUnityPlugin failed to create device.");
return false;
}
return true;
}
static void DestroyContext(ref FSR2Context ctx, CommandBuffer cmd)
{
GraphicsDevice.device.DestroyFeature(cmd, ctx);
ctx = null;
}
static void CreateContext(ref FSR2Context ctx, CommandBuffer cmd, ref FSR2GraphData data)
{
bool displayResolutionMotionVectors = data.motionVectorSizeX == data.colorOutputSizeX && data.motionVectorSizeY == data.colorOutputSizeY;
FSR2CommandInitializationData settings = new();
settings.SetFlag(FfxFsr2InitializationFlags.EnableHighDynamicRange, data.inputIsHDR);
settings.SetFlag(FfxFsr2InitializationFlags.EnableDisplayResolutionMotionVectors, displayResolutionMotionVectors);
settings.SetFlag(FfxFsr2InitializationFlags.DepthInverted, data.invertedDepthBuffer);
settings.SetFlag(FfxFsr2InitializationFlags.EnableMotionVectorsJitterCancellation, data.motionVectorsAreJittered);
settings.maxRenderSizeWidth = data.colorInputSizeX;
settings.maxRenderSizeHeight = data.colorInputSizeY;
settings.displaySizeWidth = data.colorOutputSizeX;
settings.displaySizeHeight = data.colorOutputSizeY;
ctx = GraphicsDevice.device.CreateFeature(cmd, settings);
}
#endregion // FSR2_UTILITIES
#region RENDERGRAPH_INTERFACE_DATA
class FSR2GraphData
{
public bool shouldReinitializeContext;
public uint colorInputSizeX;
public uint colorInputSizeY;
public uint colorOutputSizeX;
public uint colorOutputSizeY;
public uint motionVectorSizeX;
public uint motionVectorSizeY;
public bool invertedDepthBuffer;
public bool inputIsHDR;
public bool motionVectorsAreJittered;
public FSR2CommandExecutionData execData;
public TextureHandle colorInput;
public TextureHandle depth;
public TextureHandle motionVectors;
public TextureHandle colorOutput;
};
#endregion
#region IUPSCALER_INTERFACE
public FSR2IUpscaler(FSR2Options o)
{
if(!CheckFSR2FeatureAvailable())
{
m_FSR2Ready = false;
return;
}
m_Options = o;
m_OutputResolutionPrevious = new Vector2Int(0, 0);
m_InputResolution = new Vector2Int(1, 1);
m_OutputResolution = new Vector2Int(1, 1);
m_Jitter = new Vector2(0, 0);
m_FSR2Ready = true;
}
public override string GetName()
{
return UPSCALER_NAME;
}
public override bool IsTemporalUpscaler() { return true; }
public override void CalculateJitter(int frameIndex, out Vector2 jitter, out bool allowScaling)
{
float upscaleRatio = (float)(m_OutputResolution.x) / m_InputResolution.x;
int numPhases = CalculateJitterPhaseCount(upscaleRatio);
int haltonIndex = (frameIndex % numPhases) + 1;
float x = HaltonSequence.Get(haltonIndex, 2) - 0.5f;
float y = HaltonSequence.Get(haltonIndex, 3) - 0.5f;
jitter = new Vector2(x, y);
allowScaling = false;
m_Jitter = jitter;
}
static int CalculateJitterPhaseCount(float upscaleRatio)
{
const float basePhaseCount = 8.0f;
return (int)(basePhaseCount * upscaleRatio * upscaleRatio);
}
private bool ShouldResetFSR2Context(UpscalingIO io)
{
bool nullContext = m_FSR2Context == null;
bool outputResolutionChanged = m_OutputResolutionPrevious != io.postUpscaleResolution;
return nullContext || outputResolutionChanged;
}
public override void NegotiatePreUpscaleResolution(ref Vector2Int preUpscaleResolution, Vector2Int postUpscaleResolution)
{
if (m_Options.FixedResolutionMode)
{
Debug.Assert(GraphicsDevice.device != null);
FSR2Quality qualityMode = (FSR2Quality)m_Options.FSR2QualityMode;
GraphicsDevice.device.GetRenderResolutionFromQualityMode(qualityMode,
(uint)postUpscaleResolution.x,
(uint)postUpscaleResolution.y,
out uint renderResoolutionX,
out uint renderResoolutionY
);
preUpscaleResolution.x = (int)renderResoolutionX;
preUpscaleResolution.y = (int)renderResoolutionY;
}
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
if(!m_FSR2Ready)
return;
Debug.Assert(GraphicsDevice.device != null);
UpscalingIO io = frameData.Get<UpscalingIO>();
m_InputResolution = io.preUpscaleResolution;
m_OutputResolution = io.postUpscaleResolution;
// describe output texture
TextureHandle outputColor;
{
TextureDesc inputDesc = io.cameraColor.GetDescriptor(renderGraph);
TextureDesc outputDesc = inputDesc;
outputDesc.width = io.postUpscaleResolution.x;
outputDesc.height = io.postUpscaleResolution.y;
outputDesc.format = GraphicsFormatUtility.GetLinearFormat(inputDesc.format);
outputDesc.msaaSamples = MSAASamples.None;
outputDesc.useMipMap = false;
outputDesc.autoGenerateMips = false;
outputDesc.useDynamicScale = false;
outputDesc.anisoLevel = 0;
outputDesc.discardBuffer = false;
outputDesc.enableRandomWrite = true; // compute shader resource
outputDesc.name = "_FSR2OutputTarget";
outputDesc.clearBuffer = false;
outputDesc.filterMode = FilterMode.Bilinear;
outputColor = renderGraph.CreateTexture(outputDesc);
}
using (var builder = renderGraph.AddUnsafePass<FSR2GraphData>("FidelityFX Super Resolution 2", out FSR2GraphData passData, new ProfilingSampler("FSR2")))
{
float motionVectorSign = io.motionVectorDirection == UpscalingIO.MotionVectorDirection.PreviousFrameToCurrentFrame ? -1.0f : 1.0f;
float motionVectorScaleX = io.motionVectorDomain == UpscalingIO.MotionVectorDomain.NDC ? io.motionVectorTextureSize.x : 1.0f;
float motionVectorScaleY = io.motionVectorDomain == UpscalingIO.MotionVectorDomain.NDC ? io.motionVectorTextureSize.y : 1.0f;
// setup pass data (UpscalingIO --> FSR2GraphData)
passData.shouldReinitializeContext = ShouldResetFSR2Context(io);
passData.execData.enableSharpening = m_Options.EnableSharpening ? 1 : 0;
passData.execData.sharpness = m_Options.Sharpness;
passData.execData.MVScaleX = motionVectorSign * motionVectorScaleX;
passData.execData.MVScaleY = motionVectorSign * motionVectorScaleY;
passData.execData.renderSizeWidth = (uint)io.preUpscaleResolution.x;
passData.execData.renderSizeHeight = (uint)io.preUpscaleResolution.y;
passData.execData.jitterOffsetX = m_Jitter.x;
passData.execData.jitterOffsetY = m_Jitter.y;
passData.execData.cameraNear = io.nearClipPlane;
passData.execData.cameraFar = io.farClipPlane;
passData.execData.cameraFovAngleVertical = 2.0f * (float)Math.PI * (1 / 360.0f) * io.fieldOfViewDegrees; // radians
passData.execData.preExposure = 1.0f; // Mathf.Clamp(io.preExposureValue, 0.20f, 2.0f); // clamp to a reasonable value to prevent ghosting
passData.execData.frameTimeDelta = io.deltaTime * 1000.0f; // in milliseconds
passData.execData.reset = io.resetHistory ? 1 : 0;
builder.UseTexture(io.cameraColor);
builder.UseTexture(io.cameraDepth);
builder.UseTexture(io.motionVectorColor);
builder.UseTexture(outputColor, AccessFlags.Write);
passData.colorInput = io.cameraColor;
passData.depth = io.cameraDepth;
passData.motionVectors = io.motionVectorColor;
passData.colorOutput = outputColor;
passData.colorInputSizeX = (uint)io.preUpscaleResolution.x;
passData.colorInputSizeY = (uint)io.preUpscaleResolution.y;
passData.colorOutputSizeX = (uint)io.postUpscaleResolution.x;
passData.colorOutputSizeY = (uint)io.postUpscaleResolution.y;
passData.motionVectorSizeX = (uint)io.motionVectorTextureSize.x;
passData.motionVectorSizeY = (uint)io.motionVectorTextureSize.y;
passData.invertedDepthBuffer = io.invertedDepth;
passData.inputIsHDR = io.hdrInput;
passData.motionVectorsAreJittered = io.jitteredMotionVectors;
// set render function
builder.SetRenderFunc((FSR2GraphData data, UnsafeGraphContext ctx) =>
{
CommandBuffer cmd = CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd);
if (data.shouldReinitializeContext)
{
if (m_FSR2Context != null)
{
DestroyContext(ref m_FSR2Context, cmd);
}
CreateContext(ref m_FSR2Context, cmd, ref data);
}
Debug.Assert(m_FSR2Context != null);
m_FSR2Context.executeData = data.execData;
FSR2TextureTable textureTable = new()
{
colorInput = data.colorInput,
depth = data.depth,
motionVectors = data.motionVectors,
colorOutput = data.colorOutput,
};
GraphicsDevice.device.ExecuteFSR2(cmd, m_FSR2Context, textureTable);
});
}
io.cameraColor = outputColor;
m_OutputResolutionPrevious = io.postUpscaleResolution;
}
#endregion
#region DATA
// static data
private bool m_FSR2Ready = false;
// per-view FSR2 data (per camera / per use)
private FSR2Context m_FSR2Context = null;
private FSR2Options m_Options = null;
private Vector2Int m_OutputResolutionPrevious;
private Vector2Int m_InputResolution;
private Vector2Int m_OutputResolution;
private Vector2 m_Jitter;
#endregion
}
#endif // ENABLE_UPSCALER_FRAMEWORK && ENABLE_AMD && ENABLE_AMD_MODULE