Facilitate OpenGL debug logging via GUI (#1373)

* Allow printing GL Debug logs with GUI options

Improve GL Debugger

Make the new option persistent

Address gdkchan's comments
- Rename enum to GraphicsDebugLevel
- Move Debugger Init to Renderer Init
- Fix formatting

* nit: newlines
This commit is contained in:
mageven 2020-08-02 20:11:24 +05:30 committed by GitHub
parent 1457ab5456
commit f0c91d9efb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 231 additions and 44 deletions

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
@ -13,7 +14,7 @@ namespace Ryujinx.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 11; public const int CurrentVersion = 12;
public int Version { get; set; } public int Version { get; set; }
@ -77,6 +78,11 @@ namespace Ryujinx.Configuration
/// </summary> /// </summary>
public LogClass[] LoggingFilteredClasses { get; set; } public LogClass[] LoggingFilteredClasses { get; set; }
/// <summary>
/// Change Graphics API debug log level
/// </summary>
public GraphicsDebugLevel LoggingGraphicsDebugLevel { get; set; }
/// <summary> /// <summary>
/// Enables or disables logging to a file on disk /// Enables or disables logging to a file on disk
/// </summary> /// </summary>

View file

@ -1,4 +1,5 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Configuration.Hid; using Ryujinx.Configuration.Hid;
@ -141,17 +142,23 @@ namespace Ryujinx.Configuration
/// </summary> /// </summary>
public ReactiveObject<bool> EnableFileLog { get; private set; } public ReactiveObject<bool> EnableFileLog { get; private set; }
/// <summary>
/// Controls which OpenGL log messages are recorded in the log
/// </summary>
public ReactiveObject<GraphicsDebugLevel> GraphicsDebugLevel { get; private set; }
public LoggerSection() public LoggerSection()
{ {
EnableDebug = new ReactiveObject<bool>(); EnableDebug = new ReactiveObject<bool>();
EnableStub = new ReactiveObject<bool>(); EnableStub = new ReactiveObject<bool>();
EnableInfo = new ReactiveObject<bool>(); EnableInfo = new ReactiveObject<bool>();
EnableWarn = new ReactiveObject<bool>(); EnableWarn = new ReactiveObject<bool>();
EnableError = new ReactiveObject<bool>(); EnableError = new ReactiveObject<bool>();
EnableGuest = new ReactiveObject<bool>(); EnableGuest = new ReactiveObject<bool>();
EnableFsAccessLog = new ReactiveObject<bool>(); EnableFsAccessLog = new ReactiveObject<bool>();
FilteredClasses = new ReactiveObject<LogClass[]>(); FilteredClasses = new ReactiveObject<LogClass[]>();
EnableFileLog = new ReactiveObject<bool>(); EnableFileLog = new ReactiveObject<bool>();
GraphicsDebugLevel = new ReactiveObject<GraphicsDebugLevel>();
} }
} }
@ -378,6 +385,7 @@ namespace Ryujinx.Configuration
LoggingEnableGuest = Logger.EnableGuest, LoggingEnableGuest = Logger.EnableGuest,
LoggingEnableFsAccessLog = Logger.EnableFsAccessLog, LoggingEnableFsAccessLog = Logger.EnableFsAccessLog,
LoggingFilteredClasses = Logger.FilteredClasses, LoggingFilteredClasses = Logger.FilteredClasses,
LoggingGraphicsDebugLevel = Logger.GraphicsDebugLevel,
EnableFileLog = Logger.EnableFileLog, EnableFileLog = Logger.EnableFileLog,
SystemLanguage = System.Language, SystemLanguage = System.Language,
SystemRegion = System.Region, SystemRegion = System.Region,
@ -436,6 +444,7 @@ namespace Ryujinx.Configuration
Logger.EnableGuest.Value = true; Logger.EnableGuest.Value = true;
Logger.EnableFsAccessLog.Value = false; Logger.EnableFsAccessLog.Value = false;
Logger.FilteredClasses.Value = new LogClass[] { }; Logger.FilteredClasses.Value = new LogClass[] { };
Logger.GraphicsDebugLevel.Value = GraphicsDebugLevel.None;
Logger.EnableFileLog.Value = true; Logger.EnableFileLog.Value = true;
System.Language.Value = Language.AmericanEnglish; System.Language.Value = Language.AmericanEnglish;
System.Region.Value = Region.USA; System.Region.Value = Region.USA;
@ -678,6 +687,15 @@ namespace Ryujinx.Configuration
configurationFileUpdated = true; 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> inputConfig = new List<InputConfig>(); List<InputConfig> inputConfig = new List<InputConfig>();
inputConfig.AddRange(configurationFileFormat.ControllerConfig); inputConfig.AddRange(configurationFileFormat.ControllerConfig);
inputConfig.AddRange(configurationFileFormat.KeyboardConfig); inputConfig.AddRange(configurationFileFormat.KeyboardConfig);
@ -694,6 +712,7 @@ namespace Ryujinx.Configuration
Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest; Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest;
Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog; Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog;
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses; Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
Logger.GraphicsDebugLevel.Value = configurationFileFormat.LoggingGraphicsDebugLevel;
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
System.Language.Value = configurationFileFormat.SystemLanguage; System.Language.Value = configurationFileFormat.SystemLanguage;
System.Region.Value = configurationFileFormat.SystemRegion; System.Region.Value = configurationFileFormat.SystemRegion;

View file

@ -0,0 +1,10 @@
namespace Ryujinx.Common.Configuration
{
public enum GraphicsDebugLevel
{
None,
Error,
Performance,
All
}
}

View file

@ -1,3 +1,4 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using System; using System;
@ -32,6 +33,6 @@ namespace Ryujinx.Graphics.GAL
void ResetCounter(CounterType type); void ResetCounter(CounterType type);
void Initialize(); void Initialize(GraphicsDebugLevel logLevel);
} }
} }

View file

@ -1,7 +1,9 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL
{ {
@ -9,15 +11,43 @@ namespace Ryujinx.Graphics.OpenGL
{ {
private static DebugProc _debugCallback; 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.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; _debugCallback = GLDebugHandler;
GL.DebugMessageCallback(_debugCallback, IntPtr.Zero); GL.DebugMessageCallback(_debugCallback, IntPtr.Zero);
Logger.PrintWarning(LogClass.Gpu, "OpenGL Debugging is enabled. Performance will be negatively impacted.");
} }
private static void GLDebugHandler( private static void GLDebugHandler(
@ -29,20 +59,43 @@ namespace Ryujinx.Graphics.OpenGL
IntPtr message, IntPtr message,
IntPtr userParam) IntPtr userParam)
{ {
string fullMessage = $"{type} {severity} {source} {Marshal.PtrToStringAnsi(message)}"; string msg = Marshal.PtrToStringUTF8(message).Replace('\n', ' ');
switch (type) switch (type)
{ {
case DebugType.DebugTypeError: case DebugType.DebugTypeError : Logger.PrintError(LogClass.Gpu, $"{severity}: {msg}\nCallStack={Environment.StackTrace}", "GLERROR"); break;
Logger.PrintError(LogClass.Gpu, fullMessage); case DebugType.DebugTypePerformance: Logger.PrintWarning(LogClass.Gpu, $"{severity}: {msg}", "GLPERF"); break;
break; case DebugType.DebugTypePushGroup : Logger.PrintInfo(LogClass.Gpu, $"{{ ({id}) {severity}: {msg}", "GLINFO"); break;
case DebugType.DebugTypePerformance: case DebugType.DebugTypePopGroup : Logger.PrintInfo(LogClass.Gpu, $"}} ({id}) {severity}: {msg}", "GLINFO"); break;
Logger.PrintWarning(LogClass.Gpu, fullMessage);
break;
default: 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; 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);
}
} }
} }

View file

@ -1,4 +1,5 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Image; using Ryujinx.Graphics.OpenGL.Image;
@ -96,8 +97,10 @@ namespace Ryujinx.Graphics.OpenGL
return _counters.QueueReport(type, resultHandler); return _counters.QueueReport(type, resultHandler);
} }
public void Initialize() public void Initialize(GraphicsDebugLevel glLogLevel)
{ {
Debugger.Initialize(glLogLevel);
PrintGpuInformation(); PrintGpuInformation();
_counters.Initialize(); _counters.Initialize();

View file

@ -5,6 +5,7 @@ using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using OpenTK.Input; using OpenTK.Input;
using Ryujinx.Configuration; using Ryujinx.Configuration;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE; using Ryujinx.HLE;
@ -47,10 +48,14 @@ namespace Ryujinx.Ui
private HotkeyButtons _prevHotkeyButtons; private HotkeyButtons _prevHotkeyButtons;
public GlRenderer(Switch device) private GraphicsDebugLevel _glLogLevel;
public GlRenderer(Switch device, GraphicsDebugLevel glLogLevel)
: base (GetGraphicsMode(), : base (GetGraphicsMode(),
3, 3, 3, 3,
GraphicsContextFlags.ForwardCompatible) glLogLevel == GraphicsDebugLevel.None
? GraphicsContextFlags.ForwardCompatible
: GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
{ {
WaitEvent = new ManualResetEvent(false); WaitEvent = new ManualResetEvent(false);
@ -73,6 +78,8 @@ namespace Ryujinx.Ui
| EventMask.KeyReleaseMask)); | EventMask.KeyReleaseMask));
this.Shown += Renderer_Shown; this.Shown += Renderer_Shown;
_glLogLevel = glLogLevel;
} }
private static GraphicsMode GetGraphicsMode() private static GraphicsMode GetGraphicsMode()
@ -304,7 +311,7 @@ namespace Ryujinx.Ui
// First take exclusivity on the OpenGL context. // First take exclusivity on the OpenGL context.
GraphicsContext.MakeCurrent(WindowInfo); GraphicsContext.MakeCurrent(WindowInfo);
_renderer.Initialize(); _renderer.Initialize(_glLogLevel);
// Make sure the first frame is not transparent. // Make sure the first frame is not transparent.
GL.ClearColor(OpenTK.Color.Black); GL.ClearColor(OpenTK.Color.Black);

View file

@ -501,7 +501,7 @@ namespace Ryujinx.Ui
} }
).ToArray()); ).ToArray());
_glWidget = new GlRenderer(_emulationContext); _glWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
Application.Invoke(delegate Application.Invoke(delegate
{ {

View file

@ -1,6 +1,7 @@
using Gtk; using Gtk;
using Ryujinx.Audio; using Ryujinx.Audio;
using Ryujinx.Configuration; using Ryujinx.Configuration;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Configuration.System; using Ryujinx.Configuration.System;
using Ryujinx.HLE.HOS.Services.Time.TimeZone; using Ryujinx.HLE.HOS.Services.Time.TimeZone;
@ -35,6 +36,7 @@ namespace Ryujinx.Ui
[GUI] CheckButton _guestLogToggle; [GUI] CheckButton _guestLogToggle;
[GUI] CheckButton _fsAccessLogToggle; [GUI] CheckButton _fsAccessLogToggle;
[GUI] Adjustment _fsLogSpinAdjustment; [GUI] Adjustment _fsLogSpinAdjustment;
[GUI] ComboBoxText _graphicsDebugLevel;
[GUI] CheckButton _dockedModeToggle; [GUI] CheckButton _dockedModeToggle;
[GUI] CheckButton _discordToggle; [GUI] CheckButton _discordToggle;
[GUI] CheckButton _vSyncToggle; [GUI] CheckButton _vSyncToggle;
@ -149,6 +151,13 @@ namespace Ryujinx.Ui
_fsAccessLogToggle.Click(); _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) if (ConfigurationState.Instance.System.EnableDockedMode)
{ {
_dockedModeToggle.Click(); _dockedModeToggle.Click();
@ -496,6 +505,7 @@ namespace Ryujinx.Ui
ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active; ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active;
ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active; ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active;
ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active; ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active;
ConfigurationState.Instance.Logger.GraphicsDebugLevel.Value = Enum.Parse<GraphicsDebugLevel>(_graphicsDebugLevel.ActiveId);
ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active; ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active;
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active; ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active; ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;

View file

@ -2007,24 +2007,6 @@
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkCheckButton" id="_debugLogToggle">
<property name="label" translatable="yes">Enable Debug Logs</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Enables printing debug log messages</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child> <child>
<object class="GtkCheckButton" id="_stubLogToggle"> <object class="GtkCheckButton" id="_stubLogToggle">
<property name="label" translatable="yes">Enable Stub Logs</property> <property name="label" translatable="yes">Enable Stub Logs</property>
@ -2188,6 +2170,102 @@
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkBox" id="CatDevLogging">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_bottom">5</property>
<property name="tooltip_text" translatable="yes">Use with care</property>
<property name="label" translatable="yes">Developer Options</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">20</property>
</packing>
</child>
<child>
<object class="GtkBox" id="DevLoggingOptions">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkCheckButton" id="_debugLogToggle">
<property name="label" translatable="yes">Enable Debug Logs</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Enables printing debug log messages</property>
<property name="halign">start</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">21</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Requires appropriate log levels enabled. Not persistent across restarts.</property>
<property name="label" translatable="yes">OpenGL Log Level</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">22</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="_graphicsDebugLevel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Requires appropriate log levels enabled. Not persistent across restarts.</property>
<property name="margin_left">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">22</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">22</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="position">4</property> <property name="position">4</property>