VulkanDebugMessenger.cs 5.3 KB

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