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
-
-
-
- False
- True
- 2
-
-
+
+
+
+ False
+ True
+ 5
+ 22
+
+
4