using System; using System.Collections.Generic; using UnityEngine; using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip; namespace UnityEngine.Rendering.Universal { /// /// Debug wireframe modes. /// public enum DebugWireframeMode { /// No wireframe. None, /// Unfilled wireframe. Wireframe, /// Solid, filled wireframe. SolidWireframe, /// Solid, shaded wireframe. ShadedWireframe, } /// /// Rendering-related Rendering Debugger settings. /// public class DebugDisplaySettingsRendering : IDebugDisplaySettingsData { // Under the hood, the implementation uses a single enum (DebugSceneOverrideMode). For UI & public API, // we have split this enum into WireframeMode and a separate Overdraw boolean. DebugWireframeMode m_WireframeMode = DebugWireframeMode.None; /// /// Current debug wireframe mode. /// public DebugWireframeMode wireframeMode { get => m_WireframeMode; set { m_WireframeMode = value; UpdateDebugSceneOverrideMode(); } } bool m_Overdraw = false; /// /// Whether debug overdraw mode is active. /// [Obsolete("overdraw has been deprecated. Use overdrawMode instead.", false)] public bool overdraw { get => m_Overdraw; set { m_Overdraw = value; UpdateDebugSceneOverrideMode(); } } DebugOverdrawMode m_OverdrawMode = DebugOverdrawMode.None; /// /// Which overdraw debug mode is active. /// public DebugOverdrawMode overdrawMode { get => m_OverdrawMode; set { m_OverdrawMode = value; UpdateDebugSceneOverrideMode(); } } /// /// Maximum overdraw count for a single pixel. /// /// This is used to setup the feedback range in when is active. /// public int maxOverdrawCount { get; set; } = 10; void UpdateDebugSceneOverrideMode() { switch (wireframeMode) { case DebugWireframeMode.Wireframe: sceneOverrideMode = DebugSceneOverrideMode.Wireframe; break; case DebugWireframeMode.SolidWireframe: sceneOverrideMode = DebugSceneOverrideMode.SolidWireframe; break; case DebugWireframeMode.ShadedWireframe: sceneOverrideMode = DebugSceneOverrideMode.ShadedWireframe; break; default: sceneOverrideMode = overdrawMode != DebugOverdrawMode.None ? DebugSceneOverrideMode.Overdraw : DebugSceneOverrideMode.None; break; } } /// /// Current debug fullscreen overlay mode. /// public DebugFullScreenMode fullScreenDebugMode { get; set; } = DebugFullScreenMode.None; /// /// Size of the debug fullscreen overlay, as percentage of the screen size. /// public int fullScreenDebugModeOutputSizeScreenPercent { get; set; } = 50; internal DebugSceneOverrideMode sceneOverrideMode { get; set; } = DebugSceneOverrideMode.None; internal DebugMipInfoMode mipInfoMode { get; set; } = DebugMipInfoMode.None; /// /// Current debug post processing mode. /// public DebugPostProcessingMode postProcessingDebugMode { get; set; } = DebugPostProcessingMode.Auto; /// /// Whether MSAA is enabled. /// public bool enableMsaa { get; set; } = true; /// /// Whether HDR is enabled. /// public bool enableHDR { get; set; } = true; /// /// Current Temporal Anti-aliasing debug mode. /// public enum TaaDebugMode { /// The default non-debug TAA rendering. None = 0, /// Output the jittered raw frame render. TAA current frame influence 100%. ShowRawFrame, /// Output the raw frame render, but with jitter disabled. TAA current frame influence 100%. ShowRawFrameNoJitter, /// Output the clamped (rectified), reprojected TAA history. Current frame influence 0%. ShowClampedHistory, } /// /// Current TAA debug mode. /// public TaaDebugMode taaDebugMode { get; set; } = TaaDebugMode.None; #region Pixel validation /// /// Current debug pixel validation mode. /// public DebugValidationMode validationMode { get; set; } /// /// Current validation channels for DebugValidationMode.HighlightOutsideOfRange. /// public PixelValidationChannels validationChannels { get; set; } = PixelValidationChannels.RGB; /// /// Current minimum threshold value for pixel validation. /// Any values below this value will be considered invalid and will appear red on screen. /// public float validationRangeMin { get; set; } = 0.0f; /// /// Current maximum threshold value for pixel validation. /// Any values above this value will be considered invalid and will appear blue on screen. /// public float validationRangeMax { get; set; } = 1.0f; static class Strings { public const string RangeValidationSettingsContainerName = "Pixel Range Settings"; public static readonly NameAndTooltip MapOverlays = new() { name = "Map Overlays", tooltip = "Overlays render pipeline textures to validate the scene." }; public static readonly NameAndTooltip MapSize = new() { name = "Map Size", tooltip = "Set the size of the render pipeline texture in the scene." }; public static readonly NameAndTooltip AdditionalWireframeModes = new() { name = "Additional Wireframe Modes", tooltip = "Debug the scene with additional wireframe shader views that are different from those in the scene view." }; public static readonly NameAndTooltip WireframeNotSupportedWarning = new() { name = "Warning: This platform might not support wireframe rendering.", tooltip = "Some platforms, for example, mobile platforms using OpenGL ES and Vulkan, might not support wireframe rendering." }; public static readonly NameAndTooltip OverdrawMode = new() { name = "Overdraw Mode", tooltip = "Debug anywhere materials that overdrawn pixels top of each other." }; public static readonly NameAndTooltip MaxOverdrawCount = new() { name = "Max Overdraw Count", tooltip = "Maximum overdraw count allowed for a single pixel." }; public static readonly NameAndTooltip PostProcessing = new() { name = "Post-processing", tooltip = "Override the controls for Post Processing in the scene." }; public static readonly NameAndTooltip MSAA = new() { name = "MSAA", tooltip = "Use the checkbox to disable MSAA in the scene." }; public static readonly NameAndTooltip HDR = new() { name = "HDR", tooltip = "Use the checkbox to disable High Dynamic Range in the scene." }; public static readonly NameAndTooltip TaaDebugMode = new() { name = "TAA Debug Mode", tooltip = "Choose whether to force TAA to output the raw jittered frame or clamped reprojected history." }; public static readonly NameAndTooltip PixelValidationMode = new() { name = "Pixel Validation Mode", tooltip = "Choose between modes that validate pixel on screen." }; public static readonly NameAndTooltip Channels = new() { name = "Channels", tooltip = "Choose the texture channel used to validate the scene." }; public static readonly NameAndTooltip ValueRangeMin = new() { name = "Value Range Min", tooltip = "Any values set below this field will be considered invalid and will appear red on screen." }; public static readonly NameAndTooltip ValueRangeMax = new() { name = "Value Range Max", tooltip = "Any values set above this field will be considered invalid and will appear blue on screen." }; } #endregion internal static class WidgetFactory { internal static DebugUI.Widget CreateMapOverlays(SettingsPanel panel) => new DebugUI.EnumField { nameAndTooltip = Strings.MapOverlays, autoEnum = typeof(DebugFullScreenMode), getter = () => (int)panel.data.fullScreenDebugMode, setter = (value) => panel.data.fullScreenDebugMode = (DebugFullScreenMode)value, getIndex = () => (int)panel.data.fullScreenDebugMode, setIndex = (value) => panel.data.fullScreenDebugMode = (DebugFullScreenMode)value }; internal static DebugUI.Widget CreateMapOverlaySize(SettingsPanel panel) => new DebugUI.Container() { children = { new DebugUI.IntField { nameAndTooltip = Strings.MapSize, getter = () => panel.data.fullScreenDebugModeOutputSizeScreenPercent, setter = value => panel.data.fullScreenDebugModeOutputSizeScreenPercent = value, incStep = 10, min = () => 0, max = () => 100 } } }; internal static DebugUI.Widget CreateAdditionalWireframeShaderViews(SettingsPanel panel) => new DebugUI.EnumField { nameAndTooltip = Strings.AdditionalWireframeModes, autoEnum = typeof(DebugWireframeMode), getter = () => (int)panel.data.wireframeMode, setter = (value) => panel.data.wireframeMode = (DebugWireframeMode)value, getIndex = () => (int)panel.data.wireframeMode, setIndex = (value) => panel.data.wireframeMode = (DebugWireframeMode)value, onValueChanged = (_, _) => DebugManager.instance.ReDrawOnScreenDebug() }; internal static DebugUI.Widget CreateWireframeNotSupportedWarning(SettingsPanel panel) => new DebugUI.MessageBox { nameAndTooltip = Strings.WireframeNotSupportedWarning, style = DebugUI.MessageBox.Style.Warning, isHiddenCallback = () => { #if UNITY_EDITOR return true; #else switch (SystemInfo.graphicsDeviceType) { case GraphicsDeviceType.OpenGLES2: case GraphicsDeviceType.OpenGLES3: case GraphicsDeviceType.Vulkan: return panel.data.wireframeMode == DebugWireframeMode.None; default: return true; } #endif } }; internal static DebugUI.Widget CreateOverdrawMode(SettingsPanel panel) => new DebugUI.EnumField() { nameAndTooltip = Strings.OverdrawMode, autoEnum = typeof(DebugOverdrawMode), getter = () => (int)panel.data.overdrawMode, setter = (value) => panel.data.overdrawMode = (DebugOverdrawMode)value, getIndex = () => (int)panel.data.overdrawMode, setIndex = (value) => panel.data.overdrawMode = (DebugOverdrawMode)value }; internal static DebugUI.Widget CreateMaxOverdrawCount(SettingsPanel panel) => new DebugUI.Container() { isHiddenCallback = () => panel.data.overdrawMode == DebugOverdrawMode.None, children = { new DebugUI.IntField { nameAndTooltip = Strings.MaxOverdrawCount, getter = () => panel.data.maxOverdrawCount, setter = value => panel.data.maxOverdrawCount = value, incStep = 10, min = () => 1, max = () => 500 } } }; internal static DebugUI.Widget CreatePostProcessing(SettingsPanel panel) => new DebugUI.EnumField { nameAndTooltip = Strings.PostProcessing, autoEnum = typeof(DebugPostProcessingMode), getter = () => (int)panel.data.postProcessingDebugMode, setter = (value) => panel.data.postProcessingDebugMode = (DebugPostProcessingMode)value, getIndex = () => (int)panel.data.postProcessingDebugMode, setIndex = (value) => panel.data.postProcessingDebugMode = (DebugPostProcessingMode)value }; internal static DebugUI.Widget CreateMSAA(SettingsPanel panel) => new DebugUI.BoolField { nameAndTooltip = Strings.MSAA, getter = () => panel.data.enableMsaa, setter = (value) => panel.data.enableMsaa = value }; internal static DebugUI.Widget CreateHDR(SettingsPanel panel) => new DebugUI.BoolField { nameAndTooltip = Strings.HDR, getter = () => panel.data.enableHDR, setter = (value) => panel.data.enableHDR = value }; internal static DebugUI.Widget CreateTaaDebugMode(SettingsPanel panel) => new DebugUI.EnumField { nameAndTooltip = Strings.TaaDebugMode, autoEnum = typeof(TaaDebugMode), getter = () => (int)panel.data.taaDebugMode, setter = (value) => panel.data.taaDebugMode = (TaaDebugMode)value, getIndex = () => (int)panel.data.taaDebugMode, setIndex = (value) => panel.data.taaDebugMode = (TaaDebugMode)value, onValueChanged = (_, _) => DebugManager.instance.ReDrawOnScreenDebug() }; internal static DebugUI.Widget CreatePixelValidationMode(SettingsPanel panel) => new DebugUI.EnumField { nameAndTooltip = Strings.PixelValidationMode, autoEnum = typeof(DebugValidationMode), getter = () => (int)panel.data.validationMode, setter = (value) => panel.data.validationMode = (DebugValidationMode)value, getIndex = () => (int)panel.data.validationMode, setIndex = (value) => panel.data.validationMode = (DebugValidationMode)value, onValueChanged = (_, _) => DebugManager.instance.ReDrawOnScreenDebug() }; internal static DebugUI.Widget CreatePixelValidationChannels(SettingsPanel panel) => new DebugUI.EnumField { nameAndTooltip = Strings.Channels, autoEnum = typeof(PixelValidationChannels), getter = () => (int)panel.data.validationChannels, setter = (value) => panel.data.validationChannels = (PixelValidationChannels)value, getIndex = () => (int)panel.data.validationChannels, setIndex = (value) => panel.data.validationChannels = (PixelValidationChannels)value }; internal static DebugUI.Widget CreatePixelValueRangeMin(SettingsPanel panel) => new DebugUI.FloatField { nameAndTooltip = Strings.ValueRangeMin, getter = () => panel.data.validationRangeMin, setter = (value) => panel.data.validationRangeMin = value, incStep = 0.01f }; internal static DebugUI.Widget CreatePixelValueRangeMax(SettingsPanel panel) => new DebugUI.FloatField { nameAndTooltip = Strings.ValueRangeMax, getter = () => panel.data.validationRangeMax, setter = (value) => panel.data.validationRangeMax = value, incStep = 0.01f }; } [DisplayInfo(name = "Rendering", order = 1)] internal class SettingsPanel : DebugDisplaySettingsPanel { public SettingsPanel(DebugDisplaySettingsRendering data) : base(data) { AddWidget(DebugDisplaySettingsCommon.WidgetFactory.CreateMissingDebugShadersWarning()); AddWidget(new DebugUI.Foldout { displayName = "Rendering Debug", flags = DebugUI.Flags.FrequentlyUsed, isHeader = true, opened = true, children = { WidgetFactory.CreateMapOverlays(this), WidgetFactory.CreateMapOverlaySize(this), WidgetFactory.CreateHDR(this), WidgetFactory.CreateMSAA(this), WidgetFactory.CreateTaaDebugMode(this), WidgetFactory.CreatePostProcessing(this), WidgetFactory.CreateAdditionalWireframeShaderViews(this), WidgetFactory.CreateWireframeNotSupportedWarning(this), WidgetFactory.CreateOverdrawMode(this), WidgetFactory.CreateMaxOverdrawCount(this), } }); AddWidget(new DebugUI.Foldout { displayName = "Pixel Validation", isHeader = true, opened = true, children = { WidgetFactory.CreatePixelValidationMode(this), new DebugUI.Container() { displayName = Strings.RangeValidationSettingsContainerName, isHiddenCallback = () => data.validationMode != DebugValidationMode.HighlightOutsideOfRange, children = { WidgetFactory.CreatePixelValidationChannels(this), WidgetFactory.CreatePixelValueRangeMin(this), WidgetFactory.CreatePixelValueRangeMax(this) } } } }); } } #region IDebugDisplaySettingsData /// public bool AreAnySettingsActive => (postProcessingDebugMode != DebugPostProcessingMode.Auto) || (fullScreenDebugMode != DebugFullScreenMode.None) || (sceneOverrideMode != DebugSceneOverrideMode.None) || (mipInfoMode != DebugMipInfoMode.None) || (validationMode != DebugValidationMode.None) || !enableMsaa || !enableHDR || (taaDebugMode != TaaDebugMode.None); /// public bool IsPostProcessingAllowed => (postProcessingDebugMode != DebugPostProcessingMode.Disabled) && (sceneOverrideMode == DebugSceneOverrideMode.None) && (mipInfoMode == DebugMipInfoMode.None); /// public bool IsLightingActive => (sceneOverrideMode == DebugSceneOverrideMode.None) && (mipInfoMode == DebugMipInfoMode.None); /// public bool TryGetScreenClearColor(ref Color color) { switch (sceneOverrideMode) { case DebugSceneOverrideMode.None: case DebugSceneOverrideMode.ShadedWireframe: return false; case DebugSceneOverrideMode.Overdraw: color = Color.black; return true; case DebugSceneOverrideMode.Wireframe: case DebugSceneOverrideMode.SolidWireframe: color = new Color(0.1f, 0.1f, 0.1f, 1.0f); return true; default: throw new ArgumentOutOfRangeException(nameof(color)); } } /// IDebugDisplaySettingsPanelDisposable IDebugDisplaySettingsData.CreatePanel() { return new SettingsPanel(this); } #endregion } }