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.
357 lines
15 KiB
357 lines
15 KiB
using UnityEngine;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
#if ENABLE_UPSCALER_FRAMEWORK && ENABLE_NVIDIA && ENABLE_NVIDIA_MODULE
|
|
using UnityEngine.NVIDIA;
|
|
#endif
|
|
using System;
|
|
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
#if ENABLE_UPSCALER_FRAMEWORK && ENABLE_NVIDIA && ENABLE_NVIDIA_MODULE
|
|
|
|
#if UNITY_EDITOR
|
|
[InitializeOnLoad]
|
|
#endif
|
|
static class RegisterDLSS
|
|
{
|
|
static RegisterDLSS() => UpscalerRegistry.Register<DLSSIUpscaler, DLSSOptions>(DLSSIUpscaler.UPSCALER_NAME);
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
|
static void InitRuntime() => UpscalerRegistry.Register<DLSSIUpscaler, DLSSOptions>(DLSSIUpscaler.UPSCALER_NAME);
|
|
}
|
|
|
|
public class DLSSIUpscaler : AbstractUpscaler
|
|
{
|
|
public static readonly string UPSCALER_NAME = "DLSS (IUpscaler)";
|
|
|
|
#region DLSS_UTILITIES
|
|
static bool CheckDLSSFeatureAvailable()
|
|
{
|
|
// check plugin availability
|
|
if (!UnityEngine.NVIDIA.NVUnityPlugin.IsLoaded())
|
|
{
|
|
Debug.LogWarning("NVUnityPlugin not loaded.");
|
|
return false;
|
|
}
|
|
|
|
// check GPU vendor
|
|
if (!SystemInfo.graphicsDeviceVendor.ToLowerInvariant().Contains("nvidia"))
|
|
{
|
|
Debug.LogWarning("DLSS not available on non-NVIDIA graphics cards.");
|
|
return false;
|
|
}
|
|
|
|
// check device
|
|
UnityEngine.NVIDIA.GraphicsDevice device = UnityEngine.NVIDIA.GraphicsDevice.CreateGraphicsDevice();
|
|
if (device == null)
|
|
{
|
|
Debug.LogWarning("NVUnityPlugin failed to create device.");
|
|
return false;
|
|
}
|
|
|
|
// check DLSS feature
|
|
if(!device.IsFeatureAvailable(UnityEngine.NVIDIA.GraphicsDeviceFeature.DLSS))
|
|
{
|
|
Debug.LogWarning("DLSS not available on the current NVIDIA graphics card.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static void DestroyContext(ref DLSSContext ctx, CommandBuffer cmd)
|
|
{
|
|
GraphicsDevice.device.DestroyFeature(cmd, ctx);
|
|
ctx = null;
|
|
}
|
|
static void CreateContext(ref DLSSContext ctx, CommandBuffer cmd, ref DLSSGraphData data, ref DLSSOptions options)
|
|
{
|
|
/* Motion vectors are typically calculated at the
|
|
same resolution as the input color frame (i.e. at the render resolution). If the rendering engine
|
|
supports calculating motion vectors at the display/output resolution and dilating the motion
|
|
vectors, DLSS can accept those by setting the flag to “0”. This is preferred, though uncommon,
|
|
and can result in higher quality antialiasing of moving objects and less blurring of small objects
|
|
and thin details.
|
|
*/
|
|
bool MVLowResolution = data.motionVectorSizeX <= data.colorInputSizeX || data.motionVectorSizeY <= data.colorInputSizeY;
|
|
|
|
DLSSCommandInitializationData settings = new();
|
|
settings.SetFlag(DLSSFeatureFlags.IsHDR, data.inputIsHDR);
|
|
settings.SetFlag(DLSSFeatureFlags.MVLowRes, MVLowResolution);
|
|
settings.SetFlag(DLSSFeatureFlags.DepthInverted, data.invertedDepthBuffer);
|
|
settings.SetFlag(DLSSFeatureFlags.MVJittered, data.motionVectorsAreJittered);
|
|
settings.inputRTWidth = data.colorInputSizeX;
|
|
settings.inputRTHeight = data.colorInputSizeY;
|
|
settings.outputRTWidth = data.colorOutputSizeX;
|
|
settings.outputRTHeight = data.colorOutputSizeY;
|
|
settings.quality = (DLSSQuality)options.DLSSQualityMode;
|
|
settings.presetQualityMode = (DLSSPreset)options.DLSSRenderPresetQuality;
|
|
settings.presetBalancedMode = (DLSSPreset)options.DLSSRenderPresetBalanced;
|
|
settings.presetPerformanceMode = (DLSSPreset)options.DLSSRenderPresetPerformance;
|
|
settings.presetUltraPerformanceMode = (DLSSPreset)options.DLSSRenderPresetUltraPerformance;
|
|
settings.presetDlaaMode = (DLSSPreset)options.DLSSRenderPresetDLAA;
|
|
ctx = GraphicsDevice.device.CreateFeature(cmd, settings);
|
|
}
|
|
#endregion // DLSS_UTILITIES
|
|
|
|
|
|
#region RENDERGRAPH_INTERFACE_DATA
|
|
class DLSSGraphData
|
|
{
|
|
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 DLSSCommandExecutionData execData;
|
|
public TextureHandle colorInput;
|
|
public TextureHandle depth;
|
|
public TextureHandle motionVectors;
|
|
public TextureHandle colorOutput;
|
|
};
|
|
#endregion
|
|
|
|
#region IUPSCALER_INTERFACE
|
|
public DLSSIUpscaler(DLSSOptions o)
|
|
{
|
|
if(!CheckDLSSFeatureAvailable())
|
|
{
|
|
m_DLSSReady = false;
|
|
return;
|
|
}
|
|
|
|
m_Options = o;
|
|
if(m_Options == null)
|
|
{
|
|
Debug.LogWarning("null options given to DLSSIUpscaler()");
|
|
m_Options = (DLSSOptions)ScriptableObject.CreateInstance(typeof(DLSSOptions));
|
|
m_Options.UpscalerName = GetName();
|
|
}
|
|
if (string.IsNullOrEmpty(m_Options.UpscalerName))
|
|
{
|
|
Debug.LogWarning("options given with empty ID");
|
|
m_Options.UpscalerName = GetName();
|
|
}
|
|
m_QualityModeHistory = (DLSSQuality)m_Options.DLSSQualityMode;
|
|
|
|
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_DLSSReady = 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;
|
|
|
|
//Debug.LogFormat("haltonIndex: {0}\nframeIndex: {1}\njitter=({2}, {3})\nphases: {4}\nupscaleRatio: {5}", haltonIndex, frameIndex, x, y, numPhases, upscaleRatio);
|
|
|
|
jitter = new Vector2(x, y);
|
|
allowScaling = false;
|
|
|
|
m_Jitter = jitter;
|
|
}
|
|
|
|
public override void NegotiatePreUpscaleResolution(ref Vector2Int preUpscaleResolution, Vector2Int postUpscaleResolution)
|
|
{
|
|
if(m_Options.FixedResolutionMode)
|
|
{
|
|
Debug.Assert(GraphicsDevice.device != null);
|
|
|
|
DLSSQuality qualityMode = (DLSSQuality)m_Options.DLSSQualityMode;
|
|
GraphicsDevice.device.GetOptimalSettings(
|
|
(uint)postUpscaleResolution.x,
|
|
(uint)postUpscaleResolution.y,
|
|
qualityMode,
|
|
out OptimalDLSSSettingsData dlssOptimalData
|
|
);
|
|
preUpscaleResolution.x = (int)dlssOptimalData.outRenderWidth;
|
|
preUpscaleResolution.y = (int)dlssOptimalData.outRenderHeight;
|
|
}
|
|
}
|
|
|
|
static int CalculateJitterPhaseCount(float upscaleRatio)
|
|
{
|
|
const float basePhaseCount = 8.0f;
|
|
return (int)(basePhaseCount * upscaleRatio * upscaleRatio);
|
|
}
|
|
|
|
private bool ShouldResetDLSSContext(UpscalingIO io)
|
|
{
|
|
bool qualityChanged = m_QualityModeHistory != (DLSSQuality)m_Options.DLSSQualityMode;
|
|
|
|
bool presetChanged = m_PresetQualityHistory != (DLSSPreset)m_Options.DLSSRenderPresetQuality
|
|
|| m_PresetBalancedHistory != (DLSSPreset)m_Options.DLSSRenderPresetBalanced
|
|
|| m_PresetPerfHistory != (DLSSPreset)m_Options.DLSSRenderPresetPerformance
|
|
|| m_PresetUltraPerfHistory != (DLSSPreset)m_Options.DLSSRenderPresetUltraPerformance
|
|
|| m_PresetDLAAHistory != (DLSSPreset)m_Options.DLSSRenderPresetDLAA;
|
|
|
|
bool outputResolutionChanged = m_OutputResolutionPrevious != io.postUpscaleResolution;
|
|
|
|
bool nullContext = m_DLSSContext == null;
|
|
|
|
return nullContext || qualityChanged || presetChanged || outputResolutionChanged;
|
|
}
|
|
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
|
{
|
|
if(!m_DLSSReady)
|
|
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 = "_DLSSOutputTarget";
|
|
outputDesc.clearBuffer = false;
|
|
outputDesc.filterMode = FilterMode.Bilinear;
|
|
outputColor = renderGraph.CreateTexture(outputDesc);
|
|
}
|
|
|
|
using (var builder = renderGraph.AddUnsafePass<DLSSGraphData>("Deep Learning Super Sampling", out DLSSGraphData passData, new ProfilingSampler("DLSS")))
|
|
{
|
|
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 --> DLSSGraphData)
|
|
passData.shouldReinitializeContext = ShouldResetDLSSContext(io);
|
|
|
|
passData.execData.mvScaleX = motionVectorSign * motionVectorScaleX;
|
|
passData.execData.mvScaleY = motionVectorSign * motionVectorScaleY;
|
|
passData.execData.subrectOffsetX = 0;
|
|
passData.execData.subrectOffsetY = 0;
|
|
passData.execData.subrectWidth = (uint)io.preUpscaleResolution.x;
|
|
passData.execData.subrectHeight = (uint)io.preUpscaleResolution.y;
|
|
passData.execData.jitterOffsetX = m_Jitter.x;
|
|
passData.execData.jitterOffsetY = m_Jitter.y;
|
|
passData.execData.preExposure = Mathf.Clamp(io.preExposureValue, 0.20f, 2.0f); // clamp to a reasonable value to prevent ghosting
|
|
passData.execData.invertYAxis = io.flippedY ? 1u : 0u;
|
|
passData.execData.invertXAxis = io.flippedX ? 1u : 0u;
|
|
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((DLSSGraphData data, UnsafeGraphContext ctx) =>
|
|
{
|
|
CommandBuffer cmd = CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd);
|
|
if (data.shouldReinitializeContext)
|
|
{
|
|
if (m_DLSSContext != null)
|
|
{
|
|
DestroyContext(ref m_DLSSContext, cmd);
|
|
}
|
|
CreateContext(ref m_DLSSContext, cmd, ref data, ref m_Options);
|
|
}
|
|
|
|
Debug.Assert(m_DLSSContext != null);
|
|
|
|
m_DLSSContext.executeData = data.execData;
|
|
DLSSTextureTable textureTable = new()
|
|
{
|
|
colorInput = data.colorInput,
|
|
depth = data.depth,
|
|
motionVectors = data.motionVectors,
|
|
colorOutput = data.colorOutput,
|
|
};
|
|
|
|
GraphicsDevice.device.ExecuteDLSS(cmd, m_DLSSContext, textureTable);
|
|
});
|
|
}
|
|
|
|
io.cameraColor = outputColor;
|
|
|
|
// record history
|
|
m_OutputResolutionPrevious = io.postUpscaleResolution;
|
|
m_QualityModeHistory = (DLSSQuality)m_Options.DLSSQualityMode;
|
|
m_PresetQualityHistory = (DLSSPreset)m_Options.DLSSRenderPresetQuality;
|
|
m_PresetBalancedHistory = (DLSSPreset)m_Options.DLSSRenderPresetBalanced;
|
|
m_PresetPerfHistory = (DLSSPreset)m_Options.DLSSRenderPresetPerformance;
|
|
m_PresetUltraPerfHistory = (DLSSPreset)m_Options.DLSSRenderPresetUltraPerformance;
|
|
m_PresetDLAAHistory = (DLSSPreset)m_Options.DLSSRenderPresetDLAA;
|
|
}
|
|
#endregion
|
|
|
|
|
|
#region DATA
|
|
// static data
|
|
private bool m_DLSSReady = false;
|
|
|
|
DLSSOptions m_Options = null;
|
|
DLSSQuality m_QualityModeHistory = DLSSQuality.DLAA;
|
|
DLSSPreset m_PresetQualityHistory = DLSSPreset.Preset_Default;
|
|
DLSSPreset m_PresetBalancedHistory = DLSSPreset.Preset_Default;
|
|
DLSSPreset m_PresetPerfHistory = DLSSPreset.Preset_Default;
|
|
DLSSPreset m_PresetUltraPerfHistory = DLSSPreset.Preset_Default;
|
|
DLSSPreset m_PresetDLAAHistory = DLSSPreset.Preset_Default;
|
|
|
|
// per-view DLSS data (per camera / per use)
|
|
private DLSSContext m_DLSSContext = null;
|
|
|
|
private Vector2Int m_OutputResolutionPrevious;
|
|
private Vector2Int m_InputResolution;
|
|
private Vector2Int m_OutputResolution;
|
|
private Vector2 m_Jitter;
|
|
#endregion
|
|
}
|
|
|
|
#endif // ENABLE_UPSCALER_FRAMEWORK && ENABLE_NVIDIA && ENABLE_NVIDIA_MODULE
|