aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.OpenGL/Debugger.cs
blob: 9f67cfc67ac90576331e6b84070222bb288bd525 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
{
    public static class Debugger
    {
        private static DebugProc _debugCallback;

        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);

            if (logLevel == GraphicsDebugLevel.Error)
            {
                GL.DebugMessageControl(DebugSourceControl.DontCare, DebugTypeControl.DebugTypeError, DebugSeverityControl.DontCare, 0, (int[])null, true);
            }
            else if (logLevel == GraphicsDebugLevel.Slowdowns)
            {
                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.Warning?.Print(LogClass.Gpu, "OpenGL Debugging is enabled. Performance will be negatively impacted.");
        }

        private static void GLDebugHandler(
            DebugSource source,
            DebugType type,
            int id,
            DebugSeverity severity,
            int length,
            IntPtr message,
            IntPtr userParam)
        {
            string msg = Marshal.PtrToStringUTF8(message).Replace('\n', ' ');

            switch (type)
            {
                case DebugType.DebugTypeError      : Logger.Error?.Print(LogClass.Gpu, $"{severity}: {msg}\nCallStack={Environment.StackTrace}", "GLERROR"); break;
                case DebugType.DebugTypePerformance: Logger.Warning?.Print(LogClass.Gpu, $"{severity}: {msg}", "GLPERF"); break;
                case DebugType.DebugTypePushGroup  : Logger.Info?.Print(LogClass.Gpu, $"{{ ({id}) {severity}: {msg}", "GLINFO"); break;
                case DebugType.DebugTypePopGroup   : Logger.Info?.Print(LogClass.Gpu, $"}} ({id}) {severity}: {msg}", "GLINFO"); break;
                default:
                    if (source == DebugSource.DebugSourceApplication)
                    {
                        Logger.Info?.Print(LogClass.Gpu, $"{type} {severity}: {msg}", "GLINFO");
                    }
                    else
                    {
                        Logger.Debug?.Print(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);
        }
    }
}