diff --git a/TestProjects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs b/TestProjects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs index 21b14e6f223..7a05a98f49f 100644 --- a/TestProjects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs +++ b/TestProjects/UniversalGraphicsTest_2D/Assets/Test/Runtime/Renderer2DTests.cs @@ -54,10 +54,8 @@ public void BaseRendererDoesNotCreateRenderTexturesIfStackIsEmpty() return; Assert.IsFalse(baseRenderer.createColorTexture); - Assert.AreEqual(RenderTargetHandle.CameraTarget.Identifier(), baseRenderer.cameraColorTarget); Assert.IsFalse(baseRenderer.createDepthTexture); - Assert.AreEqual(RenderTargetHandle.CameraTarget.Identifier(), baseRenderer.cameraDepthTarget); } [Test] @@ -70,10 +68,8 @@ public void BaseRendererCreatesRenderTexturesIfStackIsNotEmpty() Renderer2D baseRenderer = m_BaseCameraData.scriptableRenderer as Renderer2D; Assert.IsTrue(baseRenderer.createColorTexture); - Assert.AreNotEqual(RenderTargetHandle.CameraTarget.Identifier(), baseRenderer.cameraColorTarget); Assert.IsTrue(baseRenderer.createDepthTexture); - Assert.AreNotEqual(RenderTargetHandle.CameraTarget.Identifier(), baseRenderer.cameraDepthTarget); } [Test] @@ -86,10 +82,8 @@ public void BaseRendererUsesDepthAttachmentOfColorTextureIfNoDepthTextureCreated Renderer2D baseRenderer = m_BaseCameraData.scriptableRenderer as Renderer2D; Assert.IsTrue(baseRenderer.createColorTexture); - Assert.AreNotEqual(RenderTargetHandle.CameraTarget.Identifier(), baseRenderer.cameraColorTarget); Assert.IsFalse(baseRenderer.createDepthTexture); - Assert.AreEqual(baseRenderer.cameraColorTarget, baseRenderer.cameraDepthTarget); } [Test] @@ -101,9 +95,6 @@ public void OverlayRendererUsesRenderTexturesFromBase() Renderer2D baseRenderer = m_BaseCameraData.scriptableRenderer as Renderer2D; Renderer2D overlayRenderer = m_OverlayCameraData.scriptableRenderer as Renderer2D; - - Assert.AreEqual(baseRenderer.cameraColorTarget, overlayRenderer.cameraColorTarget); - Assert.AreEqual(baseRenderer.cameraDepthTarget, overlayRenderer.cameraDepthTarget); } [Test] diff --git a/com.unity.render-pipelines.universal/CHANGELOG.md b/com.unity.render-pipelines.universal/CHANGELOG.md index a5c024c64a9..a0973f36e6b 100644 --- a/com.unity.render-pipelines.universal/CHANGELOG.md +++ b/com.unity.render-pipelines.universal/CHANGELOG.md @@ -171,6 +171,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Support undo of URP Global Settings asset assignation (case 1342987). - Removed unsupported fields from Presets of Light and Camera [case 1335979]. - Fixed graphical artefact when terrain height map is used with rendering layer mask for lighting. +- Fixed an issue where _AfterPostProcessTexture was no longer being assigned in UniversalRenderer. ### Changed - Change Asset/Create/Shader/Universal Render Pipeline/Lit Shader Graph to Asset/Create/Shader Graph/URP/Lit Shader Graph diff --git a/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs b/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs index 72f516bb227..3b1f0cfb827 100644 --- a/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs +++ b/com.unity.render-pipelines.universal/Runtime/Passes/FinalBlitPass.cs @@ -97,6 +97,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, // color RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare); // depth cmd.Blit(m_Source, cameraTarget, m_BlitMaterial); + cameraData.renderer.ConfigureCameraTarget(cameraTarget, cameraTarget); } else { @@ -116,6 +117,7 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData cmd.SetViewport(cameraData.pixelRect); cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial); cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix); + cameraData.renderer.ConfigureCameraTarget(cameraTarget, cameraTarget); } } diff --git a/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs b/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs index 619edfa04ff..4391cfec4cc 100644 --- a/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs +++ b/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs @@ -185,6 +185,8 @@ public void SetupFinalPass(in RenderTargetHandle source, bool useSwapBuffer = fa /// public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) { + overrideCameraTarget = true; + if (m_Destination == RenderTargetHandle.CameraTarget) return; @@ -329,6 +331,24 @@ void Render(CommandBuffer cmd, ref RenderingData renderingData) { ref CameraData cameraData = ref renderingData.cameraData; ref ScriptableRenderer renderer = ref cameraData.renderer; + bool isSceneViewCamera = cameraData.isSceneViewCamera; + + //Check amount of swaps we have to do + //We blit back and forth without msaa untill the last blit. + bool useStopNan = cameraData.isStopNaNEnabled && m_Materials.stopNaN != null; + bool useSubPixeMorpAA = cameraData.antialiasing == AntialiasingMode.SubpixelMorphologicalAntiAliasing && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2; + var dofMaterial = m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian ? m_Materials.gaussianDepthOfField : m_Materials.bokehDepthOfField; + bool useDepthOfField = m_DepthOfField.IsActive() && !isSceneViewCamera && dofMaterial != null; + bool useLensFlare = !LensFlareCommonSRP.Instance.IsEmpty(); + bool useMotionBlur = m_MotionBlur.IsActive() && !isSceneViewCamera; + bool usePaniniProjection = m_PaniniProjection.IsActive() && !isSceneViewCamera; + + int amountOfPassesRemaining = (useStopNan ? 1 : 0) + (useSubPixeMorpAA ? 1 : 0) + (useDepthOfField ? 1 : 0) + (useLensFlare ? 1 : 0) + (useMotionBlur ? 1 : 0) + (usePaniniProjection ? 1 : 0); + + if (m_UseSwapBuffer && amountOfPassesRemaining > 0) + { + renderer.EnableSwapBufferMSAA(false); + } // Don't use these directly unless you have a good reason to, use GetSource() and // GetDestination() instead @@ -336,7 +356,6 @@ void Render(CommandBuffer cmd, ref RenderingData renderingData) bool tempTarget2Used = false; RenderTargetIdentifier source = m_UseSwapBuffer ? renderer.cameraColorTarget : m_Source; RenderTargetIdentifier destination = m_UseSwapBuffer ? renderer.GetCameraColorFrontBuffer(cmd) : -1; - bool isSceneViewCamera = cameraData.isSceneViewCamera; RenderTargetIdentifier GetSource() => source; @@ -365,8 +384,15 @@ RenderTargetIdentifier GetDestination() void Swap(ref ScriptableRenderer r) { + --amountOfPassesRemaining; if (m_UseSwapBuffer) { + //we want the last blit to be to MSAA + if (amountOfPassesRemaining == 0 && !m_HasFinalPass) + { + r.EnableSwapBufferMSAA(true); + } + r.SwapColorBuffer(cmd); source = r.cameraColorTarget; destination = r.GetCameraColorFrontBuffer(cmd); @@ -382,7 +408,7 @@ void Swap(ref ScriptableRenderer r) // Optional NaN killer before post-processing kicks in // stopNaN may be null on Adreno 3xx. It doesn't support full shader level 3.5, but SystemInfo.graphicsShaderLevel is 35. - if (cameraData.isStopNaNEnabled && m_Materials.stopNaN != null) + if (useStopNan) { using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.StopNaNs))) { @@ -396,7 +422,7 @@ void Swap(ref ScriptableRenderer r) } // Anti-aliasing - if (cameraData.antialiasing == AntialiasingMode.SubpixelMorphologicalAntiAliasing && SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2) + if (useSubPixeMorpAA) { using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.SMAA))) { @@ -408,8 +434,7 @@ void Swap(ref ScriptableRenderer r) // Depth of Field // Adreno 3xx SystemInfo.graphicsShaderLevel is 35, but instancing support is disabled due to buggy drivers. // DOF shader uses #pragma target 3.5 which adds requirement for instancing support, thus marking the shader unsupported on those devices. - var dofMaterial = m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian ? m_Materials.gaussianDepthOfField : m_Materials.bokehDepthOfField; - if (m_DepthOfField.IsActive() && !isSceneViewCamera && dofMaterial != null) + if (useDepthOfField) { var markerName = m_DepthOfField.mode.value == DepthOfFieldMode.Gaussian ? URPProfileId.GaussianDepthOfField @@ -423,7 +448,7 @@ void Swap(ref ScriptableRenderer r) } // Motion blur - if (m_MotionBlur.IsActive() && !isSceneViewCamera) + if (useMotionBlur) { using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.MotionBlur))) { @@ -434,7 +459,7 @@ void Swap(ref ScriptableRenderer r) // Panini projection is done as a fullscreen pass after all depth-based effects are done // and before bloom kicks in - if (m_PaniniProjection.IsActive() && !isSceneViewCamera) + if (usePaniniProjection) { using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.PaniniProjection))) { @@ -444,7 +469,7 @@ void Swap(ref ScriptableRenderer r) } // Lens Flare - if (!LensFlareCommonSRP.Instance.IsEmpty()) + if (useLensFlare) { bool usePanini; float paniniDistance; @@ -565,6 +590,7 @@ void Swap(ref ScriptableRenderer r) #endif { cmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare); + cameraData.renderer.ConfigureCameraTarget(cameraTarget, cameraTarget); cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity); if ((m_Destination == RenderTargetHandle.CameraTarget && !m_UseSwapBuffer) || m_ResolveToScreen) @@ -600,6 +626,8 @@ void Swap(ref ScriptableRenderer r) if (tempTarget2Used) cmd.ReleaseTemporaryRT(ShaderConstants._TempTarget2); + + cmd.ReleaseTemporaryRT(m_InternalLut.id); } } @@ -1401,6 +1429,7 @@ void RenderFinalPass(CommandBuffer cmd, ref RenderingData renderingData) cmd.SetViewport(cameraData.pixelRect); cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material); cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix); + cameraData.renderer.ConfigureCameraTarget(cameraTarget, cameraTarget); } } diff --git a/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs b/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs index 4e3ab816297..222849288eb 100644 --- a/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs +++ b/com.unity.render-pipelines.universal/Runtime/RenderTargetBufferSystem.cs @@ -10,68 +10,115 @@ namespace UnityEngine.Rendering.Universal.Internal //NOTE: This class is meant to be removed when RTHandles get implemented in urp internal sealed class RenderTargetBufferSystem { - RenderTargetHandle RTA; - RenderTargetHandle RTB; - bool m_FirstIsBackBuffer = true; - RenderTextureDescriptor m_Desc; - FilterMode m_FilterMode; - - int m_NameA; - int m_NameB; + struct SwapBuffer + { + public RenderTargetHandle rt; + public int name; + public int msaa; + } + SwapBuffer m_A, m_B; + static bool m_AisBackBuffer = true; + static RenderTextureDescriptor m_Desc; + FilterMode m_FilterMode; + bool m_AllowMSAA = true; bool m_RTisAllocated = false; + SwapBuffer backBuffer { get { return m_AisBackBuffer ? m_A : m_B; } } + SwapBuffer frontBuffer { get { return m_AisBackBuffer ? m_B : m_A; } } + public RenderTargetBufferSystem(string name) { - m_NameA = Shader.PropertyToID(name + "A"); - m_NameB = Shader.PropertyToID(name + "B"); - RTA.Init(name + "A"); - RTB.Init(name + "B"); + m_A.name = Shader.PropertyToID(name + "A"); + m_B.name = Shader.PropertyToID(name + "B"); + m_A.rt.Init(name + "A"); + m_B.rt.Init(name + "B"); } public RenderTargetHandle GetBackBuffer() { - return m_FirstIsBackBuffer ? RTA : RTB; + return backBuffer.rt; } public RenderTargetHandle GetBackBuffer(CommandBuffer cmd) { if (!m_RTisAllocated) Initialize(cmd); - return m_FirstIsBackBuffer ? RTA : RTB; + return backBuffer.rt; } public RenderTargetHandle GetFrontBuffer(CommandBuffer cmd) { if (!m_RTisAllocated) Initialize(cmd); - return m_FirstIsBackBuffer ? RTB : RTA; + + int pipelineMSAA = m_Desc.msaaSamples; + int bufferMSAA = frontBuffer.msaa; + + if (m_AllowMSAA && bufferMSAA != pipelineMSAA) + { + //We don't want a depth buffer on B buffer + var desc = m_Desc; + if (m_AisBackBuffer) + desc.depthBufferBits = 0; + + cmd.ReleaseTemporaryRT(frontBuffer.name); + cmd.GetTemporaryRT(frontBuffer.name, desc, m_FilterMode); + + if (m_AisBackBuffer) + m_B.msaa = desc.msaaSamples; + else m_A.msaa = desc.msaaSamples; + } + else if (!m_AllowMSAA && bufferMSAA > 1) + { + //We don't want a depth buffer on B buffer + var desc = m_Desc; + desc.msaaSamples = 1; + if (m_AisBackBuffer) + desc.depthBufferBits = 0; + + cmd.ReleaseTemporaryRT(frontBuffer.name); + cmd.GetTemporaryRT(frontBuffer.name, desc, m_FilterMode); + + if (m_AisBackBuffer) + m_B.msaa = desc.msaaSamples; + else m_A.msaa = desc.msaaSamples; + } + + return frontBuffer.rt; } public void Swap() { - m_FirstIsBackBuffer = !m_FirstIsBackBuffer; + m_AisBackBuffer = !m_AisBackBuffer; } void Initialize(CommandBuffer cmd) { - cmd.GetTemporaryRT(m_NameA, m_Desc, m_FilterMode); + m_A.msaa = m_Desc.msaaSamples; + m_B.msaa = m_Desc.msaaSamples; + + cmd.GetTemporaryRT(m_A.name, m_Desc, m_FilterMode); var descB = m_Desc; - descB.depthBufferBits = 0; - cmd.GetTemporaryRT(m_NameB, m_Desc, m_FilterMode); + //descB.depthBufferBits = 0; + cmd.GetTemporaryRT(m_B.name, descB, m_FilterMode); + m_RTisAllocated = true; } public void Clear(CommandBuffer cmd) { - cmd.ReleaseTemporaryRT(m_NameA); - cmd.ReleaseTemporaryRT(m_NameB); + cmd.ReleaseTemporaryRT(m_A.name); + cmd.ReleaseTemporaryRT(m_B.name); - m_FirstIsBackBuffer = true; + m_AisBackBuffer = true; + m_AllowMSAA = true; } public void SetCameraSettings(CommandBuffer cmd, RenderTextureDescriptor desc, FilterMode filterMode) { + Clear(cmd); //SetCameraSettings is called when new stack starts rendering. Make sure the targets are updated to use the new descriptor. + m_Desc = desc; m_FilterMode = filterMode; @@ -80,7 +127,12 @@ public void SetCameraSettings(CommandBuffer cmd, RenderTextureDescriptor desc, F public RenderTargetHandle GetBufferA() { - return RTA; + return m_A.rt; + } + + public void EnableMSAA(bool enable) + { + m_AllowMSAA = enable; } } } diff --git a/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs b/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs index 66d8197edd5..a6ed15da98b 100644 --- a/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs +++ b/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs @@ -1320,6 +1320,7 @@ static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorAtt } internal virtual void SwapColorBuffer(CommandBuffer cmd) { } + internal virtual void EnableSwapBufferMSAA(bool enable) { } [Conditional("UNITY_EDITOR")] void DrawGizmos(ScriptableRenderContext context, Camera camera, GizmoSubset gizmoSubset) diff --git a/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs b/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs index a92bebcf382..7abb3d146a1 100644 --- a/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs +++ b/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs @@ -122,7 +122,6 @@ private static class Profiling internal ColorGradingLutPass colorGradingLutPass { get => m_PostProcessPasses.colorGradingLutPass; } internal PostProcessPass postProcessPass { get => m_PostProcessPasses.postProcessPass; } internal PostProcessPass finalPostProcessPass { get => m_PostProcessPasses.finalPostProcessPass; } - internal RenderTargetHandle afterPostProcessColor { get => m_PostProcessPasses.afterPostProcessColor; } internal RenderTargetHandle colorGradingLut { get => m_PostProcessPasses.colorGradingLut; } internal DeferredLights deferredLights { get => m_DeferredLights; } @@ -1022,6 +1021,8 @@ void CreateCameraRenderTarget(ScriptableRenderContext context, ref RenderTexture m_ActiveCameraColorAttachment = m_ColorBufferSystem.GetBackBuffer(cmd); cmd.SetGlobalTexture("_CameraColorTexture", m_ActiveCameraColorAttachment.id); + //Set _AfterPostProcessTexture, users might still rely on this although it is now always the cameratarget due to swapbuffer + cmd.SetGlobalTexture("_AfterPostProcessTexture", m_ActiveCameraColorAttachment.id); } if (m_ActiveCameraDepthAttachment != RenderTargetHandle.CameraTarget) @@ -1130,11 +1131,18 @@ internal override void SwapColorBuffer(CommandBuffer cmd) m_ActiveCameraColorAttachment = m_ColorBufferSystem.GetBackBuffer(); cmd.SetGlobalTexture("_CameraColorTexture", m_ActiveCameraColorAttachment.id); + //Set _AfterPostProcessTexture, users might still rely on this although it is now always the cameratarget due to swapbuffer + cmd.SetGlobalTexture("_AfterPostProcessTexture", m_ActiveCameraColorAttachment.id); } internal override RenderTargetIdentifier GetCameraColorFrontBuffer(CommandBuffer cmd) { return m_ColorBufferSystem.GetFrontBuffer(cmd).id; } + + internal override void EnableSwapBufferMSAA(bool enable) + { + m_ColorBufferSystem.EnableMSAA(enable); + } } }