Debugger.cs
1 using OpenTK.Graphics.OpenGL; 2 using Ryujinx.Common.Configuration; 3 using Ryujinx.Common.Logging; 4 using System; 5 using System.Runtime.InteropServices; 6 using System.Threading; 7 8 namespace Ryujinx.Graphics.OpenGL 9 { 10 public static class Debugger 11 { 12 private static DebugProc _debugCallback; 13 14 private static int _counter; 15 16 public static void Initialize(GraphicsDebugLevel logLevel) 17 { 18 // Disable everything 19 GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DontCare, DebugSeverityControl.DontCare, 0, (int[])null, false); 20 21 if (logLevel == GraphicsDebugLevel.None) 22 { 23 GL.Disable(EnableCap.DebugOutputSynchronous); 24 GL.DebugMessageCallback(null, IntPtr.Zero); 25 26 return; 27 } 28 29 GL.Enable(EnableCap.DebugOutputSynchronous); 30 31 if (logLevel == GraphicsDebugLevel.Error) 32 { 33 GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DebugTypeError, DebugSeverityControl.DontCare, 0, (int[])null, true); 34 } 35 else if (logLevel == GraphicsDebugLevel.Slowdowns) 36 { 37 GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DebugTypeError, DebugSeverityControl.DontCare, 0, (int[])null, true); 38 GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DebugTypePerformance, DebugSeverityControl.DontCare, 0, (int[])null, true); 39 } 40 else 41 { 42 GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DontCare, DebugSeverityControl.DontCare, 0, (int[])null, true); 43 } 44 45 _counter = 0; 46 _debugCallback = GLDebugHandler; 47 48 GL.DebugMessageCallback(_debugCallback, IntPtr.Zero); 49 50 Logger.Warning?.Print(LogClass.Gpu, "OpenGL Debugging is enabled. Performance will be negatively impacted."); 51 } 52 53 private static void GLDebugHandler( 54 DebugSource source, 55 DebugType type, 56 int id, 57 DebugSeverity severity, 58 int length, 59 IntPtr message, 60 IntPtr userParam) 61 { 62 string msg = Marshal.PtrToStringUTF8(message).Replace('\n', ' '); 63 64 switch (type) 65 { 66 case DebugType.DebugTypeError: 67 Logger.Error?.Print(LogClass.Gpu, $"{severity}: {msg}\nCallStack={Environment.StackTrace}", "GLERROR"); 68 break; 69 case DebugType.DebugTypePerformance: 70 Logger.Warning?.Print(LogClass.Gpu, $"{severity}: {msg}", "GLPERF"); 71 break; 72 case DebugType.DebugTypePushGroup: 73 Logger.Info?.Print(LogClass.Gpu, $"{{ ({id}) {severity}: {msg}", "GLINFO"); 74 break; 75 case DebugType.DebugTypePopGroup: 76 Logger.Info?.Print(LogClass.Gpu, $"}} ({id}) {severity}: {msg}", "GLINFO"); 77 break; 78 default: 79 if (source == DebugSource.DebugSourceApplication) 80 { 81 Logger.Info?.Print(LogClass.Gpu, $"{type} {severity}: {msg}", "GLINFO"); 82 } 83 else 84 { 85 Logger.Debug?.Print(LogClass.Gpu, $"{type} {severity}: {msg}", "GLDEBUG"); 86 } 87 break; 88 } 89 } 90 91 // Useful debug helpers 92 public static void PushGroup(string dbgMsg) 93 { 94 int counter = Interlocked.Increment(ref _counter); 95 96 GL.PushDebugGroup(DebugSourceExternal.DebugSourceApplication, counter, dbgMsg.Length, dbgMsg); 97 } 98 99 public static void PopGroup() 100 { 101 GL.PopDebugGroup(); 102 } 103 104 public static void Print(string dbgMsg, DebugType type = DebugType.DebugTypeMarker, DebugSeverity severity = DebugSeverity.DebugSeverityNotification, int id = 999999) 105 { 106 GL.DebugMessageInsert(DebugSourceExternal.DebugSourceApplication, type, id, severity, dbgMsg.Length, dbgMsg); 107 } 108 } 109 }