VulkanDebugMessenger.cs
1 using Ryujinx.Common.Configuration; 2 using Ryujinx.Common.Logging; 3 using Ryujinx.Common.Utilities; 4 using Silk.NET.Vulkan; 5 using Silk.NET.Vulkan.Extensions.EXT; 6 using System; 7 using System.Runtime.InteropServices; 8 9 namespace Ryujinx.Graphics.Vulkan 10 { 11 class VulkanDebugMessenger : IDisposable 12 { 13 private readonly Vk _api; 14 private readonly Instance _instance; 15 private readonly GraphicsDebugLevel _logLevel; 16 private readonly ExtDebugUtils _debugUtils; 17 private readonly DebugUtilsMessengerEXT? _debugUtilsMessenger; 18 private bool _disposed; 19 20 public VulkanDebugMessenger(Vk api, Instance instance, GraphicsDebugLevel logLevel) 21 { 22 _api = api; 23 _instance = instance; 24 _logLevel = logLevel; 25 26 _api.TryGetInstanceExtension(instance, out _debugUtils); 27 28 Result result = TryInitialize(out _debugUtilsMessenger); 29 30 if (result != Result.Success) 31 { 32 Logger.Error?.Print(LogClass.Gpu, $"Vulkan debug messenger initialization failed with error {result}"); 33 } 34 } 35 36 private Result TryInitialize(out DebugUtilsMessengerEXT? debugUtilsMessengerHandle) 37 { 38 debugUtilsMessengerHandle = null; 39 40 if (_debugUtils != null && _logLevel != GraphicsDebugLevel.None) 41 { 42 var messageType = _logLevel switch 43 { 44 GraphicsDebugLevel.Error => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt, 45 GraphicsDebugLevel.Slowdowns => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt | 46 DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt, 47 GraphicsDebugLevel.All => DebugUtilsMessageTypeFlagsEXT.GeneralBitExt | 48 DebugUtilsMessageTypeFlagsEXT.ValidationBitExt | 49 DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt, 50 _ => throw new ArgumentException($"Invalid log level \"{_logLevel}\"."), 51 }; 52 53 var messageSeverity = _logLevel switch 54 { 55 GraphicsDebugLevel.Error => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt, 56 GraphicsDebugLevel.Slowdowns => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt | 57 DebugUtilsMessageSeverityFlagsEXT.WarningBitExt, 58 GraphicsDebugLevel.All => DebugUtilsMessageSeverityFlagsEXT.InfoBitExt | 59 DebugUtilsMessageSeverityFlagsEXT.WarningBitExt | 60 DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt | 61 DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt, 62 _ => throw new ArgumentException($"Invalid log level \"{_logLevel}\"."), 63 }; 64 65 var debugUtilsMessengerCreateInfo = new DebugUtilsMessengerCreateInfoEXT 66 { 67 SType = StructureType.DebugUtilsMessengerCreateInfoExt, 68 MessageType = messageType, 69 MessageSeverity = messageSeverity, 70 }; 71 72 unsafe 73 { 74 debugUtilsMessengerCreateInfo.PfnUserCallback = new PfnDebugUtilsMessengerCallbackEXT(UserCallback); 75 } 76 77 DebugUtilsMessengerEXT messengerHandle = default; 78 79 Result result = _debugUtils.CreateDebugUtilsMessenger(_instance, SpanHelpers.AsReadOnlySpan(ref debugUtilsMessengerCreateInfo), ReadOnlySpan<AllocationCallbacks>.Empty, SpanHelpers.AsSpan(ref messengerHandle)); 80 81 if (result == Result.Success) 82 { 83 debugUtilsMessengerHandle = messengerHandle; 84 } 85 86 return result; 87 } 88 89 return Result.Success; 90 } 91 92 private unsafe static uint UserCallback( 93 DebugUtilsMessageSeverityFlagsEXT messageSeverity, 94 DebugUtilsMessageTypeFlagsEXT messageTypes, 95 DebugUtilsMessengerCallbackDataEXT* pCallbackData, 96 void* pUserData) 97 { 98 var msg = Marshal.PtrToStringAnsi((IntPtr)pCallbackData->PMessage); 99 100 if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt)) 101 { 102 Logger.Error?.Print(LogClass.Gpu, msg); 103 } 104 else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.WarningBitExt)) 105 { 106 Logger.Warning?.Print(LogClass.Gpu, msg); 107 } 108 else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.InfoBitExt)) 109 { 110 Logger.Info?.Print(LogClass.Gpu, msg); 111 } 112 else // if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt)) 113 { 114 Logger.Debug?.Print(LogClass.Gpu, msg); 115 } 116 117 return 0; 118 } 119 120 public void Dispose() 121 { 122 if (!_disposed) 123 { 124 if (_debugUtilsMessenger.HasValue) 125 { 126 _debugUtils.DestroyDebugUtilsMessenger(_instance, _debugUtilsMessenger.Value, Span<AllocationCallbacks>.Empty); 127 } 128 129 _disposed = true; 130 } 131 } 132 } 133 }