vulkan: Separate debug utils logic from VulkanInitialization (#4609)
* vulkan: Separate debug utils logic from VulkanInitialization Also checks for VK_EXT_debug_utils existence instead of force enabling it and allow possible error during messenger init * Address gdkchan's comment * Use CreateDebugUtilsMessenger Span variant
This commit is contained in:
parent
210557951b
commit
f5a6f45b27
3 changed files with 165 additions and 118 deletions
153
Ryujinx.Graphics.Vulkan/VulkanDebugMessenger.cs
Normal file
153
Ryujinx.Graphics.Vulkan/VulkanDebugMessenger.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue