diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/VulkanDebugMessenger.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Vulkan/VulkanDebugMessenger.cs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanDebugMessenger.cs b/src/Ryujinx.Graphics.Vulkan/VulkanDebugMessenger.cs new file mode 100644 index 00000000..7e39a251 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/VulkanDebugMessenger.cs @@ -0,0 +1,153 @@ +using Ryujinx.Common.Configuration; +using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; +using Silk.NET.Vulkan; +using Silk.NET.Vulkan.Extensions.EXT; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Vulkan +{ + class VulkanDebugMessenger : IDisposable + { + private static string[] _excludedMessages = new string[] + { + // NOTE: Done on purpose right now. + "UNASSIGNED-CoreValidation-Shader-OutputNotConsumed", + // TODO: Figure out if fixable + "VUID-vkCmdDrawIndexed-None-04584", + // TODO: Might be worth looking into making this happy to possibly optimize copies. + "UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout", + // TODO: Fix this, it's causing too much noise right now. + "VUID-VkSubpassDependency-srcSubpass-00867" + }; + + private readonly Vk _api; + private readonly Instance _instance; + private readonly GraphicsDebugLevel _logLevel; + private readonly ExtDebugUtils _debugUtils; + private readonly DebugUtilsMessengerEXT? _debugUtilsMessenger; + private bool _disposed; + + public VulkanDebugMessenger(Vk api, Instance instance, GraphicsDebugLevel logLevel) + { + _api = api; + _instance = instance; + _logLevel = logLevel; + + _api.TryGetInstanceExtension(instance, out _debugUtils); + + Result result = TryInitialize(out _debugUtilsMessenger); + + if (result != Result.Success) + { + Logger.Error?.Print(LogClass.Gpu, $"Vulkan debug messenger initialization failed with error {result}"); + } + } + + private Result TryInitialize(out DebugUtilsMessengerEXT? debugUtilsMessengerHandle) + { + debugUtilsMessengerHandle = null; + + if (_debugUtils != null && _logLevel != GraphicsDebugLevel.None) + { + var messageType = _logLevel switch + { + GraphicsDebugLevel.Error => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt, + GraphicsDebugLevel.Slowdowns => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt | + DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt, + GraphicsDebugLevel.All => DebugUtilsMessageTypeFlagsEXT.GeneralBitExt | + DebugUtilsMessageTypeFlagsEXT.ValidationBitExt | + DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt, + _ => throw new ArgumentException($"Invalid log level \"{_logLevel}\".") + }; + + var messageSeverity = _logLevel switch + { + GraphicsDebugLevel.Error => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt, + GraphicsDebugLevel.Slowdowns => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt | + DebugUtilsMessageSeverityFlagsEXT.WarningBitExt, + GraphicsDebugLevel.All => DebugUtilsMessageSeverityFlagsEXT.InfoBitExt | + DebugUtilsMessageSeverityFlagsEXT.WarningBitExt | + DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt | + DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt, + _ => throw new ArgumentException($"Invalid log level \"{_logLevel}\".") + }; + + var debugUtilsMessengerCreateInfo = new DebugUtilsMessengerCreateInfoEXT() + { + SType = StructureType.DebugUtilsMessengerCreateInfoExt, + MessageType = messageType, + MessageSeverity = messageSeverity + }; + + unsafe + { + debugUtilsMessengerCreateInfo.PfnUserCallback = new PfnDebugUtilsMessengerCallbackEXT(UserCallback); + } + + DebugUtilsMessengerEXT messengerHandle = default; + + Result result = _debugUtils.CreateDebugUtilsMessenger(_instance, SpanHelpers.AsReadOnlySpan(ref debugUtilsMessengerCreateInfo), ReadOnlySpan<AllocationCallbacks>.Empty, SpanHelpers.AsSpan(ref messengerHandle)); + + if (result == Result.Success) + { + debugUtilsMessengerHandle = messengerHandle; + } + + return result; + } + + return Result.Success; + } + + private unsafe static uint UserCallback( + DebugUtilsMessageSeverityFlagsEXT messageSeverity, + DebugUtilsMessageTypeFlagsEXT messageTypes, + DebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) + { + var msg = Marshal.PtrToStringAnsi((IntPtr)pCallbackData->PMessage); + + foreach (string excludedMessagePart in _excludedMessages) + { + if (msg.Contains(excludedMessagePart)) + { + return 0; + } + } + + if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt)) + { + Logger.Error?.Print(LogClass.Gpu, msg); + } + else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.WarningBitExt)) + { + Logger.Warning?.Print(LogClass.Gpu, msg); + } + else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.InfoBitExt)) + { + Logger.Info?.Print(LogClass.Gpu, msg); + } + else // if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt)) + { + Logger.Debug?.Print(LogClass.Gpu, msg); + } + + return 0; + } + + public void Dispose() + { + if (!_disposed) + { + if (_debugUtilsMessenger.HasValue) + { + _debugUtils.DestroyDebugUtilsMessenger(_instance, _debugUtilsMessenger.Value, Span<AllocationCallbacks>.Empty); + } + + _disposed = true; + } + } + } +} |