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

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