using System; using System.Runtime.InteropServices; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using NVStreamline; namespace NVStreamline { [AddComponentMenu("NVIDIA/Streamline DLSS-G Builtin")] public class StreamlineDLSSG : MonoBehaviour { private CommandBuffer m_cmdCopyDepthAndMVecs; private CommandBuffer m_cmdCopyHudlessColor; private Camera m_camera; private uint m_id; public bool DLSSGFeatureAvailable { get; private set; } = false; #if false //Put 5x3Compute shader in test project and drag onto this in editor public ComputeShader TESTcs5x3 = null; #endif private void AttachCamera() { m_camera.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, m_cmdCopyDepthAndMVecs); m_camera.AddCommandBuffer(CameraEvent.AfterEverything, m_cmdCopyHudlessColor); ClearCommandLists(); } private void DetachCamera() { ClearCommandLists(); m_camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, m_cmdCopyDepthAndMVecs); m_camera.RemoveCommandBuffer(CameraEvent.AfterEverything, m_cmdCopyHudlessColor); } private void CreateCommandLists() { m_cmdCopyDepthAndMVecs = new CommandBuffer(); m_cmdCopyDepthAndMVecs.name = "Streamline DLSSG CopyDepthMVecs"; //Command list still required for sending Null tag m_cmdCopyHudlessColor = new CommandBuffer(); m_cmdCopyHudlessColor.name = "Streamline DLSSG CopyHudlessColor"; } private void DestroyCommandLists() { } void ClearCommandLists() { m_cmdCopyDepthAndMVecs.Clear(); m_cmdCopyHudlessColor.Clear(); #if !UNITY_EDITOR && UNITY_2019_1_OR_NEWER // On DX12 up until 2020.2 command lists that are being generated do not get flushed. // This causes incorrect ordering of plugin side command lists. // i.e. After submitted lists but before currently being generated lists. // We can force a flush in non-editor mode by creating a fence but never waiting for it. // Editor mode does not support GPUFence. GraphicsFence fence1 = m_cmdCopyDepthAndMVecs.CreateGraphicsFence(GraphicsFenceType.AsyncQueueSynchronisation, SynchronisationStageFlags.AllGPUOperations); GraphicsFence fence2 = m_cmdCopyHudlessColor.CreateGraphicsFence(GraphicsFenceType.AsyncQueueSynchronisation, SynchronisationStageFlags.AllGPUOperations); #endif } void SetupTextureBlits() { uint frameIndex = (uint)Time.frameCount; if (StreamlineDLSSGCore.DLSSGEnabled) { // Using this scale and bias rather than the draw&view rects as they were only relevant for editor rendering and Unity2019.4 // doesn't have the same Blit commands as 2021 (src and dest bias/scale) Vector2 scale = new Vector2(1.0f, -1.0f); Vector2 offset = new Vector2(0.0f, 1.0f); RenderTexture targetDepth = StreamlineDLSSGCore.GetTargetDepthTexture(); RenderTexture targetMVecs = StreamlineDLSSGCore.GetTargetMVecsTexture(); RenderTexture targetHudlessColor = StreamlineDLSSGCore.GetTargetHudlessColorTexture(); // Copy flipped textures bool deferred = m_camera.actualRenderingPath == RenderingPath.DeferredShading; RenderTargetIdentifier srcRtid = new RenderTargetIdentifier(deferred ? BuiltinRenderTextureType.ResolvedDepth : BuiltinRenderTextureType.Depth); m_cmdCopyDepthAndMVecs.Blit(srcRtid, targetDepth.colorBuffer, scale, offset); m_cmdCopyDepthAndMVecs.Blit(new RenderTargetIdentifier(BuiltinRenderTextureType.MotionVectors), targetMVecs, scale, offset); if (StreamlineDLSSGCore.UseHudlessColor) { m_cmdCopyHudlessColor.Blit(new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget), targetHudlessColor, scale, offset); } #if false if (TESTcs5x3) { int kernel = TESTcs5x3.FindKernel("Font5x3Draw"); int w = (4 * 6 * 32); int h = (5 * 32); Vector4 offsetsh = new Vector4(targetDepth.width / 3, targetDepth.height / 2, 0, 0); m_cmdCopyDepthAndMVecs.SetComputeTextureParam(TESTcs5x3, kernel, "_OutputDTexture", targetDepth, 0, RenderTextureSubElement.Color); m_cmdCopyDepthAndMVecs.SetComputeIntParam(TESTcs5x3, "_InputValue", (int)frameIndex); m_cmdCopyDepthAndMVecs.SetComputeIntParam(TESTcs5x3, "_Phase", 0); m_cmdCopyDepthAndMVecs.SetComputeVectorParam(TESTcs5x3, "_Offset", offsetsh); m_cmdCopyDepthAndMVecs.DispatchCompute(TESTcs5x3, kernel, w, h, 1); m_cmdCopyDepthAndMVecs.SetComputeTextureParam(TESTcs5x3, kernel, "_OutputMTexture", targetMVecs, 0, RenderTextureSubElement.Color); m_cmdCopyDepthAndMVecs.SetComputeIntParam(TESTcs5x3, "_InputValue", (int)frameIndex); m_cmdCopyDepthAndMVecs.SetComputeIntParam(TESTcs5x3, "_Phase", 1); m_cmdCopyDepthAndMVecs.SetComputeVectorParam(TESTcs5x3, "_Offset", offsetsh); m_cmdCopyDepthAndMVecs.DispatchCompute(TESTcs5x3, kernel, w, h, 1); if (StreamlineDLSSGCore.UseHudlessColor) { m_cmdCopyHudlessColor.SetComputeTextureParam(TESTcs5x3, kernel, "_OutputHTexture", targetHudlessColor, 0, RenderTextureSubElement.Color); m_cmdCopyHudlessColor.SetComputeIntParam(TESTcs5x3, "_InputValue", (int)frameIndex); m_cmdCopyHudlessColor.SetComputeIntParam(TESTcs5x3, "_Phase", 2); m_cmdCopyHudlessColor.SetComputeVectorParam(TESTcs5x3, "_Offset", offsetsh); m_cmdCopyHudlessColor.DispatchCompute(TESTcs5x3, kernel, w, h, 1); } } #endif } } public void SetupDepthAndMVecTextureTags(CommandBuffer cmd) { uint frameIndex = (uint)Time.frameCount; if (StreamlineDLSSGCore.DLSSGEnabled) { RenderTexture targetDepth = StreamlineDLSSGCore.GetTargetDepthTexture(); RenderTexture targetMVecs = StreamlineDLSSGCore.GetTargetMVecsTexture(); StreamlineCore.SetTag(cmd, frameIndex, m_id, targetDepth, StreamlineCore.BufferType.eBufferTypeDepth, 0); StreamlineCore.SetTag(cmd, frameIndex, m_id, targetMVecs, StreamlineCore.BufferType.eBufferTypeMVec, 0); } else { StreamlineCore.SetTag(cmd, frameIndex, m_id, null, StreamlineCore.BufferType.eBufferTypeDepth, 0); StreamlineCore.SetTag(cmd, frameIndex, m_id, null, StreamlineCore.BufferType.eBufferTypeMVec, 0); } } public void SetupHudlessColorTextureTags(CommandBuffer cmd) { uint frameIndex = (uint)Time.frameCount; if (StreamlineDLSSGCore.DLSSGEnabled && StreamlineDLSSGCore.UseHudlessColor) { RenderTexture targetHudlessColor = StreamlineDLSSGCore.GetTargetHudlessColorTexture(); StreamlineCore.SetTag(cmd, frameIndex, m_id, targetHudlessColor, StreamlineCore.BufferType.eBufferTypeHUDLessColor, 0); //StreamlineCore.SetTag(cmd, frameIndex, m_id, null, StreamlineCore.BufferType.eBufferTypeHUDLessColor, 0); } else { StreamlineCore.SetTag(cmd, frameIndex, m_id, null, StreamlineCore.BufferType.eBufferTypeHUDLessColor, 0); } } void Awake() { DLSSGFeatureAvailable = false; if (!StreamlineCore.IsFeatureSupported(StreamlineCore.Feature.eFeatureDLSS_G)) { Debug.Log("DLSSG is not supported"); return; } int id = StreamlineCore.CreateFeature(StreamlineCore.Feature.eFeatureDLSS_G); if (id != 0) //CreateFeature must return 0 for DLSSG { Debug.LogError("DLSSG Awake FAILED to get feature id"); return; } m_id = (uint)id; DLSSGFeatureAvailable = true; m_camera = GetComponent(); m_camera.depthTextureMode |= DepthTextureMode.Depth | DepthTextureMode.MotionVectors; CreateCommandLists(); } void OnDestroy() { if (DLSSGFeatureAvailable && m_id == 0) { StreamlineCore.DestroyFeature((int)m_id); } } void OnEnable() { if (DLSSGFeatureAvailable) { AttachCamera(); } } void OnDisable() { if (DLSSGFeatureAvailable) { DetachCamera(); } } // Update is called once per frame void LateUpdate() { if (DLSSGFeatureAvailable) { StreamlineDLSSGCore.ProcessDisposals(); if (StreamlineDLSSGCore.UpdateDrawRects(m_camera)) { //reallocate tagged textures StreamlineDLSSGCore.TaggedTextureDimensions tdd = StreamlineDLSSGCore.GetTaggedTextureDimensionsRef(); StreamlineDLSSGCore.AllocateTextures(tdd.m_currentDrawRect, tdd.m_currentViewRect, false, tdd.m_desktopScale, StreamlineDLSSGCore.UseHudlessColor); } if (GraphicsSettings.defaultRenderPipeline == null) //Built in only { ClearCommandLists(); SetupTextureBlits(); SetupDepthAndMVecTextureTags(m_cmdCopyDepthAndMVecs); SetupHudlessColorTextureTags(m_cmdCopyHudlessColor); StreamlineDLSSGCore.SetupDLSSGFeatureConstants(m_cmdCopyDepthAndMVecs, m_camera, m_id, (uint)Time.frameCount); } } } } }