diff --git a/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs b/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs index 13dad62ce0..ae3fa4937f 100644 --- a/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs +++ b/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; @@ -13,7 +14,7 @@ namespace Ryujinx.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 11; + public const int CurrentVersion = 12; public int Version { get; set; } @@ -77,6 +78,11 @@ namespace Ryujinx.Configuration /// public LogClass[] LoggingFilteredClasses { get; set; } + /// + /// Change Graphics API debug log level + /// + public GraphicsDebugLevel LoggingGraphicsDebugLevel { get; set; } + /// /// Enables or disables logging to a file on disk /// diff --git a/Ryujinx.Common/Configuration/ConfigurationState.cs b/Ryujinx.Common/Configuration/ConfigurationState.cs index 3149f250f1..dc9dd65991 100644 --- a/Ryujinx.Common/Configuration/ConfigurationState.cs +++ b/Ryujinx.Common/Configuration/ConfigurationState.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Logging; using Ryujinx.Configuration.Hid; @@ -141,17 +142,23 @@ namespace Ryujinx.Configuration /// public ReactiveObject EnableFileLog { get; private set; } + /// + /// Controls which OpenGL log messages are recorded in the log + /// + public ReactiveObject GraphicsDebugLevel { get; private set; } + public LoggerSection() { - EnableDebug = new ReactiveObject(); - EnableStub = new ReactiveObject(); - EnableInfo = new ReactiveObject(); - EnableWarn = new ReactiveObject(); - EnableError = new ReactiveObject(); - EnableGuest = new ReactiveObject(); - EnableFsAccessLog = new ReactiveObject(); - FilteredClasses = new ReactiveObject(); - EnableFileLog = new ReactiveObject(); + EnableDebug = new ReactiveObject(); + EnableStub = new ReactiveObject(); + EnableInfo = new ReactiveObject(); + EnableWarn = new ReactiveObject(); + EnableError = new ReactiveObject(); + EnableGuest = new ReactiveObject(); + EnableFsAccessLog = new ReactiveObject(); + FilteredClasses = new ReactiveObject(); + EnableFileLog = new ReactiveObject(); + GraphicsDebugLevel = new ReactiveObject(); } } @@ -378,6 +385,7 @@ namespace Ryujinx.Configuration LoggingEnableGuest = Logger.EnableGuest, LoggingEnableFsAccessLog = Logger.EnableFsAccessLog, LoggingFilteredClasses = Logger.FilteredClasses, + LoggingGraphicsDebugLevel = Logger.GraphicsDebugLevel, EnableFileLog = Logger.EnableFileLog, SystemLanguage = System.Language, SystemRegion = System.Region, @@ -436,6 +444,7 @@ namespace Ryujinx.Configuration Logger.EnableGuest.Value = true; Logger.EnableFsAccessLog.Value = false; Logger.FilteredClasses.Value = new LogClass[] { }; + Logger.GraphicsDebugLevel.Value = GraphicsDebugLevel.None; Logger.EnableFileLog.Value = true; System.Language.Value = Language.AmericanEnglish; System.Region.Value = Region.USA; @@ -678,6 +687,15 @@ namespace Ryujinx.Configuration configurationFileUpdated = true; } + if (configurationFileFormat.Version < 12) + { + Common.Logging.Logger.PrintWarning(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 12."); + + configurationFileFormat.LoggingGraphicsDebugLevel = GraphicsDebugLevel.None; + + configurationFileUpdated = true; + } + List inputConfig = new List(); inputConfig.AddRange(configurationFileFormat.ControllerConfig); inputConfig.AddRange(configurationFileFormat.KeyboardConfig); @@ -694,6 +712,7 @@ namespace Ryujinx.Configuration Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest; Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog; Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses; + Logger.GraphicsDebugLevel.Value = configurationFileFormat.LoggingGraphicsDebugLevel; Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; System.Language.Value = configurationFileFormat.SystemLanguage; System.Region.Value = configurationFileFormat.SystemRegion; diff --git a/Ryujinx.Common/Configuration/GraphicsDebugLevel.cs b/Ryujinx.Common/Configuration/GraphicsDebugLevel.cs new file mode 100644 index 0000000000..1bef4a7e90 --- /dev/null +++ b/Ryujinx.Common/Configuration/GraphicsDebugLevel.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Common.Configuration +{ + public enum GraphicsDebugLevel + { + None, + Error, + Performance, + All + } +} diff --git a/Ryujinx.Graphics.GAL/IRenderer.cs b/Ryujinx.Graphics.GAL/IRenderer.cs index 6fd3feba60..fec8d3bea5 100644 --- a/Ryujinx.Graphics.GAL/IRenderer.cs +++ b/Ryujinx.Graphics.GAL/IRenderer.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Configuration; using Ryujinx.Graphics.Shader; using System; @@ -32,6 +33,6 @@ namespace Ryujinx.Graphics.GAL void ResetCounter(CounterType type); - void Initialize(); + void Initialize(GraphicsDebugLevel logLevel); } } diff --git a/Ryujinx.Graphics.OpenGL/Debugger.cs b/Ryujinx.Graphics.OpenGL/Debugger.cs index ff9fcd855a..9d0a1f59b6 100644 --- a/Ryujinx.Graphics.OpenGL/Debugger.cs +++ b/Ryujinx.Graphics.OpenGL/Debugger.cs @@ -1,7 +1,9 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using System; using System.Runtime.InteropServices; +using System.Threading; namespace Ryujinx.Graphics.OpenGL { @@ -9,15 +11,43 @@ namespace Ryujinx.Graphics.OpenGL { private static DebugProc _debugCallback; - public static void Initialize() + private static int _counter; + + public static void Initialize(GraphicsDebugLevel logLevel) { + // Disable everything + GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DontCare, DebugSeverityControl.DontCare, 0, (int[])null, false); + + if (logLevel == GraphicsDebugLevel.None) + { + GL.Disable(EnableCap.DebugOutputSynchronous); + GL.DebugMessageCallback(null, IntPtr.Zero); + + return; + } + GL.Enable(EnableCap.DebugOutputSynchronous); - GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DontCare, DebugSeverityControl.DontCare, 0, (int[])null, true); + if (logLevel == GraphicsDebugLevel.Error) + { + GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DebugTypeError, DebugSeverityControl.DontCare, 0, (int[])null, true); + } + else if (logLevel == GraphicsDebugLevel.Performance) + { + GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DebugTypeError, DebugSeverityControl.DontCare, 0, (int[])null, true); + GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DebugTypePerformance, DebugSeverityControl.DontCare, 0, (int[])null, true); + } + else + { + GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DontCare, DebugSeverityControl.DontCare, 0, (int[])null, true); + } + _counter = 0; _debugCallback = GLDebugHandler; GL.DebugMessageCallback(_debugCallback, IntPtr.Zero); + + Logger.PrintWarning(LogClass.Gpu, "OpenGL Debugging is enabled. Performance will be negatively impacted."); } private static void GLDebugHandler( @@ -29,20 +59,43 @@ namespace Ryujinx.Graphics.OpenGL IntPtr message, IntPtr userParam) { - string fullMessage = $"{type} {severity} {source} {Marshal.PtrToStringAnsi(message)}"; + string msg = Marshal.PtrToStringUTF8(message).Replace('\n', ' '); switch (type) { - case DebugType.DebugTypeError: - Logger.PrintError(LogClass.Gpu, fullMessage); - break; - case DebugType.DebugTypePerformance: - Logger.PrintWarning(LogClass.Gpu, fullMessage); - break; + case DebugType.DebugTypeError : Logger.PrintError(LogClass.Gpu, $"{severity}: {msg}\nCallStack={Environment.StackTrace}", "GLERROR"); break; + case DebugType.DebugTypePerformance: Logger.PrintWarning(LogClass.Gpu, $"{severity}: {msg}", "GLPERF"); break; + case DebugType.DebugTypePushGroup : Logger.PrintInfo(LogClass.Gpu, $"{{ ({id}) {severity}: {msg}", "GLINFO"); break; + case DebugType.DebugTypePopGroup : Logger.PrintInfo(LogClass.Gpu, $"}} ({id}) {severity}: {msg}", "GLINFO"); break; default: - Logger.PrintDebug(LogClass.Gpu, fullMessage); + if (source == DebugSource.DebugSourceApplication) + { + Logger.PrintInfo(LogClass.Gpu, $"{type} {severity}: {msg}", "GLINFO"); + } + else + { + Logger.PrintDebug(LogClass.Gpu, $"{type} {severity}: {msg}", "GLDEBUG"); + } break; } } + + // Useful debug helpers + public static void PushGroup(string dbgMsg) + { + int counter = Interlocked.Increment(ref _counter); + + GL.PushDebugGroup(DebugSourceExternal.DebugSourceApplication, counter, dbgMsg.Length, dbgMsg); + } + + public static void PopGroup() + { + GL.PopDebugGroup(); + } + + public static void Print(string dbgMsg, DebugType type = DebugType.DebugTypeMarker, DebugSeverity severity = DebugSeverity.DebugSeverityNotification, int id = 999999) + { + GL.DebugMessageInsert(DebugSourceExternal.DebugSourceApplication, type, id, severity, dbgMsg.Length, dbgMsg); + } } } diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs index 49324637bc..e7a8a96b79 100644 --- a/Ryujinx.Graphics.OpenGL/Renderer.cs +++ b/Ryujinx.Graphics.OpenGL/Renderer.cs @@ -1,4 +1,5 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.OpenGL.Image; @@ -96,8 +97,10 @@ namespace Ryujinx.Graphics.OpenGL return _counters.QueueReport(type, resultHandler); } - public void Initialize() + public void Initialize(GraphicsDebugLevel glLogLevel) { + Debugger.Initialize(glLogLevel); + PrintGpuInformation(); _counters.Initialize(); diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs index a8ed9156ce..867401ada1 100644 --- a/Ryujinx/Ui/GLRenderer.cs +++ b/Ryujinx/Ui/GLRenderer.cs @@ -5,6 +5,7 @@ using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using OpenTK.Input; using Ryujinx.Configuration; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Graphics.OpenGL; using Ryujinx.HLE; @@ -47,10 +48,14 @@ namespace Ryujinx.Ui private HotkeyButtons _prevHotkeyButtons; - public GlRenderer(Switch device) + private GraphicsDebugLevel _glLogLevel; + + public GlRenderer(Switch device, GraphicsDebugLevel glLogLevel) : base (GetGraphicsMode(), 3, 3, - GraphicsContextFlags.ForwardCompatible) + glLogLevel == GraphicsDebugLevel.None + ? GraphicsContextFlags.ForwardCompatible + : GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug) { WaitEvent = new ManualResetEvent(false); @@ -73,6 +78,8 @@ namespace Ryujinx.Ui | EventMask.KeyReleaseMask)); this.Shown += Renderer_Shown; + + _glLogLevel = glLogLevel; } private static GraphicsMode GetGraphicsMode() @@ -304,7 +311,7 @@ namespace Ryujinx.Ui // First take exclusivity on the OpenGL context. GraphicsContext.MakeCurrent(WindowInfo); - _renderer.Initialize(); + _renderer.Initialize(_glLogLevel); // Make sure the first frame is not transparent. GL.ClearColor(OpenTK.Color.Black); diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 92e0c95678..4287010784 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -501,7 +501,7 @@ namespace Ryujinx.Ui } ).ToArray()); - _glWidget = new GlRenderer(_emulationContext); + _glWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel); Application.Invoke(delegate { diff --git a/Ryujinx/Ui/SettingsWindow.cs b/Ryujinx/Ui/SettingsWindow.cs index b488fdbbb8..5fe51854ee 100644 --- a/Ryujinx/Ui/SettingsWindow.cs +++ b/Ryujinx/Ui/SettingsWindow.cs @@ -1,6 +1,7 @@ using Gtk; using Ryujinx.Audio; using Ryujinx.Configuration; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Configuration.System; using Ryujinx.HLE.HOS.Services.Time.TimeZone; @@ -35,6 +36,7 @@ namespace Ryujinx.Ui [GUI] CheckButton _guestLogToggle; [GUI] CheckButton _fsAccessLogToggle; [GUI] Adjustment _fsLogSpinAdjustment; + [GUI] ComboBoxText _graphicsDebugLevel; [GUI] CheckButton _dockedModeToggle; [GUI] CheckButton _discordToggle; [GUI] CheckButton _vSyncToggle; @@ -149,6 +151,13 @@ namespace Ryujinx.Ui _fsAccessLogToggle.Click(); } + foreach (GraphicsDebugLevel level in Enum.GetValues(typeof(GraphicsDebugLevel))) + { + _graphicsDebugLevel.Append(level.ToString(), level.ToString()); + } + + _graphicsDebugLevel.SetActiveId(ConfigurationState.Instance.Logger.GraphicsDebugLevel.Value.ToString()); + if (ConfigurationState.Instance.System.EnableDockedMode) { _dockedModeToggle.Click(); @@ -496,6 +505,7 @@ namespace Ryujinx.Ui ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active; ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active; ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active; + ConfigurationState.Instance.Logger.GraphicsDebugLevel.Value = Enum.Parse(_graphicsDebugLevel.ActiveId); ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active; ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active; ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active; diff --git a/Ryujinx/Ui/SettingsWindow.glade b/Ryujinx/Ui/SettingsWindow.glade index 384fed4dcf..33ea05b75d 100644 --- a/Ryujinx/Ui/SettingsWindow.glade +++ b/Ryujinx/Ui/SettingsWindow.glade @@ -2007,24 +2007,6 @@ 1 - - - Enable Debug Logs - True - True - False - Enables printing debug log messages - start - 5 - 5 - True - - - False - True - 2 - - Enable Stub Logs @@ -2188,6 +2170,102 @@ 0 + + + True + False + 5 + 5 + 10 + vertical + + + True + False + start + 5 + Use with care + Developer Options + + + + + + False + True + 20 + + + + + True + False + start + 10 + 10 + vertical + + + Enable Debug Logs + True + True + False + Enables printing debug log messages + start + 5 + 5 + True + + + False + True + 21 + + + + + True + False + 5 + + + True + False + Requires appropriate log levels enabled. Not persistent across restarts. + OpenGL Log Level + + + False + True + 5 + 22 + + + + + True + False + Requires appropriate log levels enabled. Not persistent across restarts. + 5 + + + False + True + 22 + + + + + + + + + False + True + 5 + 22 + + 4