using Unity.Scripting.LifecycleManagement; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering.Universal.Internal; using UnityEngine.Rendering.Universal.U2D.Profiler; using static UnityEngine.Rendering.Universal.UniversalResourceDataBase; using CommonResourceData = UnityEngine.Rendering.Universal.UniversalResourceData; namespace UnityEngine.Rendering.Universal { internal sealed partial class Renderer2D : ScriptableRenderer { private struct RenderPassInputSummary { internal bool requiresDepthTexture; internal bool requiresColorTexture; } private struct ImportResourceSummary { internal RenderTargetInfo importInfo; internal RenderTargetInfo importInfoDepth; internal ImportResourceParams cameraColorParams; internal ImportResourceParams cameraDepthParams; internal ImportResourceParams backBufferColorParams; internal ImportResourceParams backBufferDepthParams; } const int k_FinalBlitPassQueueOffset = 1; const int k_AfterFinalBlitPassQueueOffset = k_FinalBlitPassQueueOffset + 1; // TODO RENDERGRAPH: Once all cameras will run in a single RenderGraph we should remove all RTHandles and use per frame RG textures. // We use 2 camera color handles so we can handle the edge case when a pass might want to read and write the same target. // This is not allowed so we just swap the current target, this keeps camera stacking working and avoids an extra blit pass. [NoAutoStaticsCleanup] static int s_CurrentColorHandle = 0; [NoAutoStaticsCleanup] static readonly RTHandle[] s_RenderGraphCameraColorHandles = { null, null }; [NoAutoStaticsCleanup] internal static RTHandle s_RenderGraphCameraDepthHandle; [NoAutoStaticsCleanup] static RTHandle s_OffscreenUIColorHandle; #if ENABLE_PROFILER && PROFILER_INSTALLED [NoAutoStaticsCleanup] static bool s_CanProfilerCapture; #if UNITY_2D_URP_TESTS // Do not do any capture in test due to the current profiling requires memory allocation which causes tests to fail. // We should look into a way to capture profiler data without allocations in the future and re-enable this for tests as well. internal static bool canProfilerCapture => false && s_CanProfilerCapture; #else internal static bool canProfilerCapture => s_CanProfilerCapture && UnityEngine.Profiling.Profiler.enabled; #endif #endif RTHandle m_RenderGraphBackbufferColorHandle; RTHandle m_RenderGraphBackbufferDepthHandle; RTHandle m_CameraSortingLayerHandle; Material m_BlitMaterial; Material m_BlitHDRMaterial; Material m_BlitOffscreenUICoverMaterial; Material m_SamplingMaterial; Material m_BackdropFilterCompositeMaterial; // 2D specific render passes CameraRenderingLayerMaskPass m_RenderingLayerMaskPass = new CameraRenderingLayerMaskPass(); DrawNormal2DPass m_NormalPass = new DrawNormal2DPass(); DrawLight2DPass m_LightPass = new DrawLight2DPass(); DrawShadow2DPass m_ShadowPass = new DrawShadow2DPass(); DrawRenderer2DPass m_RendererPass = new DrawRenderer2DPass(); CopyDepthPass m_CopyDepthPass; UpscalePass m_UpscalePass; CopyCameraSortingLayerPass m_CopyCameraSortingLayerPass; CapturePass m_CapturePass; FinalBlitPass m_FinalBlitPass; FinalBlitPass m_OffscreenUICoverPrepass; DrawScreenSpaceUIPass m_DrawOffscreenUIPass; DrawScreenSpaceUIPass m_DrawOverlayUIPass; // from HDRP code Renderer2DData m_Renderer2DData; internal bool m_CreateColorTexture; internal bool m_CreateDepthTexture; bool ppcUpscaleRT = false; PostProcess m_PostProcess; ColorGradingLutPass m_ColorGradingLutPassRenderGraph; private RTHandle currentRenderGraphCameraColorHandle { get { return s_RenderGraphCameraColorHandles[s_CurrentColorHandle]; } } // get the next m_RenderGraphCameraColorHandles and make it the new current for future accesses private RTHandle nextRenderGraphCameraColorHandle { get { s_CurrentColorHandle = (s_CurrentColorHandle + 1) % 2; return currentRenderGraphCameraColorHandle; } } /// public override int SupportedCameraStackingTypes() { return 1 << (int)CameraRenderType.Base | 1 << (int)CameraRenderType.Overlay; } public Renderer2D(Renderer2DData data) : base(data) { if (GraphicsSettings.TryGetRenderPipelineSettings(out var shadersResources)) { m_BlitMaterial = CoreUtils.CreateEngineMaterial(shadersResources.coreBlitPS); m_BlitHDRMaterial = CoreUtils.CreateEngineMaterial(shadersResources.blitHDROverlay); m_BlitOffscreenUICoverMaterial = CoreUtils.CreateEngineMaterial(shadersResources.blitHDROverlay); m_SamplingMaterial = CoreUtils.CreateEngineMaterial(shadersResources.samplingPS); m_BackdropFilterCompositeMaterial = CoreUtils.CreateEngineMaterial(shadersResources.uiBackdropFilterCompositePS); } if (GraphicsSettings.TryGetRenderPipelineSettings(out var renderer2DResources)) { m_CopyDepthPass = new CopyDepthPass( RenderPassEvent.AfterRenderingTransparents, renderer2DResources.copyDepthPS, shouldClear: true); } m_UpscalePass = new UpscalePass(RenderPassEvent.AfterRenderingPostProcessing, m_BlitMaterial); m_CopyCameraSortingLayerPass = new CopyCameraSortingLayerPass(m_BlitMaterial); m_CapturePass = new CapturePass(RenderPassEvent.AfterRendering); m_FinalBlitPass = new FinalBlitPass(RenderPassEvent.AfterRendering + k_FinalBlitPassQueueOffset, m_BlitMaterial, m_BlitHDRMaterial); m_OffscreenUICoverPrepass = new FinalBlitPass(RenderPassEvent.BeforeRenderingPostProcessing, m_BlitMaterial, m_BlitOffscreenUICoverMaterial); m_DrawOffscreenUIPass = new DrawScreenSpaceUIPass(RenderPassEvent.BeforeRenderingPostProcessing); m_DrawOverlayUIPass = new DrawScreenSpaceUIPass(RenderPassEvent.AfterRendering + k_AfterFinalBlitPassQueueOffset, m_BackdropFilterCompositeMaterial, m_BlitMaterial); // after m_FinalBlitPass m_Renderer2DData = data; m_Renderer2DData.lightCullResult = new Light2DCullResult(); UpdateSupportedRenderingFeatures(); LensFlareCommonSRP.mergeNeeded = 0; LensFlareCommonSRP.maxLensFlareWithOcclusionTemporalSample = 1; LensFlareCommonSRP.Initialize(); Light2DManager.Initialize(); if (data.postProcessData != null) { m_PostProcess = new PostProcess(data.postProcessData); m_ColorGradingLutPassRenderGraph = new ColorGradingLutPass(RenderPassEvent.BeforeRenderingPrePasses, data.postProcessData); } PlatformAutoDetect.Initialize(); #if ENABLE_VR && ENABLE_XR_MODULE if (GraphicsSettings.TryGetRenderPipelineSettings(out var xrResources)) { XRSystem.Initialize(XRPassUniversal.Create, xrResources.xrOcclusionMeshPS, xrResources.xrMirrorViewPS); } #endif } internal override void UpdateSupportedRenderingFeatures() { // Only set supported rendering features that apply to 2D supportedRenderingFeatures.supportsHDR = true; supportedRenderingFeatures.postProcessing = m_Renderer2DData.postProcessData != null; supportedRenderingFeatures.cameraDepthTexture = true; supportedRenderingFeatures.upscaling = true; supportedRenderingFeatures.antiAliasing = true; supportedRenderingFeatures.overlayCamera = true; supportedRenderingFeatures.msaa = true; foreach (var feature in rendererFeatures) { if (feature.isActive) { supportedRenderingFeatures.postProcessing |= feature.supportedRenderingFeatures.postProcessing; } } // Setting the engine wide feature flags here as well. We can likely phase these out. SupportedRenderingFeatures.active.supportsHDR = supportedRenderingFeatures.supportsHDR; } internal static bool IsDepthUsageAllowed(ContextContainer frameData, Renderer2DData rendererData) { UniversalCameraData cameraData = frameData.Get(); // Renderer2DData.useDepthStencilBuffer bool allowDepth = rendererData.useDepthStencilBuffer; // 3D Render Textures with depth/stencil buffer are not supported if (cameraData.targetTexture != null) allowDepth &= cameraData.targetTexture.dimension != TextureDimension.Tex3D; // The back buffer has none when PlayerSettings.disableDepthAndStencilBuffers is enabled on a graphics API that acts on it allowDepth &= Graphics.backBufferHasDepthStencil; return allowDepth; } private bool IsPixelPerfectCameraEnabled(UniversalCameraData cameraData, out PixelPerfectCamera ppc) { ppc = null; // Pixel Perfect Camera doesn't support camera stacking. if (cameraData.renderType == CameraRenderType.Base && cameraData.resolveFinalTarget) cameraData.camera.TryGetComponent(out ppc); return ppc != null && ppc.enabled; } private RenderPassInputSummary GetRenderPassInputs() { UniversalCameraData cameraData = frameData.Get(); RenderPassInputSummary inputSummary = new RenderPassInputSummary(); for (int i = 0; i < activeRenderPassQueue.Count; ++i) { ScriptableRenderPass pass = activeRenderPassQueue[i]; bool needsDepth = (pass.input & ScriptableRenderPassInput.Depth) != ScriptableRenderPassInput.None; bool needsColor = (pass.input & ScriptableRenderPassInput.Color) != ScriptableRenderPassInput.None; inputSummary.requiresDepthTexture |= needsDepth; inputSummary.requiresColorTexture |= needsColor; inputSummary.requiresColorTexture |= pass.requiresIntermediateTexture; } // Volumetric shadow pass requires intermediate texture bool hasVolumetricShadowPass = false; var layerBatches = frameData.Get().layerBatches; var batchCount = frameData.Get().batchCount; for (int i = 0; i < batchCount; ++i) hasVolumetricShadowPass |= layerBatches[i].lightStats.useVolumetricShadowLights; inputSummary.requiresColorTexture |= cameraData.postProcessEnabled || cameraData.isHdrEnabled || cameraData.isSceneViewCamera || !cameraData.isDefaultViewport || cameraData.requireSrgbConversion || !cameraData.resolveFinalTarget || cameraData.cameraTargetDescriptor.msaaSamples > 1 && UniversalRenderer.PlatformRequiresExplicitMsaaResolve() || m_Renderer2DData.useCameraSortingLayerTexture || !Mathf.Approximately(cameraData.renderScale, 1.0f) || (DebugHandler != null && DebugHandler.WriteToDebugScreenTexture(cameraData.resolveFinalTarget)) || cameraData.captureActions != null || hasVolumetricShadowPass; return inputSummary; } ImportResourceSummary GetImportResourceSummary(RenderGraph renderGraph, UniversalCameraData cameraData) { ImportResourceSummary output = new ImportResourceSummary(); bool clearColor = cameraData.renderType == CameraRenderType.Base; bool clearDepth = cameraData.renderType == CameraRenderType.Base || cameraData.clearDepth; // Clear back buffer color if pixel perfect crop frame is used // Non-base cameras the back buffer should never be cleared bool ppcEnabled = IsPixelPerfectCameraEnabled(cameraData, out var ppc) && ppc.cropFrame != PixelPerfectCamera.CropFrame.None; bool clearColorBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && (!m_CreateColorTexture || ppcEnabled); bool clearDepthBackbufferOnFirstUse = (cameraData.renderType == CameraRenderType.Base) && !m_CreateColorTexture; // if the camera background type is "uninitialized" clear using a yellow color, so users can clearly understand the underlying behaviour Color cameraBackgroundColor = (cameraData.camera.clearFlags == CameraClearFlags.Nothing) ? Color.yellow : cameraData.backgroundColor; Color backBufferBackgroundColor = ppcEnabled ? Color.black : cameraBackgroundColor; if (IsSceneFilteringEnabled(cameraData.camera)) { cameraBackgroundColor.a = 0; clearDepth = false; } // Certain debug modes (e.g. wireframe/overdraw modes) require that we override clear flags and clear everything. var debugHandler = cameraData.renderer.DebugHandler; if (debugHandler != null && debugHandler.IsActiveForCamera(cameraData.isPreviewCamera) && debugHandler.IsScreenClearNeeded) { clearColor = true; clearDepth = true; debugHandler.TryGetScreenClearColor(ref cameraBackgroundColor); } output.cameraColorParams.clearOnFirstUse = clearColor; output.cameraColorParams.clearColor = cameraBackgroundColor; output.cameraColorParams.discardOnLastUse = false; output.cameraDepthParams.clearOnFirstUse = clearDepth; output.cameraDepthParams.clearColor = cameraBackgroundColor; output.cameraDepthParams.discardOnLastUse = false; output.backBufferColorParams.clearOnFirstUse = clearColorBackbufferOnFirstUse; output.backBufferColorParams.clearColor = backBufferBackgroundColor; output.backBufferColorParams.discardOnLastUse = false; output.backBufferDepthParams.clearOnFirstUse = clearDepthBackbufferOnFirstUse; output.backBufferDepthParams.clearColor = backBufferBackgroundColor; output.backBufferDepthParams.discardOnLastUse = true; bool isBuiltInTexture = cameraData.targetTexture == null; TextureUVOrigin backbufferTextureUVOrigin = RenderingUtils.GetBackBufferUVOrientation(cameraData); output.backBufferColorParams.textureUVOrigin = backbufferTextureUVOrigin; output.backBufferDepthParams.textureUVOrigin = backbufferTextureUVOrigin; #if ENABLE_VR && ENABLE_XR_MODULE if (cameraData.xr.enabled) { isBuiltInTexture = false; } #endif if (!isBuiltInTexture) { #if ENABLE_VR && ENABLE_XR_MODULE if (cameraData.xr.enabled) { output.importInfo.width = cameraData.xr.renderTargetDesc.width; output.importInfo.height = cameraData.xr.renderTargetDesc.height; output.importInfo.volumeDepth = cameraData.xr.renderTargetDesc.volumeDepth; output.importInfo.msaaSamples = cameraData.xr.renderTargetDesc.msaaSamples; output.importInfo.format = cameraData.xr.renderTargetDesc.graphicsFormat; if (!UniversalRenderer.PlatformRequiresExplicitMsaaResolve()) output.importInfo.bindMS = output.importInfo.msaaSamples > 1; output.importInfoDepth = output.importInfo; output.importInfoDepth.format = cameraData.xr.renderTargetDesc.depthStencilFormat; } else #endif { output.importInfo.width = cameraData.targetTexture.width; output.importInfo.height = cameraData.targetTexture.height; output.importInfo.volumeDepth = cameraData.targetTexture.volumeDepth; output.importInfo.msaaSamples = cameraData.targetTexture.antiAliasing; output.importInfo.format = cameraData.targetTexture.graphicsFormat; output.importInfoDepth = output.importInfo; output.importInfoDepth.format = cameraData.targetTexture.depthStencilFormat; // We let users know that a depth format is required for correct usage, but we fallback to the old default depth format behaviour to avoid regressions if (output.importInfoDepth.format == GraphicsFormat.None) { output.importInfoDepth.format = SystemInfo.GetGraphicsFormat(DefaultFormat.DepthStencil); Debug.LogWarning("In the render graph API, the output Render Texture must have a depth buffer. When you select a Render Texture in any camera's Output Texture property, the Depth Stencil Format property of the texture must be set to a value other than None."); } } } else { // Import the live back buffer sample count; it always matches the real surface even when a // pending Screen.SetMSAASamples request hasn't been applied yet (deferred reallocation). int numSamples = Screen.currentBackbufferMSAASamples; //NOTE: Careful what you use here as many of the properties bake-in the camera rect so for example //cameraData.cameraTargetDescriptor.width is the width of the rectangle but not the actual render target //same with cameraData.camera.pixelWidth output.importInfo.width = Screen.width; output.importInfo.height = Screen.height; output.importInfo.volumeDepth = 1; output.importInfo.msaaSamples = numSamples; output.importInfo.format = cameraData.cameraTargetDescriptor.graphicsFormat; output.importInfoDepth = output.importInfo; output.importInfoDepth.format = SystemInfo.GetGraphicsFormat(DefaultFormat.DepthStencil); } return output; } public override void SetupCullingParameters(ref ScriptableCullingParameters cullingParameters, ref CameraData cameraData) { cullingParameters.cullingOptions = CullingOptions.None; cullingParameters.isOrthographic = cameraData.camera.orthographic; cullingParameters.shadowDistance = 0.0f; var cullResult = m_Renderer2DData.lightCullResult as Light2DCullResult; cullResult.SetupCulling(ref cullingParameters, cameraData.camera); } void InitializeLayerBatches() { Universal2DResourceData resourceData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); Universal2DRenderingData renderData = frameData.Get(); ref var layerBatches = ref renderData.layerBatches; layerBatches = LayerUtility.CalculateBatches(renderData.renderingData, out var batchCount); renderData.batchCount = batchCount; // Initialize textures dependent on batch size if (resourceData.normalsTexture.Length != batchCount) resourceData.normalsTexture = new TextureHandle[batchCount]; if (resourceData.shadowTextures.Length != batchCount) resourceData.shadowTextures = new TextureHandle[batchCount][]; if (resourceData.lightTextures.Length != batchCount) resourceData.lightTextures = new TextureHandle[batchCount][]; // Initialize light textures based on active blend styles to save on resources for (int i = 0; i < resourceData.lightTextures.Length; ++i) { if (resourceData.lightTextures[i] == null || resourceData.lightTextures[i].Length != layerBatches[i].activeBlendStylesIndices.Length) resourceData.lightTextures[i] = new TextureHandle[layerBatches[i].activeBlendStylesIndices.Length]; } for (int i = 0; i < resourceData.shadowTextures.Length; ++i) { if (resourceData.shadowTextures[i] == null || resourceData.shadowTextures[i].Length != layerBatches[i].shadowIndices.Count) resourceData.shadowTextures[i] = new TextureHandle[layerBatches[i].shadowIndices.Count]; } } void CreateResources(RenderGraph renderGraph) { Universal2DResourceData universal2DResourceData = frameData.Get(); CommonResourceData commonResourceData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); ref var cameraTargetDescriptor = ref cameraData.cameraTargetDescriptor; var cameraTargetFilterMode = FilterMode.Bilinear; bool lastCameraInTheStack = cameraData.resolveFinalTarget; #if UNITY_EDITOR // The scene view camera cannot be uninitialized or skybox when using the 2D renderer. if (cameraData.cameraType == CameraType.SceneView) { cameraData.camera.clearFlags = CameraClearFlags.SolidColor; } #endif bool forceCreateColorTexture = false; // Pixel Perfect Camera doesn't support camera stacking. if (cameraData.renderType == CameraRenderType.Base && lastCameraInTheStack) { cameraData.camera.TryGetComponent(out var ppc); if (ppc != null && ppc.enabled) { if (ppc.offscreenRTSize != Vector2Int.zero) { forceCreateColorTexture = true; // Pixel Perfect Camera may request a different RT size than camera VP size. // In that case we need to modify cameraTargetDescriptor here so that all the passes would use the same size. cameraTargetDescriptor.width = ppc.offscreenRTSize.x; cameraTargetDescriptor.height = ppc.offscreenRTSize.y; } cameraTargetFilterMode = FilterMode.Point; ppcUpscaleRT = ppc.gridSnapping == PixelPerfectCamera.GridSnapping.UpscaleRenderTexture || ppc.requiresUpscalePass; if (ppc.requiresUpscalePass) { var upscaleDescriptor = cameraTargetDescriptor; upscaleDescriptor.width = ppc.refResolutionX * ppc.pixelRatio; upscaleDescriptor.height = ppc.refResolutionY * ppc.pixelRatio; upscaleDescriptor.depthStencilFormat = GraphicsFormat.None; universal2DResourceData.upscaleTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, upscaleDescriptor, "_UpscaleTexture", true, ppc.finalBlitFilterMode); } } } // Account for Quality->Render Scale and Light Texture Render Scale var renderTextureScale = m_Renderer2DData.lightRenderTextureScale; var width = (int)Mathf.Max(1, cameraTargetDescriptor.width * renderTextureScale); var height = (int)Mathf.Max(1, cameraTargetDescriptor.height * renderTextureScale); // Normals and Light textures have to be of the same renderTextureScale, to prevent any sampling artifacts during lighting calculations CreateCameraNormalsTextures(renderGraph, cameraTargetDescriptor, width, height); CreateLightTextures(renderGraph, width, height); CreateShadowTextures(renderGraph, width, height); CreateCameraSortingLayerTexture(renderGraph, cameraTargetDescriptor); CreateRenderingLayersTexture(renderGraph, width, height); // Create the attachments if (cameraData.renderType == CameraRenderType.Base) // require intermediate textures { RenderPassInputSummary renderPassInputs = GetRenderPassInputs(); m_CreateColorTexture = renderPassInputs.requiresColorTexture; m_CreateDepthTexture = renderPassInputs.requiresDepthTexture; m_CreateColorTexture |= forceCreateColorTexture; // Backdrop-filter compositing needs an intermediate color target to sample. m_CreateColorTexture |= m_DrawOverlayUIPass.RequiresComposition(); // RTHandles do not support combining color and depth in the same texture so we create them separately m_CreateDepthTexture |= m_CreateColorTexture; m_CreateDepthTexture &= IsDepthUsageAllowed(frameData, m_Renderer2DData); // Camera Target Color if (m_CreateColorTexture) { cameraTargetDescriptor.useMipMap = false; cameraTargetDescriptor.autoGenerateMips = false; cameraTargetDescriptor.depthStencilFormat = GraphicsFormat.None; RenderingUtils.ReAllocateHandleIfNeeded(ref s_RenderGraphCameraColorHandles[0], cameraTargetDescriptor, cameraTargetFilterMode, TextureWrapMode.Clamp, name: "_CameraTargetAttachmentA"); RenderingUtils.ReAllocateHandleIfNeeded(ref s_RenderGraphCameraColorHandles[1], cameraTargetDescriptor, cameraTargetFilterMode, TextureWrapMode.Clamp, name: "_CameraTargetAttachmentB"); commonResourceData.activeColorID = ActiveID.Camera; } else commonResourceData.activeColorID = ActiveID.BackBuffer; // Camera Target Depth if (m_CreateDepthTexture) { var depthDescriptor = cameraData.cameraTargetDescriptor; depthDescriptor.useMipMap = false; depthDescriptor.autoGenerateMips = false; bool hasMSAA = depthDescriptor.msaaSamples > 1; depthDescriptor.bindMS = hasMSAA && RenderingUtils.ShouldDepthAttachmentBindMS(); depthDescriptor.graphicsFormat = GraphicsFormat.None; depthDescriptor.depthStencilFormat = CoreUtils.GetDefaultDepthStencilFormat(); RenderingUtils.ReAllocateHandleIfNeeded(ref s_RenderGraphCameraDepthHandle, depthDescriptor, FilterMode.Point, TextureWrapMode.Clamp, name: "_CameraDepthAttachment"); commonResourceData.activeDepthID = ActiveID.Camera; } else commonResourceData.activeDepthID = ActiveID.BackBuffer; } else // Overlay camera { cameraData.baseCamera.TryGetComponent(out var baseCameraData); var baseRenderer = (Renderer2D)baseCameraData.scriptableRenderer; m_RenderGraphBackbufferColorHandle = baseRenderer.m_RenderGraphBackbufferColorHandle; m_RenderGraphBackbufferDepthHandle = baseRenderer.m_RenderGraphBackbufferDepthHandle; m_CreateColorTexture = baseRenderer.m_CreateColorTexture; m_CreateDepthTexture = baseRenderer.m_CreateDepthTexture; commonResourceData.activeColorID = m_CreateColorTexture ? ActiveID.Camera : ActiveID.BackBuffer; commonResourceData.activeDepthID = m_CreateDepthTexture ? ActiveID.Camera : ActiveID.BackBuffer; } // Report this camera's real back buffer MSAA need; a 2D camera renders directly to it only when // no intermediate color texture is created (m_CreateColorTexture == false). ReportRealBackbufferMSAA(cameraData, m_CreateColorTexture); ImportResourceSummary importSummary = GetImportResourceSummary(renderGraph, cameraData); if (m_CreateColorTexture) { importSummary.cameraColorParams.discardOnLastUse = lastCameraInTheStack; commonResourceData.cameraColor = renderGraph.ImportTexture(currentRenderGraphCameraColorHandle, importSummary.cameraColorParams); } if (m_CreateDepthTexture) { importSummary.cameraDepthParams.discardOnLastUse = lastCameraInTheStack; commonResourceData.cameraDepth = renderGraph.ImportTexture(s_RenderGraphCameraDepthHandle, importSummary.cameraDepthParams); } RenderTargetIdentifier targetColorId = cameraData.targetTexture != null ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.CameraTarget; RenderTargetIdentifier targetDepthId = cameraData.targetTexture != null ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.Depth; #if ENABLE_VR && ENABLE_XR_MODULE if (cameraData.xr.enabled) { targetColorId = cameraData.xr.renderTarget; targetDepthId = cameraData.xr.renderTarget; } #endif if (m_RenderGraphBackbufferColorHandle == null) { m_RenderGraphBackbufferColorHandle = RTHandles.Alloc(targetColorId, "Backbuffer color"); } else if (m_RenderGraphBackbufferColorHandle.nameID != targetColorId) { RTHandleStaticHelpers.SetRTHandleUserManagedWrapper(ref m_RenderGraphBackbufferColorHandle, targetColorId); } commonResourceData.backBufferColor = renderGraph.ImportTexture(m_RenderGraphBackbufferColorHandle, importSummary.importInfo, importSummary.backBufferColorParams); if (IsDepthUsageAllowed(frameData, m_Renderer2DData)) { if (m_RenderGraphBackbufferDepthHandle == null) { m_RenderGraphBackbufferDepthHandle = RTHandles.Alloc(targetDepthId, "Backbuffer depth"); } else if (m_RenderGraphBackbufferDepthHandle.nameID != targetDepthId) { RTHandleStaticHelpers.SetRTHandleUserManagedWrapper(ref m_RenderGraphBackbufferDepthHandle, targetDepthId); } commonResourceData.backBufferDepth = renderGraph.ImportTexture(m_RenderGraphBackbufferDepthHandle, importSummary.importInfoDepth, importSummary.backBufferDepthParams); } if (RequiresDepthCopyPass()) CreateCameraDepthCopyTexture(renderGraph, cameraTargetDescriptor); if (cameraData.isHDROutputActive && cameraData.rendersOverlayUI) CreateOffscreenUITexture(renderGraph, cameraTargetDescriptor); } void CreateCameraNormalsTextures(RenderGraph renderGraph, RenderTextureDescriptor descriptor, int width, int height) { Universal2DResourceData resourceData = frameData.Get(); var layerBatches = frameData.Get().layerBatches; var desc = new RenderTextureDescriptor(width, height); desc.graphicsFormat = RendererLighting.GetRenderTextureFormat(); desc.autoGenerateMips = false; desc.msaaSamples = descriptor.msaaSamples; bool useNormals = false; for (int i = 0; i < resourceData.normalsTexture.Length; ++i) { useNormals |= layerBatches[i].useNormals; if (layerBatches[i].useNormals) { resourceData.normalsTexture[i] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "_NormalMap", true, RendererLighting.k_NormalClearColor); #if ENABLE_PROFILER && PROFILER_INSTALLED if (canProfilerCapture) ProfilerMarkers.s_U2DNormalMapProfilerCounterValue.Value++; #endif } } if (useNormals && IsDepthUsageAllowed(frameData, m_Renderer2DData)) { // Normals pass can reuse active depth if same dimensions, if not create a new depth texture #if !(ENABLE_VR && ENABLE_XR_MODULE) if (descriptor.width != width || descriptor.height != height) #endif { var normalsDepthDesc = new RenderTextureDescriptor(width, height); normalsDepthDesc.graphicsFormat = GraphicsFormat.None; normalsDepthDesc.autoGenerateMips = false; normalsDepthDesc.msaaSamples = descriptor.msaaSamples; normalsDepthDesc.depthStencilFormat = CoreUtils.GetDefaultDepthStencilFormat(); resourceData.normalsDepth = UniversalRenderer.CreateRenderGraphTexture(renderGraph, normalsDepthDesc, "_NormalDepth", false, FilterMode.Bilinear); } } } void CreateLightTextures(RenderGraph renderGraph, int width, int height) { UniversalCameraData cameraData = frameData.Get(); Universal2DResourceData resourceData = frameData.Get(); var layerBatches = frameData.Get().layerBatches; var desc = new RenderTextureDescriptor(width, height); desc.graphicsFormat = RendererLighting.GetRenderTextureFormat(); desc.autoGenerateMips = false; for (int i = 0; i < resourceData.lightTextures.Length; ++i) { for (var j = 0; j < layerBatches[i].activeBlendStylesIndices.Length; ++j) { var index = layerBatches[i].activeBlendStylesIndices[j]; if (!Light2DManager.GetGlobalColor(layerBatches[i].startLayerID, index, cameraData.camera, out var clearColor)) clearColor = Color.black; resourceData.lightTextures[i][j] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, RendererLighting.k_ShapeLightTextureIDs[index], true, clearColor, FilterMode.Bilinear); #if ENABLE_PROFILER && PROFILER_INSTALLED if (canProfilerCapture) ProfilerMarkers.s_U2DLightProfilerCounterValue.Value++; #endif } } } void CreateShadowTextures(RenderGraph renderGraph, int width, int height) { Universal2DResourceData resourceData = frameData.Get(); var layerBatches = frameData.Get().layerBatches; var shadowDesc = new RenderTextureDescriptor(width, height); shadowDesc.graphicsFormat = GraphicsFormat.B10G11R11_UFloatPack32; shadowDesc.autoGenerateMips = false; for (int i = 0; i < resourceData.shadowTextures.Length; ++i) { for (var j = 0; j < layerBatches[i].shadowIndices.Count; ++j) { resourceData.shadowTextures[i][j] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, shadowDesc, "_ShadowTex", false, FilterMode.Bilinear); #if ENABLE_PROFILER && PROFILER_INSTALLED if (canProfilerCapture) ProfilerMarkers.s_U2DShadowProfilerCounterValue.Value++; #endif } } var shadowDepthDesc = new RenderTextureDescriptor(width, height); shadowDepthDesc.graphicsFormat = GraphicsFormat.None; shadowDepthDesc.autoGenerateMips = false; shadowDepthDesc.depthStencilFormat = CoreUtils.GetDefaultDepthStencilFormat(); resourceData.shadowDepth = UniversalRenderer.CreateRenderGraphTexture(renderGraph, shadowDepthDesc, "_ShadowDepth", false, FilterMode.Bilinear); } void CreateCameraSortingLayerTexture(RenderGraph renderGraph, RenderTextureDescriptor cameraDesc) { if (m_Renderer2DData.useCameraSortingLayerTexture) { Universal2DResourceData resourceData = frameData.Get(); CopyCameraSortingLayerPass.ConfigureDescriptor(m_Renderer2DData.cameraSortingLayerDownsamplingMethod, ref cameraDesc, out var filterMode); RenderingUtils.ReAllocateHandleIfNeeded(ref m_CameraSortingLayerHandle, cameraDesc, filterMode, TextureWrapMode.Clamp, name: CopyCameraSortingLayerPass.k_CameraSortingLayerTexture); resourceData.cameraSortingLayerTexture = renderGraph.ImportTexture(m_CameraSortingLayerHandle); } } void CreateRenderingLayersTexture(RenderGraph renderGraph, int width, int height) { if (m_Renderer2DData.useRenderingLayers) { var resourceData = frameData.Get(); int count = RenderingLayerMask.GetRenderingLayerCount(); m_Renderer2DData.renderingLayersMaskSize = RenderingLayerUtils.GetMaskSize(count); var desc = new RenderTextureDescriptor(width, height); desc.graphicsFormat = RenderingLayerUtils.GetFormat(m_Renderer2DData.renderingLayersMaskSize); desc.autoGenerateMips = false; resourceData.renderingLayersTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, CameraRenderingLayerMaskPass.k_RenderingLayersTextureName, true); } } bool RequiresDepthCopyPass() { UniversalCameraData cameraData = frameData.Get(); var renderPassInputs = GetRenderPassInputs(); bool requiresDepthTexture = cameraData.requiresDepthTexture || renderPassInputs.requiresDepthTexture; bool cameraHasPostProcessingWithDepth = cameraData.postProcessEnabled && m_PostProcess != null && (cameraData.postProcessingRequiresDepthTexture || !LensFlareCommonSRP.Instance.IsEmpty()); bool requiresDepthCopyPass = (cameraHasPostProcessingWithDepth || requiresDepthTexture) && m_CreateDepthTexture; return requiresDepthCopyPass; } void CreateCameraDepthCopyTexture(RenderGraph renderGraph, RenderTextureDescriptor descriptor) { CommonResourceData resourceData = frameData.Get(); var depthDescriptor = descriptor; depthDescriptor.msaaSamples = 1;// Depth-Only pass don't use MSAA if (PlatformAutoDetect.hasRenderToR32F) { depthDescriptor.graphicsFormat = GraphicsFormat.R32_SFloat; depthDescriptor.depthStencilFormat = GraphicsFormat.None; } else { depthDescriptor.graphicsFormat = GraphicsFormat.None; depthDescriptor.depthStencilFormat = CoreUtils.GetDefaultDepthOnlyFormat(); } resourceData.cameraDepthTexture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDescriptor, "_CameraDepthTexture", true); } void CreateOffscreenUITexture(RenderGraph renderGraph, in RenderTextureDescriptor descriptor) { UniversalResourceData resourceData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); TextureDesc textureDesc = new TextureDesc(descriptor); DrawScreenSpaceUIPass.ConfigureOffscreenUITextureDesc(ref textureDesc); RenderingUtils.ReAllocateHandleIfNeeded(ref s_OffscreenUIColorHandle, textureDesc, name: "_OverlayUITexture"); // Clear the texture to avoid stale data from previous frames ImportResourceParams importParams = new ImportResourceParams(); importParams.clearOnFirstUse = cameraData.rendersOffscreenUI; importParams.clearColor = Color.clear; importParams.discardOnLastUse = false; resourceData.overlayUITexture = renderGraph.ImportTexture(s_OffscreenUIColorHandle, importParams); } public override void OnBeginRenderGraphFrame() { Universal2DResourceData universal2DResourceData = frameData.Create(); CommonResourceData commonResourceData = frameData.Get(); frameData.Create().renderingData = m_Renderer2DData; universal2DResourceData.InitFrame(); commonResourceData.InitFrame(); } internal void RecordCustomRenderGraphPasses(RenderGraph renderGraph, RenderPassEvent2D eventStart, int batchIndex = -1) { foreach (ScriptableRenderPass pass in activeRenderPassQueue) { var batchCount = frameData.Get().batchCount; var isBatchValid = batchIndex >= 0 && batchIndex < batchCount; pass.GetInjectionPoint2D(out RenderPassEvent2D rpEvent, out int layerID); int range = ScriptableRenderPass2D.GetRenderPassEventRange(eventStart); // Account for render passes in between events. if (rpEvent >= eventStart && rpEvent < eventStart + range) { // Invalid sorting layer specified for render pass if (!SortingLayer.IsValid(layerID) && ScriptableRenderPass2D.IsSortingLayerEvent(rpEvent)) { Debug.Assert(SortingLayer.IsValid(layerID), SortingLayer.IDToName(layerID) + " is not a valid Sorting Layer."); } // BatchIndex is valid else if (isBatchValid) { var layerBatch = frameData.Get().layerBatches[batchIndex]; if (layerBatch.IsValueWithinLayerRange(SortingLayer.GetLayerValueFromID(layerID))) pass.RecordRenderGraph(renderGraph, frameData); } else pass.RecordRenderGraph(renderGraph, frameData); } } } internal override void OnRecordRenderGraph(RenderGraph renderGraph, ScriptableRenderContext context) { CommonResourceData commonResourceData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); #if ENABLE_PROFILER && PROFILER_INSTALLED // canProfilerCapture is initialized here and can only be used after s_CanProfilerCapture = cameraData.isGameCamera; #endif InitializeLayerBatches(); // Before CreateResources: it reads RequiresComposition() to force an intermediate color target. m_DrawOverlayUIPass.Setup(cameraData); CreateResources(renderGraph); DebugHandler?.Setup(renderGraph, cameraData.isPreviewCamera); RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRendering); SetupRenderGraphCameraProperties(renderGraph, commonResourceData.activeColorTexture); #if VISUAL_EFFECT_GRAPH_0_0_1_OR_NEWER ProcessVFXCameraCommand(renderGraph); #endif OnBeforeRendering(renderGraph); BeginRenderGraphXRRendering(renderGraph); OnMainRendering(renderGraph); RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingPostProcessing); OnAfterRendering(renderGraph); EndRenderGraphXRRendering(renderGraph); } public override void OnEndRenderGraphFrame() { Universal2DResourceData universal2DResourceData = frameData.Get(); CommonResourceData commonResourceData = frameData.Get(); universal2DResourceData.EndFrame(); commonResourceData.EndFrame(); } internal override void OnFinishRenderGraphRendering(CommandBuffer cmd) { m_CopyDepthPass?.OnCameraCleanup(cmd); } private void OnBeforeRendering(RenderGraph renderGraph) { UniversalCameraData cameraData = frameData.Get(); var renderingData = frameData.Get().renderingData; m_LightPass.Setup(renderGraph, frameData); // Before rendering the lights cache some values that are expensive to get/calculate var culledLights = renderingData.lightCullResult.visibleLights; for (var i = 0; i < culledLights.Count; i++) { culledLights[i].CacheValues(); } ShadowCasterGroup2DManager.CacheValues(); ShadowRendering.CallOnBeforeRender(cameraData.camera, renderingData.lightCullResult); RendererLighting.lightBatch.Reset(); } private void OnMainRendering(RenderGraph renderGraph) { Universal2DResourceData universal2DResourceData = frameData.Get(); CommonResourceData commonResourceData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); var layerBatches = frameData.Get().layerBatches; var batchCount = frameData.Get().batchCount; // Color Grading LUT bool requiredColorGradingLutPass = cameraData.postProcessEnabled && m_PostProcess != null; if (requiredColorGradingLutPass) { TextureHandle internalColorLut = TextureHandle.nullHandle; m_ColorGradingLutPassRenderGraph.Render(renderGraph, frameData, out internalColorLut); commonResourceData.internalColorLut = internalColorLut; } var cameraSortingLayerBoundsIndex = m_Renderer2DData.GetCameraSortingLayerBoundsIndex(); bool useLights = false; for (int i = 0; i < batchCount; ++i) useLights |= layerBatches[i].lightStats.useLights; // Set Global Properties and Textures GlobalPropertiesPass.Setup(renderGraph, frameData, useLights); // Main render passes // Rendering Layer Mask Prepass m_RenderingLayerMaskPass.Render(renderGraph, frameData); // Normal Pass for (var i = 0; i < batchCount; i++) { RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingNormals, i); m_NormalPass.Render(renderGraph, frameData, i); RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingNormals, i); } // Shadow Pass (TODO: Optimize RT swapping between shadow and light textures) for (var i = 0; i < batchCount; i++) { RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingShadows, i); m_ShadowPass.Render(renderGraph, frameData, i); RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingShadows, i); } // Light Pass for (var i = 0; i < batchCount; i++) { RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingLights, i); m_LightPass.Render(renderGraph, frameData, i); RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingLights, i); } #if ENABLE_PROFILER && PROFILER_INSTALLED if (canProfilerCapture) { ProfilerMarkers.s_ShadowMeshFrameData.Emit(); ProfilerMarkers.s_ShadowRenderFrameData.Emit(); ProfilerMarkers.s_LightMeshFrameData.Emit(); ProfilerMarkers.s_LightRenderFrameData.Emit(); } #endif // Default Render Pass for (var i = 0; i < batchCount; i++) { RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.BeforeRenderingSprites, i); LayerUtility.GetFilterSettings(m_Renderer2DData, layerBatches[i], out var filterSettings); m_RendererPass.Render(renderGraph, frameData, i, ref filterSettings); RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingSprites, i); // Shadow Volumetric Pass m_ShadowPass.Render(renderGraph, frameData, i, true); // Light Volumetric Pass m_LightPass.Render(renderGraph, frameData, i, true); // Camera Sorting Layer Pass if (m_Renderer2DData.useCameraSortingLayerTexture) { ref var layerBatch = ref layerBatches[i]; if (layerBatch.IsValueWithinLayerRange(cameraSortingLayerBoundsIndex)) { m_CopyCameraSortingLayerPass.Render(renderGraph, frameData); } } } if (RequiresDepthCopyPass()) m_CopyDepthPass?.Render(renderGraph, frameData, commonResourceData.cameraDepthTexture, commonResourceData.activeDepthTexture, true); bool shouldRenderUI = cameraData.rendersOverlayUI; bool outputToHDR = cameraData.isHDROutputActive; if (shouldRenderUI && outputToHDR) { if (cameraData.rendersOffscreenUI) { m_DrawOffscreenUIPass.RenderOffscreen(renderGraph, frameData, CoreUtils.GetDefaultDepthStencilFormat(), commonResourceData.overlayUITexture); if (cameraData.blitsOffscreenUICover) m_OffscreenUICoverPrepass.Render(renderGraph, cameraData, commonResourceData, renderGraph.defaultResources.blackTexture, true); } else { // When the first camera renders the shared offscreen UI texture, register it as a global texture so subsequent cameras can use it in their final passes. RenderGraphUtils.SetGlobalTexture(renderGraph, ShaderPropertyId.overlayUITexture, commonResourceData.overlayUITexture); } } } private void OnAfterRendering(RenderGraph renderGraph) { Universal2DResourceData universal2DResourceData = frameData.Get(); CommonResourceData commonResourceData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); UniversalPostProcessingData postProcessingData = frameData.Get(); bool drawGizmos = UniversalRenderPipelineDebugDisplaySettings.Instance.renderingSettings.sceneOverrideMode == DebugSceneOverrideMode.None; if (drawGizmos) DrawRenderGraphGizmos(renderGraph, frameData, commonResourceData.activeColorTexture, commonResourceData.activeDepthTexture, GizmoSubset.PreImageEffects); DebugHandler debugHandler = ScriptableRenderPass.GetActiveDebugHandler(cameraData); bool resolveToDebugScreen = debugHandler != null && debugHandler.WriteToDebugScreenTexture(cameraData.resolveFinalTarget); //When the debughandler displays HDR debug views, it needs to redirect (final) post-process output to an intermediate color target (debugScreenTexture). //Therefore, we swap the backbuffer textures for the debug screen textures such that the next post processing passes don't need to be aware of the debug handler at all. //At the end, when the handler is active, we swap them back. This isolates the debug handler code from the sequence of post process passes and is a common pattern to //use the resourceData. var debugRealBackBufferColor = TextureHandle.nullHandle; var debugRealBackBufferDepth = TextureHandle.nullHandle; // Allocate debug screen texture if the debug mode needs it. if (resolveToDebugScreen) { debugRealBackBufferColor = commonResourceData.backBufferColor; debugRealBackBufferDepth = commonResourceData.backBufferDepth; RenderTextureDescriptor colorDesc = cameraData.cameraTargetDescriptor; DebugHandler.ConfigureColorDescriptorForDebugScreen(ref colorDesc, cameraData.pixelWidth, cameraData.pixelHeight); commonResourceData.backBufferColor = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorDesc, "_DebugScreenColor", false); RenderTextureDescriptor depthDesc = cameraData.cameraTargetDescriptor; DebugHandler.ConfigureDepthDescriptorForDebugScreen(ref depthDesc, CoreUtils.GetDefaultDepthStencilFormat(), cameraData.pixelWidth, cameraData.pixelHeight); commonResourceData.backBufferDepth = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDesc, "_DebugScreenDepth", false); } bool applyPostProcessing = cameraData.postProcessEnabled && m_PostProcess != null; bool anyPostProcessing = postProcessingData.isEnabled && m_PostProcess != null; #if ENABLE_UPSCALER_FRAMEWORK bool fsr1Enabled = cameraData.resolvedUpscalerHash == UniversalRenderPipeline.k_UpscalerHash_FSR1; #else bool fsr1Enabled = cameraData.upscalingFilter == ImageUpscalingFilter.FSR; #endif bool requirePixelPerfectUpscale = IsPixelPerfectCameraEnabled(cameraData, out var ppc) && ppc.requiresUpscalePass; // When using Upscale Render Texture on a Pixel Perfect Camera, we want all post-processing effects done with a low-res RT, // and only upscale the low-res RT to fullscreen when blitting it to camera target. Also, final post processing pass is not run in this case, // so FXAA is not supported (you don't want to apply FXAA when everything is intentionally pixelated). // FSR1 also requires the final pass (unlike upscalers using IUpscaler, it does not self-schedule). bool applyFinalPostProcessing = cameraData.resolveFinalTarget && !ppcUpscaleRT && anyPostProcessing && ((cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing) || (cameraData.imageScalingMode == ImageScalingMode.Upscaling && fsr1Enabled)); bool hasPassesAfterPostProcessing = activeRenderPassQueue.Find(x => x.renderPassEvent == RenderPassEvent.AfterRenderingPostProcessing || (x as ScriptableRenderPass2D)?.renderPassEvent2D == RenderPassEvent2D.AfterRenderingPostProcessing) != null; bool needsColorEncoding = !resolveToDebugScreen; // Don't resolve during post processing if there are passes after or pixel perfect camera is used bool pixelPerfectCameraEnabled = ppc != null && ppc.enabled; bool hasCaptureActions = cameraData.captureActions != null && cameraData.resolveFinalTarget; bool resolvePostProcessingToCameraTarget = cameraData.resolveFinalTarget && !hasCaptureActions && !hasPassesAfterPostProcessing && !applyFinalPostProcessing && !pixelPerfectCameraEnabled && !m_DrawOverlayUIPass.RequiresComposition(); bool doSRGBEncoding = resolvePostProcessingToCameraTarget && needsColorEncoding; if (applyPostProcessing) { bool isTargetBackbuffer = resolvePostProcessingToCameraTarget; if(isTargetBackbuffer) { commonResourceData.SwitchActiveTexturesToBackbuffer(); } else { // if the postprocessing pass is trying to read and write to the same CameraColor target, we need to swap so it writes to a different target, // since reading a pass attachment is not possible. Normally this would be possible using temporary RenderGraph managed textures. // The reason why in this case we need to use "external" RTHandles is to preserve the results for camera stacking. // TODO RENDERGRAPH: Once all cameras will run in a single RenderGraph we can just use temporary RenderGraph textures as intermediate buffer. ImportResourceParams importColorParams = new ImportResourceParams(); importColorParams.clearOnFirstUse = true; importColorParams.clearColor = Color.black; importColorParams.discardOnLastUse = cameraData.resolveFinalTarget; // check if last camera in the stack commonResourceData.destinationCameraColor = renderGraph.ImportTexture(nextRenderGraphCameraColorHandle, importColorParams); } m_PostProcess.RenderPostProcessing( renderGraph, frameData, applyFinalPostProcessing, doSRGBEncoding); } RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRenderingPostProcessing); // Do PixelPerfect upscaling when using the Stretch Fill option if (requirePixelPerfectUpscale) { m_UpscalePass.Render(renderGraph, cameraData.camera, commonResourceData.cameraColor, universal2DResourceData.upscaleTexture); commonResourceData.cameraColor = universal2DResourceData.upscaleTexture; } // Capture pass for Unity Recorder if (hasCaptureActions) { m_CapturePass.RecordRenderGraph(renderGraph, frameData); } // Composite needs cameraColor, so blit it into the overlay buffer before final post / the final blit // swap it to the backbuffer. Skipped once the active target is already the backbuffer. bool renderOverlayComposite = m_DrawOverlayUIPass.RequiresComposition() && !commonResourceData.isActiveTargetBackBuffer; if (renderOverlayComposite) m_DrawOverlayUIPass.BlitCameraColorToOverlayCompositeBuffer(renderGraph, commonResourceData, cameraData.pixelRect, CoreUtils.GetDefaultDepthStencilFormat()); if (applyFinalPostProcessing) { //Will swap the active camera targets to backbuffer (resourceData.SwitchActiveTexturesToBackbuffer) m_PostProcess.RenderFinalPostProcessing(renderGraph, frameData, needsColorEncoding); } if (!commonResourceData.isActiveTargetBackBuffer && cameraData.resolveFinalTarget) { //Will swap the active camera targets to backbuffer (resourceData.SwitchActiveTexturesToBackbuffer) m_FinalBlitPass.RecordRenderGraph(renderGraph, frameData); } RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent2D.AfterRendering); // We can explicitly render the overlay UI from URP when HDR output is not enabled. // SupportedRenderingFeatures.active.rendersUIOverlay should also be set to true. bool shouldRenderUI = cameraData.rendersOverlayUI && cameraData.isLastBaseCamera; bool outputToHDR = cameraData.isHDROutputActive; if (shouldRenderUI && !outputToHDR) { var color = commonResourceData.backBufferColor; var depth = commonResourceData.backBufferDepth; if (renderOverlayComposite) m_DrawOverlayUIPass.RenderOverlayUIToolkitAndUGUIComposite(renderGraph, frameData, in color); else m_DrawOverlayUIPass.RenderOverlayUIToolkitAndUGUI(renderGraph, frameData, in color, in depth); m_DrawOverlayUIPass.RenderOverlayIMGUI(renderGraph, frameData, in color, in depth); } // If HDR debug views are enabled, debugHandler will perform the blit from debugScreenColor (== finalColorHandle) to backBufferColor. if (resolveToDebugScreen) { debugHandler.Render(renderGraph, cameraData, commonResourceData.backBufferColor, commonResourceData.overlayUITexture, debugRealBackBufferColor); //Swapping the backbuffer textures back commonResourceData.backBufferColor = debugRealBackBufferColor; commonResourceData.backBufferDepth = debugRealBackBufferDepth; } if (cameraData.resolveFinalTarget) { if (cameraData.isSceneViewCamera) DrawRenderGraphWireOverlay(renderGraph, frameData, commonResourceData.activeColorTexture); if (drawGizmos) DrawRenderGraphGizmos(renderGraph, frameData, commonResourceData.activeColorTexture, commonResourceData.activeDepthTexture, GizmoSubset.PostImageEffects); } } public Renderer2DData GetRenderer2DData() { return m_Renderer2DData; } protected override void Dispose(bool disposing) { CleanupRenderGraphResources(); base.Dispose(disposing); } private void CleanupRenderGraphResources() { m_Renderer2DData.Dispose(); m_CopyDepthPass?.Dispose(); m_FinalBlitPass?.Dispose(); m_OffscreenUICoverPrepass?.Dispose(); m_DrawOffscreenUIPass?.Dispose(); m_DrawOverlayUIPass?.Dispose(); m_PostProcess?.Dispose(); m_RenderingLayerMaskPass.Dispose(); m_ColorGradingLutPassRenderGraph?.Cleanup(); s_RenderGraphCameraColorHandles[0]?.Release(); s_RenderGraphCameraColorHandles[1]?.Release(); s_RenderGraphCameraDepthHandle?.Release(); m_RenderGraphBackbufferColorHandle?.Release(); m_RenderGraphBackbufferDepthHandle?.Release(); m_CameraSortingLayerHandle?.Release(); s_OffscreenUIColorHandle?.Release(); Light2DManager.Dispose(); Light2DLookupTexture.Release(); LensFlareCommonSRP.Dispose(); CoreUtils.Destroy(m_BlitMaterial); CoreUtils.Destroy(m_BlitHDRMaterial); CoreUtils.Destroy(m_BlitOffscreenUICoverMaterial); CoreUtils.Destroy(m_SamplingMaterial); CoreUtils.Destroy(m_BackdropFilterCompositeMaterial); #if ENABLE_VR && ENABLE_XR_MODULE XRSystem.Dispose(); #endif } internal static bool IsGLESDevice() { return SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3; } internal static bool supportsMRT { get => !IsGLESDevice(); } internal static bool IsSceneViewOrPreviewLightingActive(UniversalCameraData cameraData) { DebugHandler debugHandler = ScriptableRenderPass.GetActiveDebugHandler(cameraData); var isLightingActive = debugHandler?.IsLightingActive ?? true; #if UNITY_EDITOR if (cameraData.isSceneViewCamera && UnityEditor.SceneView.currentDrawingSceneView != null) isLightingActive &= UnityEditor.SceneView.currentDrawingSceneView.sceneLighting; #endif return isLightingActive; } } }