summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matías Locatti2022-12-02 18:32:54 -0300
committerGravatar GitHub2022-12-02 18:32:54 -0300
commitc043ba84675794b37c42ac47b2776dc57d63decb (patch)
tree479743223a7103a600bf162fffa0203c9f92232d
parentMerge pull request #9363 from liamwhite/gs (diff)
parentVulkan: update initialization (diff)
downloadyuzu-c043ba84675794b37c42ac47b2776dc57d63decb.tar.gz
yuzu-c043ba84675794b37c42ac47b2776dc57d63decb.tar.xz
yuzu-c043ba84675794b37c42ac47b2776dc57d63decb.zip
Merge pull request #9303 from liamwhite/new-vulkan-init
Vulkan: update initialization
-rw-r--r--.gitmodules2
m---------externals/sirit0
-rw-r--r--src/core/frontend/emu_window.h2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp13
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp35
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp4
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp120
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h16
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.cpp27
-rw-r--r--src/video_core/vulkan_common/vulkan_surface.cpp38
-rw-r--r--src/yuzu/bootmanager.cpp4
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp2
-rw-r--r--src/yuzu/startup_checks.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp27
15 files changed, 192 insertions, 102 deletions
diff --git a/.gitmodules b/.gitmodules
index 8a90f4d15..8e98ee9cb 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -27,7 +27,7 @@
27 url = https://github.com/KhronosGroup/Vulkan-Headers.git 27 url = https://github.com/KhronosGroup/Vulkan-Headers.git
28[submodule "sirit"] 28[submodule "sirit"]
29 path = externals/sirit 29 path = externals/sirit
30 url = https://github.com/ReinUsesLisp/sirit 30 url = https://github.com/yuzu-emu/sirit
31[submodule "mbedtls"] 31[submodule "mbedtls"]
32 path = externals/mbedtls 32 path = externals/mbedtls
33 url = https://github.com/yuzu-emu/mbedtls 33 url = https://github.com/yuzu-emu/mbedtls
diff --git a/externals/sirit b/externals/sirit
Subproject aa292d56650bc28f2b2d75973fab2e61d0136f9 Subproject d7ad93a88864bda94e282e95028f90b5784e4d2
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index ac1906d5e..95363b645 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -17,6 +17,8 @@ enum class WindowSystemType {
17 Windows, 17 Windows,
18 X11, 18 X11,
19 Wayland, 19 Wayland,
20 Cocoa,
21 Android,
20}; 22};
21 23
22/** 24/**
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 265ac9c85..0f86a8004 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -402,8 +402,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
402 ctx.AddCapability(spv::Capability::SparseResidency); 402 ctx.AddCapability(spv::Capability::SparseResidency);
403 } 403 }
404 if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) { 404 if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) {
405 ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); 405 if (profile.supported_spirv < 0x00010600) {
406 ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); 406 ctx.AddExtension("SPV_EXT_demote_to_helper_invocation");
407 }
408 ctx.AddCapability(spv::Capability::DemoteToHelperInvocation);
407 } 409 }
408 if (info.stores[IR::Attribute::ViewportIndex]) { 410 if (info.stores[IR::Attribute::ViewportIndex]) {
409 ctx.AddCapability(spv::Capability::MultiViewport); 411 ctx.AddCapability(spv::Capability::MultiViewport);
@@ -426,12 +428,11 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
426 if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || 428 if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id ||
427 info.uses_subgroup_shuffles) && 429 info.uses_subgroup_shuffles) &&
428 profile.support_vote) { 430 profile.support_vote) {
429 ctx.AddExtension("SPV_KHR_shader_ballot"); 431 ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
430 ctx.AddCapability(spv::Capability::SubgroupBallotKHR); 432 ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
431 if (!profile.warp_size_potentially_larger_than_guest) { 433 if (!profile.warp_size_potentially_larger_than_guest) {
432 // vote ops are only used when not taking the long path 434 // vote ops are only used when not taking the long path
433 ctx.AddExtension("SPV_KHR_subgroup_vote"); 435 ctx.AddCapability(spv::Capability::GroupNonUniformVote);
434 ctx.AddCapability(spv::Capability::SubgroupVoteKHR);
435 } 436 }
436 } 437 }
437 if (info.uses_int64_bit_atomics && profile.support_int64_atomics) { 438 if (info.uses_int64_bit_atomics && profile.support_int64_atomics) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
index 7ad0b08ac..fb2c792c1 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
@@ -12,7 +12,7 @@ void EmitJoin(EmitContext&) {
12 12
13void EmitDemoteToHelperInvocation(EmitContext& ctx) { 13void EmitDemoteToHelperInvocation(EmitContext& ctx) {
14 if (ctx.profile.support_demote_to_helper_invocation) { 14 if (ctx.profile.support_demote_to_helper_invocation) {
15 ctx.OpDemoteToHelperInvocationEXT(); 15 ctx.OpDemoteToHelperInvocation();
16 } else { 16 } else {
17 const Id kill_label{ctx.OpLabel()}; 17 const Id kill_label{ctx.OpLabel()};
18 const Id impossible_label{ctx.OpLabel()}; 18 const Id impossible_label{ctx.OpLabel()};
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
index 7cbbbfaa6..2c90f2368 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
@@ -6,6 +6,10 @@
6 6
7namespace Shader::Backend::SPIRV { 7namespace Shader::Backend::SPIRV {
8namespace { 8namespace {
9Id SubgroupScope(EmitContext& ctx) {
10 return ctx.Const(static_cast<u32>(spv::Scope::Subgroup));
11}
12
9Id GetThreadId(EmitContext& ctx) { 13Id GetThreadId(EmitContext& ctx) {
10 return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id); 14 return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id);
11} 15}
@@ -49,8 +53,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask
49} 53}
50 54
51Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) { 55Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) {
52 return ctx.OpSelect(ctx.U32[1], in_range, 56 return ctx.OpSelect(
53 ctx.OpSubgroupReadInvocationKHR(ctx.U32[1], value, src_thread_id), value); 57 ctx.U32[1], in_range,
58 ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value);
54} 59}
55 60
56Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) { 61Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) {
@@ -71,40 +76,46 @@ Id EmitLaneId(EmitContext& ctx) {
71 76
72Id EmitVoteAll(EmitContext& ctx, Id pred) { 77Id EmitVoteAll(EmitContext& ctx, Id pred) {
73 if (!ctx.profile.warp_size_potentially_larger_than_guest) { 78 if (!ctx.profile.warp_size_potentially_larger_than_guest) {
74 return ctx.OpSubgroupAllKHR(ctx.U1, pred); 79 return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred);
75 } 80 }
76 const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; 81 const Id mask_ballot{
82 ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};
77 const Id active_mask{WarpExtract(ctx, mask_ballot)}; 83 const Id active_mask{WarpExtract(ctx, mask_ballot)};
78 const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; 84 const Id ballot{
85 WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};
79 const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; 86 const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};
80 return ctx.OpIEqual(ctx.U1, lhs, active_mask); 87 return ctx.OpIEqual(ctx.U1, lhs, active_mask);
81} 88}
82 89
83Id EmitVoteAny(EmitContext& ctx, Id pred) { 90Id EmitVoteAny(EmitContext& ctx, Id pred) {
84 if (!ctx.profile.warp_size_potentially_larger_than_guest) { 91 if (!ctx.profile.warp_size_potentially_larger_than_guest) {
85 return ctx.OpSubgroupAnyKHR(ctx.U1, pred); 92 return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred);
86 } 93 }
87 const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; 94 const Id mask_ballot{
95 ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};
88 const Id active_mask{WarpExtract(ctx, mask_ballot)}; 96 const Id active_mask{WarpExtract(ctx, mask_ballot)};
89 const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; 97 const Id ballot{
98 WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};
90 const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; 99 const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};
91 return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value); 100 return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value);
92} 101}
93 102
94Id EmitVoteEqual(EmitContext& ctx, Id pred) { 103Id EmitVoteEqual(EmitContext& ctx, Id pred) {
95 if (!ctx.profile.warp_size_potentially_larger_than_guest) { 104 if (!ctx.profile.warp_size_potentially_larger_than_guest) {
96 return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred); 105 return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred);
97 } 106 }
98 const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; 107 const Id mask_ballot{
108 ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};
99 const Id active_mask{WarpExtract(ctx, mask_ballot)}; 109 const Id active_mask{WarpExtract(ctx, mask_ballot)};
100 const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; 110 const Id ballot{
111 WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};
101 const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)}; 112 const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)};
102 return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value), 113 return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value),
103 ctx.OpIEqual(ctx.U1, lhs, active_mask)); 114 ctx.OpIEqual(ctx.U1, lhs, active_mask));
104} 115}
105 116
106Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { 117Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
107 const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)}; 118 const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)};
108 if (!ctx.profile.warp_size_potentially_larger_than_guest) { 119 if (!ctx.profile.warp_size_potentially_larger_than_guest) {
109 return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U); 120 return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U);
110 } 121 }
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 150413b04..29da442fa 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment;
54using VideoCommon::GenericEnvironment; 54using VideoCommon::GenericEnvironment;
55using VideoCommon::GraphicsEnvironment; 55using VideoCommon::GraphicsEnvironment;
56 56
57constexpr u32 CACHE_VERSION = 7; 57constexpr u32 CACHE_VERSION = 8;
58 58
59template <typename Container> 59template <typename Container>
60auto MakeSpan(Container& container) { 60auto MakeSpan(Container& container) {
@@ -289,7 +289,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
289 const auto& float_control{device.FloatControlProperties()}; 289 const auto& float_control{device.FloatControlProperties()};
290 const VkDriverIdKHR driver_id{device.GetDriverID()}; 290 const VkDriverIdKHR driver_id{device.GetDriverID()};
291 profile = Shader::Profile{ 291 profile = Shader::Profile{
292 .supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U, 292 .supported_spirv = device.SupportedSpirvVersion(),
293 .unified_descriptor_binding = true, 293 .unified_descriptor_binding = true,
294 .support_descriptor_aliasing = true, 294 .support_descriptor_aliasing = true,
295 .support_int8 = device.IsInt8Supported(), 295 .support_int8 = device.IsInt8Supported(),
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index ddecfca13..a16a8275b 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -74,23 +74,14 @@ enum class NvidiaArchitecture {
74}; 74};
75 75
76constexpr std::array REQUIRED_EXTENSIONS{ 76constexpr std::array REQUIRED_EXTENSIONS{
77 VK_KHR_MAINTENANCE1_EXTENSION_NAME,
78 VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME,
79 VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
80 VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
81 VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
82 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
83 VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
84 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
85 VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
86 VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
87 VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
88 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, 77 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
89 VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
90 VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
91 VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, 78 VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
79
80 // Core in 1.2, but required due to use of extension methods,
81 // and well-supported by drivers
82 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
83 VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
92 VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, 84 VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
93 VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
94#ifdef _WIN32 85#ifdef _WIN32
95 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, 86 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
96#endif 87#endif
@@ -99,6 +90,17 @@ constexpr std::array REQUIRED_EXTENSIONS{
99#endif 90#endif
100}; 91};
101 92
93constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{
94 VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
95 VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
96 VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
97 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
98};
99
100constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{
101 VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
102};
103
102template <typename T> 104template <typename T>
103void SetNext(void**& next, T& data) { 105void SetNext(void**& next, T& data) {
104 *next = &data; 106 *next = &data;
@@ -327,7 +329,8 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
327Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, 329Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
328 const vk::InstanceDispatch& dld_) 330 const vk::InstanceDispatch& dld_)
329 : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, 331 : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
330 supported_extensions{GetSupportedExtensions(physical)}, 332 instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions(
333 physical)},
331 format_properties(GetFormatProperties(physical)) { 334 format_properties(GetFormatProperties(physical)) {
332 CheckSuitability(surface != nullptr); 335 CheckSuitability(surface != nullptr);
333 SetupFamilies(surface); 336 SetupFamilies(surface);
@@ -451,8 +454,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
451 }; 454 };
452 SetNext(next, variable_pointers); 455 SetNext(next, variable_pointers);
453 456
454 VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{ 457 VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{
455 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT, 458 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES,
456 .pNext = nullptr, 459 .pNext = nullptr,
457 .shaderDemoteToHelperInvocation = true, 460 .shaderDemoteToHelperInvocation = true,
458 }; 461 };
@@ -896,28 +899,51 @@ std::string Device::GetDriverName() const {
896 } 899 }
897} 900}
898 901
902static std::vector<const char*> ExtensionsRequiredForInstanceVersion(u32 available_version) {
903 std::vector<const char*> extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()};
904
905 if (available_version < VK_API_VERSION_1_2) {
906 extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(),
907 REQUIRED_EXTENSIONS_BEFORE_1_2.end());
908 }
909
910 if (available_version < VK_API_VERSION_1_3) {
911 extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(),
912 REQUIRED_EXTENSIONS_BEFORE_1_3.end());
913 }
914
915 return extensions;
916}
917
899void Device::CheckSuitability(bool requires_swapchain) const { 918void Device::CheckSuitability(bool requires_swapchain) const {
900 std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; 919 std::vector<const char*> required_extensions =
901 bool has_swapchain = false; 920 ExtensionsRequiredForInstanceVersion(instance_version);
902 for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) { 921 std::vector<const char*> available_extensions;
903 const std::string_view name{property.extensionName}; 922
904 for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { 923 if (requires_swapchain) {
905 if (available_extensions[i]) { 924 required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
906 continue;
907 }
908 available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
909 }
910 has_swapchain = has_swapchain || name == VK_KHR_SWAPCHAIN_EXTENSION_NAME;
911 } 925 }
912 for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { 926
913 if (available_extensions[i]) { 927 auto extension_properties = physical.EnumerateDeviceExtensionProperties();
914 continue; 928
929 for (const VkExtensionProperties& property : extension_properties) {
930 available_extensions.push_back(property.extensionName);
931 }
932
933 bool has_all_required_extensions = true;
934 for (const char* requirement_name : required_extensions) {
935 const bool found =
936 std::ranges::any_of(available_extensions, [&](const char* extension_name) {
937 return std::strcmp(requirement_name, extension_name) == 0;
938 });
939
940 if (!found) {
941 LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name);
942 has_all_required_extensions = false;
915 } 943 }
916 LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
917 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
918 } 944 }
919 if (requires_swapchain && !has_swapchain) { 945
920 LOG_ERROR(Render_Vulkan, "Missing required extension: VK_KHR_swapchain"); 946 if (!has_all_required_extensions) {
921 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); 947 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
922 } 948 }
923 949
@@ -940,9 +966,8 @@ void Device::CheckSuitability(bool requires_swapchain) const {
940 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); 966 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
941 } 967 }
942 } 968 }
943 VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{}; 969 VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{};
944 demote.sType = 970 demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES;
945 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT;
946 demote.pNext = nullptr; 971 demote.pNext = nullptr;
947 972
948 VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{}; 973 VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{};
@@ -960,7 +985,7 @@ void Device::CheckSuitability(bool requires_swapchain) const {
960 physical.GetFeatures2KHR(features2); 985 physical.GetFeatures2KHR(features2);
961 986
962 const VkPhysicalDeviceFeatures& features{features2.features}; 987 const VkPhysicalDeviceFeatures& features{features2.features};
963 const std::array feature_report{ 988 std::vector feature_report{
964 std::make_pair(features.robustBufferAccess, "robustBufferAccess"), 989 std::make_pair(features.robustBufferAccess, "robustBufferAccess"),
965 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), 990 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
966 std::make_pair(features.imageCubeArray, "imageCubeArray"), 991 std::make_pair(features.imageCubeArray, "imageCubeArray"),
@@ -983,27 +1008,30 @@ void Device::CheckSuitability(bool requires_swapchain) const {
983 "shaderStorageImageWriteWithoutFormat"), 1008 "shaderStorageImageWriteWithoutFormat"),
984 std::make_pair(features.shaderClipDistance, "shaderClipDistance"), 1009 std::make_pair(features.shaderClipDistance, "shaderClipDistance"),
985 std::make_pair(features.shaderCullDistance, "shaderCullDistance"), 1010 std::make_pair(features.shaderCullDistance, "shaderCullDistance"),
986 std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
987 std::make_pair(variable_pointers.variablePointers, "variablePointers"), 1011 std::make_pair(variable_pointers.variablePointers, "variablePointers"),
988 std::make_pair(variable_pointers.variablePointersStorageBuffer, 1012 std::make_pair(variable_pointers.variablePointersStorageBuffer,
989 "variablePointersStorageBuffer"), 1013 "variablePointersStorageBuffer"),
990 std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"), 1014 std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"),
991 std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"), 1015 std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"),
992 std::make_pair(robustness2.nullDescriptor, "nullDescriptor"), 1016 std::make_pair(robustness2.nullDescriptor, "nullDescriptor"),
1017 std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
993 }; 1018 };
1019
1020 bool has_all_required_features = true;
994 for (const auto& [is_supported, name] : feature_report) { 1021 for (const auto& [is_supported, name] : feature_report) {
995 if (is_supported) { 1022 if (!is_supported) {
996 continue; 1023 LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
1024 has_all_required_features = false;
997 } 1025 }
998 LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); 1026 }
1027
1028 if (!has_all_required_features) {
999 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); 1029 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
1000 } 1030 }
1001} 1031}
1002 1032
1003std::vector<const char*> Device::LoadExtensions(bool requires_surface) { 1033std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
1004 std::vector<const char*> extensions; 1034 std::vector<const char*> extensions = ExtensionsRequiredForInstanceVersion(instance_version);
1005 extensions.reserve(8 + REQUIRED_EXTENSIONS.size());
1006 extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
1007 if (requires_surface) { 1035 if (requires_surface) {
1008 extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 1036 extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
1009 } 1037 }
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index d7cc6c593..c85fbba77 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -211,11 +211,6 @@ public:
211 return khr_uniform_buffer_standard_layout; 211 return khr_uniform_buffer_standard_layout;
212 } 212 }
213 213
214 /// Returns true if the device supports VK_KHR_spirv_1_4.
215 bool IsKhrSpirv1_4Supported() const {
216 return khr_spirv_1_4;
217 }
218
219 /// Returns true if the device supports VK_KHR_push_descriptor. 214 /// Returns true if the device supports VK_KHR_push_descriptor.
220 bool IsKhrPushDescriptorSupported() const { 215 bool IsKhrPushDescriptorSupported() const {
221 return khr_push_descriptor; 216 return khr_push_descriptor;
@@ -316,6 +311,17 @@ public:
316 return ext_shader_atomic_int64; 311 return ext_shader_atomic_int64;
317 } 312 }
318 313
314 /// Returns the minimum supported version of SPIR-V.
315 u32 SupportedSpirvVersion() const {
316 if (instance_version >= VK_API_VERSION_1_3) {
317 return 0x00010600U;
318 }
319 if (khr_spirv_1_4) {
320 return 0x00010400U;
321 }
322 return 0x00010000U;
323 }
324
319 /// Returns true when a known debugging tool is attached. 325 /// Returns true when a known debugging tool is attached.
320 bool HasDebuggingToolAttached() const { 326 bool HasDebuggingToolAttached() const {
321 return has_renderdoc || has_nsight_graphics; 327 return has_renderdoc || has_nsight_graphics;
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp
index a082e3059..35e073e16 100644
--- a/src/video_core/vulkan_common/vulkan_instance.cpp
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -14,13 +14,15 @@
14#include "video_core/vulkan_common/vulkan_wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16// Include these late to avoid polluting previous headers 16// Include these late to avoid polluting previous headers
17#ifdef _WIN32 17#if defined(_WIN32)
18#include <windows.h> 18#include <windows.h>
19// ensure include order 19// ensure include order
20#include <vulkan/vulkan_win32.h> 20#include <vulkan/vulkan_win32.h>
21#endif 21#elif defined(__APPLE__)
22 22#include <vulkan/vulkan_macos.h>
23#if !defined(_WIN32) && !defined(__APPLE__) 23#elif defined(__ANDROID__)
24#include <vulkan/vulkan_android.h>
25#else
24#include <X11/Xlib.h> 26#include <X11/Xlib.h>
25#include <vulkan/vulkan_wayland.h> 27#include <vulkan/vulkan_wayland.h>
26#include <vulkan/vulkan_xlib.h> 28#include <vulkan/vulkan_xlib.h>
@@ -39,8 +41,15 @@ namespace {
39 case Core::Frontend::WindowSystemType::Windows: 41 case Core::Frontend::WindowSystemType::Windows:
40 extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); 42 extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
41 break; 43 break;
42#endif 44#elif defined(__APPLE__)
43#if !defined(_WIN32) && !defined(__APPLE__) 45 case Core::Frontend::WindowSystemType::Cocoa:
46 extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
47 break;
48#elif defined(__ANDROID__)
49 case Core::Frontend::WindowSystemType::Android:
50 extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
51 break;
52#else
44 case Core::Frontend::WindowSystemType::X11: 53 case Core::Frontend::WindowSystemType::X11:
45 extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); 54 extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
46 break; 55 break;
@@ -59,6 +68,10 @@ namespace {
59 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); 68 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
60 } 69 }
61 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); 70 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
71
72#ifdef __APPLE__
73 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
74#endif
62 return extensions; 75 return extensions;
63} 76}
64 77
@@ -140,7 +153,7 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
140 } 153 }
141 vk::Instance instance = 154 vk::Instance instance =
142 std::async([&] { 155 std::async([&] {
143 return vk::Instance::Create(required_version, layers, extensions, dld); 156 return vk::Instance::Create(available_version, layers, extensions, dld);
144 }).get(); 157 }).get();
145 if (!vk::Load(*instance, dld)) { 158 if (!vk::Load(*instance, dld)) {
146 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); 159 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp
index 69f9c494b..fa9bafa20 100644
--- a/src/video_core/vulkan_common/vulkan_surface.cpp
+++ b/src/video_core/vulkan_common/vulkan_surface.cpp
@@ -11,9 +11,11 @@
11#include <windows.h> 11#include <windows.h>
12// ensure include order 12// ensure include order
13#include <vulkan/vulkan_win32.h> 13#include <vulkan/vulkan_win32.h>
14#endif 14#elif defined(__APPLE__)
15 15#include <vulkan/vulkan_macos.h>
16#if !defined(_WIN32) && !defined(__APPLE__) 16#elif defined(__ANDROID__)
17#include <vulkan/vulkan_android.h>
18#else
17#include <X11/Xlib.h> 19#include <X11/Xlib.h>
18#include <vulkan/vulkan_wayland.h> 20#include <vulkan/vulkan_wayland.h>
19#include <vulkan/vulkan_xlib.h> 21#include <vulkan/vulkan_xlib.h>
@@ -40,8 +42,33 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
40 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); 42 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
41 } 43 }
42 } 44 }
43#endif 45#elif defined(__APPLE__)
44#if !defined(_WIN32) && !defined(__APPLE__) 46 if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
47 const VkMacOSSurfaceCreateInfoMVK mvk_ci{VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK,
48 nullptr, 0, window_info.render_surface};
49 const auto vkCreateMacOSSurfaceMVK = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>(
50 dld.vkGetInstanceProcAddr(*instance, "vkCreateMacOSSurfaceMVK"));
51 if (!vkCreateMacOSSurfaceMVK ||
52 vkCreateMacOSSurfaceMVK(*instance, &mvk_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
53 LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface");
54 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
55 }
56 }
57#elif defined(__ANDROID__)
58 if (window_info.type == Core::Frontend::WindowSystemType::Android) {
59 const VkAndroidSurfaceCreateInfoKHR android_ci{
60 VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0,
61 reinterpret_cast<ANativeWindow*>(window_info.render_surface)};
62 const auto vkCreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(
63 dld.vkGetInstanceProcAddr(*instance, "vkCreateAndroidSurfaceKHR"));
64 if (!vkCreateAndroidSurfaceKHR ||
65 vkCreateAndroidSurfaceKHR(*instance, &android_ci, nullptr, &unsafe_surface) !=
66 VK_SUCCESS) {
67 LOG_ERROR(Render_Vulkan, "Failed to initialize Android surface");
68 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
69 }
70 }
71#else
45 if (window_info.type == Core::Frontend::WindowSystemType::X11) { 72 if (window_info.type == Core::Frontend::WindowSystemType::X11) {
46 const VkXlibSurfaceCreateInfoKHR xlib_ci{ 73 const VkXlibSurfaceCreateInfoKHR xlib_ci{
47 VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, 74 VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@@ -70,6 +97,7 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
70 } 97 }
71 } 98 }
72#endif 99#endif
100
73 if (!unsafe_surface) { 101 if (!unsafe_surface) {
74 LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); 102 LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
75 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); 103 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index c934069dd..ccf1c50f4 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -267,6 +267,10 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() {
267 return Core::Frontend::WindowSystemType::X11; 267 return Core::Frontend::WindowSystemType::X11;
268 else if (platform_name == QStringLiteral("wayland")) 268 else if (platform_name == QStringLiteral("wayland"))
269 return Core::Frontend::WindowSystemType::Wayland; 269 return Core::Frontend::WindowSystemType::Wayland;
270 else if (platform_name == QStringLiteral("cocoa"))
271 return Core::Frontend::WindowSystemType::Cocoa;
272 else if (platform_name == QStringLiteral("android"))
273 return Core::Frontend::WindowSystemType::Android;
270 274
271 LOG_CRITICAL(Frontend, "Unknown Qt platform!"); 275 LOG_CRITICAL(Frontend, "Unknown Qt platform!");
272 return Core::Frontend::WindowSystemType::Windows; 276 return Core::Frontend::WindowSystemType::Windows;
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index f1385e972..20bc651f1 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -360,7 +360,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
360 360
361 vk::InstanceDispatch dld; 361 vk::InstanceDispatch dld;
362 const Common::DynamicLibrary library = OpenLibrary(); 362 const Common::DynamicLibrary library = OpenLibrary();
363 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0); 363 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1);
364 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); 364 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
365 365
366 vulkan_devices.clear(); 366 vulkan_devices.clear();
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp
index ccdcf10fa..563818362 100644
--- a/src/yuzu/startup_checks.cpp
+++ b/src/yuzu/startup_checks.cpp
@@ -27,7 +27,7 @@ void CheckVulkan() {
27 Vulkan::vk::InstanceDispatch dld; 27 Vulkan::vk::InstanceDispatch dld;
28 const Common::DynamicLibrary library = Vulkan::OpenLibrary(); 28 const Common::DynamicLibrary library = Vulkan::OpenLibrary();
29 const Vulkan::vk::Instance instance = 29 const Vulkan::vk::Instance instance =
30 Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); 30 Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);
31 31
32 } catch (const Vulkan::vk::Exception& exception) { 32 } catch (const Vulkan::vk::Exception& exception) {
33 fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what()); 33 fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what());
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
index 25948328c..0d580fe4f 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -51,11 +51,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
51 window_info.type = Core::Frontend::WindowSystemType::Windows; 51 window_info.type = Core::Frontend::WindowSystemType::Windows;
52 window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window); 52 window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
53 break; 53 break;
54#else
55 case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
56 LOG_CRITICAL(Frontend, "Window manager subsystem Windows not compiled");
57 std::exit(EXIT_FAILURE);
58 break;
59#endif 54#endif
60#ifdef SDL_VIDEO_DRIVER_X11 55#ifdef SDL_VIDEO_DRIVER_X11
61 case SDL_SYSWM_TYPE::SDL_SYSWM_X11: 56 case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
@@ -63,11 +58,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
63 window_info.display_connection = wm.info.x11.display; 58 window_info.display_connection = wm.info.x11.display;
64 window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window); 59 window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
65 break; 60 break;
66#else
67 case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
68 LOG_CRITICAL(Frontend, "Window manager subsystem X11 not compiled");
69 std::exit(EXIT_FAILURE);
70 break;
71#endif 61#endif
72#ifdef SDL_VIDEO_DRIVER_WAYLAND 62#ifdef SDL_VIDEO_DRIVER_WAYLAND
73 case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: 63 case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
@@ -75,14 +65,21 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
75 window_info.display_connection = wm.info.wl.display; 65 window_info.display_connection = wm.info.wl.display;
76 window_info.render_surface = wm.info.wl.surface; 66 window_info.render_surface = wm.info.wl.surface;
77 break; 67 break;
78#else 68#endif
79 case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: 69#ifdef SDL_VIDEO_DRIVER_COCOA
80 LOG_CRITICAL(Frontend, "Window manager subsystem Wayland not compiled"); 70 case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA:
81 std::exit(EXIT_FAILURE); 71 window_info.type = Core::Frontend::WindowSystemType::Cocoa;
72 window_info.render_surface = SDL_Metal_CreateView(render_window);
73 break;
74#endif
75#ifdef SDL_VIDEO_DRIVER_ANDROID
76 case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID:
77 window_info.type = Core::Frontend::WindowSystemType::Android;
78 window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window);
82 break; 79 break;
83#endif 80#endif
84 default: 81 default:
85 LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); 82 LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);
86 std::exit(EXIT_FAILURE); 83 std::exit(EXIT_FAILURE);
87 break; 84 break;
88 } 85 }