using System; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.Universal { /// /// Generate HDR debug data into the given color target /// internal class HDRDebugViewPass : ScriptableRenderPass { private enum HDRDebugPassId { CIExyPrepass = 0, DebugViewPass = 1 } PassDataCIExy m_PassDataCIExy; PassDataDebugView m_PassDataDebugView; RTHandle m_CIExyTarget; // xyBuffer; RTHandle m_PassthroughRT; Material m_material; /// /// Creates a new HDRDebugViewPass instance. /// /// The Material to use. /// public HDRDebugViewPass(Material mat) { profilingSampler = new ProfilingSampler("Blit HDR Debug Data"); renderPassEvent = RenderPassEvent.AfterRendering + 3; m_PassDataCIExy = new PassDataCIExy() { material = mat }; m_PassDataDebugView = new PassDataDebugView() { material = mat }; m_material = mat; // Disabling native render passes (for non-RG) because it renders to 2 different render targets useNativeRenderPass = false; } // Common to RenderGraph and non-RenderGraph paths private class PassDataCIExy { internal Material material; internal Vector4 luminanceParameters; internal TextureHandle srcColor; internal TextureHandle xyBuffer; internal TextureHandle passThrough; } private class PassDataDebugView { internal Material material; internal HDRDebugMode hdrDebugMode; internal UniversalCameraData cameraData; internal Vector4 luminanceParameters; internal TextureHandle overlayUITexture; internal TextureHandle xyBuffer; internal TextureHandle srcColor; internal TextureHandle dstColor; } public static void ConfigureDescriptorForCIEPrepass(ref RenderTextureDescriptor descriptor) { descriptor.graphicsFormat = GraphicsFormat.R32_SFloat; descriptor.width = descriptor.height = ShaderConstants._SizeOfHDRXYMapping; descriptor.useMipMap = false; descriptor.autoGenerateMips = false; descriptor.useDynamicScale = true; descriptor.depthStencilFormat = GraphicsFormat.None; descriptor.enableRandomWrite = true; descriptor.msaaSamples = 1; descriptor.dimension = TextureDimension.Tex2D; descriptor.vrUsage = VRTextureUsage.None; // We only need one for both eyes in VR } internal static Vector4 GetLuminanceParameters(UniversalCameraData cameraData) { var luminanceParams = Vector4.zero; if (cameraData.isHDROutputActive) { Tonemapping tonemapping = VolumeManager.instance.stack.GetComponent(); UniversalRenderPipeline.GetHDROutputLuminanceParameters(cameraData.hdrDisplayInformation, cameraData.hdrDisplayColorGamut, tonemapping, out luminanceParams); } else { luminanceParams.z = 1.0f; } return luminanceParams; } private static void ExecuteCIExyPrepass(CommandBuffer cmd, PassDataCIExy data, RTHandle sourceTexture, RTHandle xyTarget, RTHandle destTexture) { CoreUtils.SetRenderTarget(cmd, destTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare, ClearFlag.None, Color.clear); Vector4 debugParameters = new Vector4(ShaderConstants._SizeOfHDRXYMapping, ShaderConstants._SizeOfHDRXYMapping, 0, 0); cmd.SetRandomWriteTarget(ShaderConstants._CIExyUAVIndex, xyTarget); data.material.SetVector(ShaderConstants._HDRDebugParamsId, debugParameters); data.material.SetVector(ShaderPropertyId.hdrOutputLuminanceParams, data.luminanceParameters); Vector2 viewportScale = sourceTexture.useScaling ? new Vector2(sourceTexture.rtHandleProperties.rtHandleScale.x, sourceTexture.rtHandleProperties.rtHandleScale.y) : Vector2.one; Blitter.BlitTexture(cmd, sourceTexture, viewportScale, data.material, 0); cmd.ClearRandomWriteTargets(); } private static void ExecuteHDRDebugViewFinalPass(RasterCommandBuffer cmd, PassDataDebugView data, RTHandle sourceTexture, RTHandle destination, RTHandle xyTarget) { if (data.cameraData.isHDROutputActive) { HDROutputUtils.ConfigureHDROutput(data.material, data.cameraData.hdrDisplayColorGamut, HDROutputUtils.Operation.ColorEncoding); CoreUtils.SetKeyword(data.material, ShaderKeywordStrings.HDROverlay, data.cameraData.rendersOverlayUI); } data.material.SetTexture(ShaderConstants._xyTextureId, xyTarget); Vector4 debugParameters = new Vector4(ShaderConstants._SizeOfHDRXYMapping, ShaderConstants._SizeOfHDRXYMapping, 0, 0); data.material.SetVector(ShaderConstants._HDRDebugParamsId, debugParameters); data.material.SetVector(ShaderPropertyId.hdrOutputLuminanceParams, data.luminanceParameters); data.material.SetInteger(ShaderConstants._DebugHDRModeId, (int)data.hdrDebugMode); Vector4 scaleBias = RenderingUtils.GetFinalBlitScaleBias(sourceTexture, destination, data.cameraData); RenderTargetIdentifier cameraTarget = BuiltinRenderTextureType.CameraTarget; #if ENABLE_VR && ENABLE_XR_MODULE if (data.cameraData.xr.enabled) cameraTarget = data.cameraData.xr.renderTarget; #endif if (destination.nameID == cameraTarget || data.cameraData.targetTexture != null) cmd.SetViewport(data.cameraData.pixelRect); Blitter.BlitTexture(cmd, sourceTexture, scaleBias, data.material, 1); } // Non-RenderGraph path public void Dispose() { m_CIExyTarget?.Release(); m_PassthroughRT?.Release(); } /// /// Configure the pass /// /// Descriptor for the color buffer. /// Active DebugMode for HDR. public void Setup(UniversalCameraData cameraData, HDRDebugMode hdrdebugMode) { m_PassDataDebugView.hdrDebugMode = hdrdebugMode; RenderTextureDescriptor descriptor = cameraData.cameraTargetDescriptor; DebugHandler.ConfigureColorDescriptorForDebugScreen(ref descriptor, cameraData.pixelWidth, cameraData.pixelHeight); RenderingUtils.ReAllocateHandleIfNeeded(ref m_PassthroughRT, descriptor, name: "_HDRDebugDummyRT"); RenderTextureDescriptor descriptorCIE = cameraData.cameraTargetDescriptor; HDRDebugViewPass.ConfigureDescriptorForCIEPrepass(ref descriptorCIE); RenderingUtils.ReAllocateHandleIfNeeded(ref m_CIExyTarget, descriptorCIE, name: "_xyBuffer"); } /// [Obsolete(DeprecationMessage.CompatibilityScriptingAPIObsolete, false)] public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { UniversalCameraData cameraData = renderingData.frameData.Get(); var cmd = renderingData.commandBuffer; m_PassDataCIExy.luminanceParameters = m_PassDataDebugView.luminanceParameters = GetLuminanceParameters(cameraData); m_PassDataDebugView.cameraData = cameraData; var sourceTexture = renderingData.cameraData.renderer.cameraColorTargetHandle; var cameraTarget = RenderingUtils.GetCameraTargetIdentifier(ref renderingData); // Get RTHandle alias to use RTHandle apis RTHandleStaticHelpers.SetRTHandleStaticWrapper(cameraTarget); var cameraTargetHandle = RTHandleStaticHelpers.s_RTHandleWrapper; m_material.enabledKeywords = null; GetActiveDebugHandler(cameraData)?.UpdateShaderGlobalPropertiesForFinalValidationPass(cmd, cameraData, true); CoreUtils.SetRenderTarget(cmd, m_CIExyTarget, ClearFlag.Color, Color.clear); ExecutePass(cmd, m_PassDataCIExy, m_PassDataDebugView, sourceTexture, m_CIExyTarget, cameraTargetHandle); } private void ExecutePass(CommandBuffer cmd, PassDataCIExy dataCIExy, PassDataDebugView dataDebugView, RTHandle sourceTexture, RTHandle xyTarget, RTHandle destTexture) { RasterCommandBuffer rasterCmd = CommandBufferHelpers.GetRasterCommandBuffer(cmd); //CIExyPrepass bool requiresCIExyData = dataDebugView.hdrDebugMode != HDRDebugMode.ValuesAbovePaperWhite; if (requiresCIExyData) { using (new ProfilingScope(cmd, profilingSampler)) { ExecuteCIExyPrepass(cmd, dataCIExy, sourceTexture, xyTarget, m_PassthroughRT); } } //HDR DebugView - should always be the last stack of the camera CoreUtils.SetRenderTarget(cmd, destTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, ClearFlag.None, Color.clear); using (new ProfilingScope(cmd, profilingSampler)) { ExecuteHDRDebugViewFinalPass(rasterCmd, dataDebugView, sourceTexture, destTexture, xyTarget); } // Disable obsolete warning for internal usage #pragma warning disable CS0618 dataDebugView.cameraData.renderer.ConfigureCameraTarget(destTexture, destTexture); #pragma warning restore CS0618 } //RenderGraph path internal void RenderHDRDebug(RenderGraph renderGraph, UniversalCameraData cameraData, TextureHandle srcColor, TextureHandle overlayUITexture, TextureHandle dstColor, HDRDebugMode hdrDebugMode) { bool requiresCIExyData = hdrDebugMode != HDRDebugMode.ValuesAbovePaperWhite; Vector4 luminanceParameters = GetLuminanceParameters(cameraData); TextureHandle intermediateRT = srcColor; TextureHandle xyBuffer = TextureHandle.nullHandle; if (requiresCIExyData) { RenderTextureDescriptor descriptor = cameraData.cameraTargetDescriptor; DebugHandler.ConfigureColorDescriptorForDebugScreen(ref descriptor, cameraData.pixelWidth, cameraData.pixelHeight); intermediateRT = UniversalRenderer.CreateRenderGraphTexture(renderGraph, descriptor, "_HDRDebugDummyRT", false); ConfigureDescriptorForCIEPrepass(ref descriptor); xyBuffer = UniversalRenderer.CreateRenderGraphTexture(renderGraph, descriptor, "_xyBuffer", true); // Using low level pass because of random UAV support, and since this is a debug view, we don't care much about merging passes or optimizing for TBDR. // This could be a compute pass (like in HDRP) but doing it in pixel is compatible with devices that might support HDR output but not compute shaders. using (var builder = renderGraph.AddUnsafePass("Blit HDR DebugView CIExy", out var passData, profilingSampler)) { passData.material = m_material; passData.luminanceParameters = luminanceParameters; passData.srcColor = srcColor; builder.UseTexture(srcColor); passData.xyBuffer = xyBuffer; builder.UseTexture(xyBuffer, AccessFlags.Write); passData.passThrough = intermediateRT; builder.UseTexture(intermediateRT, AccessFlags.Write); builder.SetRenderFunc((PassDataCIExy data, UnsafeGraphContext context) => { ExecuteCIExyPrepass(CommandBufferHelpers.GetNativeCommandBuffer(context.cmd), data, data.srcColor, data.xyBuffer, data.passThrough); }); } } using (var builder = renderGraph.AddRasterRenderPass("Blit HDR DebugView", out var passData, profilingSampler)) { passData.material = m_material; passData.hdrDebugMode = hdrDebugMode; passData.luminanceParameters = luminanceParameters; passData.cameraData = cameraData; if (requiresCIExyData) { passData.xyBuffer = xyBuffer; builder.UseTexture(xyBuffer); } passData.srcColor = srcColor; builder.UseTexture(srcColor); passData.dstColor = dstColor; builder.SetRenderAttachment(dstColor, 0, AccessFlags.WriteAll); if (overlayUITexture.IsValid()) { passData.overlayUITexture = overlayUITexture; builder.UseTexture(overlayUITexture); } builder.SetRenderFunc((PassDataDebugView data, RasterGraphContext context) => { data.material.enabledKeywords = null; ExecuteHDRDebugViewFinalPass(context.cmd, data, data.srcColor, data.dstColor, data.xyBuffer); }); } } internal class ShaderConstants { public static readonly int _DebugHDRModeId = Shader.PropertyToID("_DebugHDRMode"); public static readonly int _HDRDebugParamsId = Shader.PropertyToID("_HDRDebugParams"); public static readonly int _xyTextureId = Shader.PropertyToID("_xyBuffer"); public static readonly int _SizeOfHDRXYMapping = 512; public static readonly int _CIExyUAVIndex = 1; } } }