From 2956a33463df8fe97819df2b08d31834eaeed442 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 22 Nov 2022 19:14:46 -0500 Subject: [PATCH] Vulkan: update initialization Co-authored-by: bylaws --- .gitmodules | 2 +- externals/sirit | 2 +- src/core/frontend/emu_window.h | 2 + .../backend/spirv/emit_spirv.cpp | 13 +- .../backend/spirv/emit_spirv_control_flow.cpp | 2 +- .../backend/spirv/emit_spirv_warp.cpp | 35 +++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 4 +- .../vulkan_common/vulkan_device.cpp | 122 +++++++++++------- src/video_core/vulkan_common/vulkan_device.h | 16 ++- .../vulkan_common/vulkan_instance.cpp | 27 +++- .../vulkan_common/vulkan_surface.cpp | 38 +++++- src/yuzu/bootmanager.cpp | 4 + src/yuzu/configuration/configure_graphics.cpp | 2 +- src/yuzu/startup_checks.cpp | 2 +- .../emu_window/emu_window_sdl2_vk.cpp | 27 ++-- 15 files changed, 194 insertions(+), 104 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8a90f4d15c..8e98ee9cb3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,7 +27,7 @@ url = https://github.com/KhronosGroup/Vulkan-Headers.git [submodule "sirit"] path = externals/sirit - url = https://github.com/ReinUsesLisp/sirit + url = https://github.com/yuzu-emu/sirit [submodule "mbedtls"] path = externals/mbedtls url = https://github.com/yuzu-emu/mbedtls diff --git a/externals/sirit b/externals/sirit index aa292d5665..d7ad93a888 160000 --- a/externals/sirit +++ b/externals/sirit @@ -1 +1 @@ -Subproject commit aa292d56650bc28f2b2d75973fab2e61d0136f9c +Subproject commit d7ad93a88864bda94e282e95028f90b5784e4d20 diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index ac1906d5ef..95363b645e 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -17,6 +17,8 @@ enum class WindowSystemType { Windows, X11, Wayland, + Cocoa, + Android, }; /** diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 265ac9c858..0f86a80049 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 ctx.AddCapability(spv::Capability::SparseResidency); } if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) { - ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); - ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); + if (profile.supported_spirv < 0x00010600) { + ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); + } + ctx.AddCapability(spv::Capability::DemoteToHelperInvocation); } if (info.stores[IR::Attribute::ViewportIndex]) { ctx.AddCapability(spv::Capability::MultiViewport); @@ -426,12 +428,11 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles) && profile.support_vote) { - ctx.AddExtension("SPV_KHR_shader_ballot"); - ctx.AddCapability(spv::Capability::SubgroupBallotKHR); + ctx.AddCapability(spv::Capability::GroupNonUniformBallot); + ctx.AddCapability(spv::Capability::GroupNonUniformShuffle); if (!profile.warp_size_potentially_larger_than_guest) { // vote ops are only used when not taking the long path - ctx.AddExtension("SPV_KHR_subgroup_vote"); - ctx.AddCapability(spv::Capability::SubgroupVoteKHR); + ctx.AddCapability(spv::Capability::GroupNonUniformVote); } } 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 7ad0b08ac3..fb2c792c11 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&) { void EmitDemoteToHelperInvocation(EmitContext& ctx) { if (ctx.profile.support_demote_to_helper_invocation) { - ctx.OpDemoteToHelperInvocationEXT(); + ctx.OpDemoteToHelperInvocation(); } else { const Id kill_label{ctx.OpLabel()}; 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 7cbbbfaa68..2c90f23682 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 @@ namespace Shader::Backend::SPIRV { namespace { +Id SubgroupScope(EmitContext& ctx) { + return ctx.Const(static_cast(spv::Scope::Subgroup)); +} + Id GetThreadId(EmitContext& ctx) { return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id); } @@ -49,8 +53,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask } Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) { - return ctx.OpSelect(ctx.U32[1], in_range, - ctx.OpSubgroupReadInvocationKHR(ctx.U32[1], value, src_thread_id), value); + return ctx.OpSelect( + ctx.U32[1], in_range, + ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value); } Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) { @@ -71,40 +76,46 @@ Id EmitLaneId(EmitContext& ctx) { Id EmitVoteAll(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAllKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; return ctx.OpIEqual(ctx.U1, lhs, active_mask); } Id EmitVoteAny(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAnyKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value); } Id EmitVoteEqual(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)}; return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value), ctx.OpIEqual(ctx.U1, lhs, active_mask)); } Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { - const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)}; + const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)}; if (!ctx.profile.warp_size_potentially_larger_than_guest) { return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U); } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index d4b0a542ae..5995aeff0b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -53,7 +53,7 @@ using VideoCommon::FileEnvironment; using VideoCommon::GenericEnvironment; using VideoCommon::GraphicsEnvironment; -constexpr u32 CACHE_VERSION = 7; +constexpr u32 CACHE_VERSION = 8; template auto MakeSpan(Container& container) { @@ -277,7 +277,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device const auto& float_control{device.FloatControlProperties()}; const VkDriverIdKHR driver_id{device.GetDriverID()}; profile = Shader::Profile{ - .supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U, + .supported_spirv = device.SupportedSpirvVersion(), .unified_descriptor_binding = true, .support_descriptor_aliasing = true, .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 ddecfca132..a16a8275bb 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 { }; constexpr std::array REQUIRED_EXTENSIONS{ - VK_KHR_MAINTENANCE1_EXTENSION_NAME, - VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, - VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, - VK_KHR_16BIT_STORAGE_EXTENSION_NAME, - VK_KHR_8BIT_STORAGE_EXTENSION_NAME, - VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, - VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, - VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, - VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, - VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, - VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, - VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, - VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, + + // Core in 1.2, but required due to use of extension methods, + // and well-supported by drivers + VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, + VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, - VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME, #ifdef _WIN32 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, #endif @@ -99,6 +90,17 @@ constexpr std::array REQUIRED_EXTENSIONS{ #endif }; +constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{ + VK_KHR_8BIT_STORAGE_EXTENSION_NAME, + VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, + VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, + VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, +}; + +constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{ + VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME, +}; + template void SetNext(void**& next, T& data) { *next = &data; @@ -327,7 +329,8 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, - supported_extensions{GetSupportedExtensions(physical)}, + instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions( + physical)}, format_properties(GetFormatProperties(physical)) { CheckSuitability(surface != nullptr); SetupFamilies(surface); @@ -451,8 +454,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR }; SetNext(next, variable_pointers); - VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT, + VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, .pNext = nullptr, .shaderDemoteToHelperInvocation = true, }; @@ -896,28 +899,51 @@ std::string Device::GetDriverName() const { } } +static std::vector ExtensionsRequiredForInstanceVersion(u32 available_version) { + std::vector extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()}; + + if (available_version < VK_API_VERSION_1_2) { + extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(), + REQUIRED_EXTENSIONS_BEFORE_1_2.end()); + } + + if (available_version < VK_API_VERSION_1_3) { + extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(), + REQUIRED_EXTENSIONS_BEFORE_1_3.end()); + } + + return extensions; +} + void Device::CheckSuitability(bool requires_swapchain) const { - std::bitset available_extensions; - bool has_swapchain = false; - for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) { - const std::string_view name{property.extensionName}; - for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { - if (available_extensions[i]) { - continue; - } - available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; - } - has_swapchain = has_swapchain || name == VK_KHR_SWAPCHAIN_EXTENSION_NAME; + std::vector required_extensions = + ExtensionsRequiredForInstanceVersion(instance_version); + std::vector available_extensions; + + if (requires_swapchain) { + required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } - for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { - if (available_extensions[i]) { - continue; - } - LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); - throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); + + auto extension_properties = physical.EnumerateDeviceExtensionProperties(); + + for (const VkExtensionProperties& property : extension_properties) { + available_extensions.push_back(property.extensionName); } - if (requires_swapchain && !has_swapchain) { - LOG_ERROR(Render_Vulkan, "Missing required extension: VK_KHR_swapchain"); + + bool has_all_required_extensions = true; + for (const char* requirement_name : required_extensions) { + const bool found = + std::ranges::any_of(available_extensions, [&](const char* extension_name) { + return std::strcmp(requirement_name, extension_name) == 0; + }); + + if (!found) { + LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name); + has_all_required_extensions = false; + } + } + + if (!has_all_required_extensions) { throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); } @@ -940,9 +966,8 @@ void Device::CheckSuitability(bool requires_swapchain) const { throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); } } - VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{}; - demote.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT; + VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{}; + demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES; demote.pNext = nullptr; VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{}; @@ -960,7 +985,7 @@ void Device::CheckSuitability(bool requires_swapchain) const { physical.GetFeatures2KHR(features2); const VkPhysicalDeviceFeatures& features{features2.features}; - const std::array feature_report{ + std::vector feature_report{ std::make_pair(features.robustBufferAccess, "robustBufferAccess"), std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), std::make_pair(features.imageCubeArray, "imageCubeArray"), @@ -983,27 +1008,30 @@ void Device::CheckSuitability(bool requires_swapchain) const { "shaderStorageImageWriteWithoutFormat"), std::make_pair(features.shaderClipDistance, "shaderClipDistance"), std::make_pair(features.shaderCullDistance, "shaderCullDistance"), - std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"), std::make_pair(variable_pointers.variablePointers, "variablePointers"), std::make_pair(variable_pointers.variablePointersStorageBuffer, "variablePointersStorageBuffer"), std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"), std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"), std::make_pair(robustness2.nullDescriptor, "nullDescriptor"), + std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"), }; + + bool has_all_required_features = true; for (const auto& [is_supported, name] : feature_report) { - if (is_supported) { - continue; + if (!is_supported) { + LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); + has_all_required_features = false; } - LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); + } + + if (!has_all_required_features) { throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); } } std::vector Device::LoadExtensions(bool requires_surface) { - std::vector extensions; - extensions.reserve(8 + REQUIRED_EXTENSIONS.size()); - extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); + std::vector extensions = ExtensionsRequiredForInstanceVersion(instance_version); if (requires_surface) { extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index d7cc6c5938..c85fbba77f 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -211,11 +211,6 @@ public: return khr_uniform_buffer_standard_layout; } - /// Returns true if the device supports VK_KHR_spirv_1_4. - bool IsKhrSpirv1_4Supported() const { - return khr_spirv_1_4; - } - /// Returns true if the device supports VK_KHR_push_descriptor. bool IsKhrPushDescriptorSupported() const { return khr_push_descriptor; @@ -316,6 +311,17 @@ public: return ext_shader_atomic_int64; } + /// Returns the minimum supported version of SPIR-V. + u32 SupportedSpirvVersion() const { + if (instance_version >= VK_API_VERSION_1_3) { + return 0x00010600U; + } + if (khr_spirv_1_4) { + return 0x00010400U; + } + return 0x00010000U; + } + /// Returns true when a known debugging tool is attached. bool HasDebuggingToolAttached() const { 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 a082e30593..35e073e163 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -14,13 +14,15 @@ #include "video_core/vulkan_common/vulkan_wrapper.h" // Include these late to avoid polluting previous headers -#ifdef _WIN32 +#if defined(_WIN32) #include // ensure include order #include -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +#include +#elif defined(__ANDROID__) +#include +#else #include #include #include @@ -39,8 +41,15 @@ namespace { case Core::Frontend::WindowSystemType::Windows: extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); break; -#endif -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) + case Core::Frontend::WindowSystemType::Cocoa: + extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); + break; +#elif defined(__ANDROID__) + case Core::Frontend::WindowSystemType::Android: + extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); + break; +#else case Core::Frontend::WindowSystemType::X11: extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); break; @@ -59,6 +68,10 @@ namespace { extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + +#ifdef __APPLE__ + extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); +#endif return extensions; } @@ -140,7 +153,7 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD } vk::Instance instance = std::async([&] { - return vk::Instance::Create(required_version, layers, extensions, dld); + return vk::Instance::Create(available_version, layers, extensions, dld); }).get(); if (!vk::Load(*instance, dld)) { 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 69f9c494bd..fa9bafa206 100644 --- a/src/video_core/vulkan_common/vulkan_surface.cpp +++ b/src/video_core/vulkan_common/vulkan_surface.cpp @@ -11,9 +11,11 @@ #include // ensure include order #include -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +#include +#elif defined(__ANDROID__) +#include +#else #include #include #include @@ -40,8 +42,33 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance, throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } } -#endif -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) + if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) { + const VkMacOSSurfaceCreateInfoMVK mvk_ci{VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, + nullptr, 0, window_info.render_surface}; + const auto vkCreateMacOSSurfaceMVK = reinterpret_cast( + dld.vkGetInstanceProcAddr(*instance, "vkCreateMacOSSurfaceMVK")); + if (!vkCreateMacOSSurfaceMVK || + vkCreateMacOSSurfaceMVK(*instance, &mvk_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + } +#elif defined(__ANDROID__) + if (window_info.type == Core::Frontend::WindowSystemType::Android) { + const VkAndroidSurfaceCreateInfoKHR android_ci{ + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0, + reinterpret_cast(window_info.render_surface)}; + const auto vkCreateAndroidSurfaceKHR = reinterpret_cast( + dld.vkGetInstanceProcAddr(*instance, "vkCreateAndroidSurfaceKHR")); + if (!vkCreateAndroidSurfaceKHR || + vkCreateAndroidSurfaceKHR(*instance, &android_ci, nullptr, &unsafe_surface) != + VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Android surface"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + } +#else if (window_info.type == Core::Frontend::WindowSystemType::X11) { const VkXlibSurfaceCreateInfoKHR xlib_ci{ VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, @@ -70,6 +97,7 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance, } } #endif + if (!unsafe_surface) { LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d88efacd78..bbb3ee5538 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -265,6 +265,10 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() { return Core::Frontend::WindowSystemType::X11; else if (platform_name == QStringLiteral("wayland")) return Core::Frontend::WindowSystemType::Wayland; + else if (platform_name == QStringLiteral("cocoa")) + return Core::Frontend::WindowSystemType::Cocoa; + else if (platform_name == QStringLiteral("android")) + return Core::Frontend::WindowSystemType::Android; LOG_CRITICAL(Frontend, "Unknown Qt platform!"); return Core::Frontend::WindowSystemType::Windows; diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index bd69d04a65..45cbce4ac5 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -331,7 +331,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try { vk::InstanceDispatch dld; const Common::DynamicLibrary library = OpenLibrary(); - const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0); + const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1); const std::vector physical_devices = instance.EnumeratePhysicalDevices(); vulkan_devices.clear(); diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index 6a91212e20..612f29d2c9 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp @@ -24,7 +24,7 @@ void CheckVulkan() { Vulkan::vk::InstanceDispatch dld; const Common::DynamicLibrary library = Vulkan::OpenLibrary(); const Vulkan::vk::Instance instance = - Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); + Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1); } catch (const Vulkan::vk::Exception& exception) { std::fprintf(stderr, "Failed to initialize Vulkan: %s\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 25948328c1..0d580fe4fc 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 window_info.type = Core::Frontend::WindowSystemType::Windows; window_info.render_surface = reinterpret_cast(wm.info.win.window); break; -#else - case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS: - LOG_CRITICAL(Frontend, "Window manager subsystem Windows not compiled"); - std::exit(EXIT_FAILURE); - break; #endif #ifdef SDL_VIDEO_DRIVER_X11 case SDL_SYSWM_TYPE::SDL_SYSWM_X11: @@ -63,11 +58,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste window_info.display_connection = wm.info.x11.display; window_info.render_surface = reinterpret_cast(wm.info.x11.window); break; -#else - case SDL_SYSWM_TYPE::SDL_SYSWM_X11: - LOG_CRITICAL(Frontend, "Window manager subsystem X11 not compiled"); - std::exit(EXIT_FAILURE); - break; #endif #ifdef SDL_VIDEO_DRIVER_WAYLAND case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: @@ -75,14 +65,21 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste window_info.display_connection = wm.info.wl.display; window_info.render_surface = wm.info.wl.surface; break; -#else - case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: - LOG_CRITICAL(Frontend, "Window manager subsystem Wayland not compiled"); - std::exit(EXIT_FAILURE); +#endif +#ifdef SDL_VIDEO_DRIVER_COCOA + case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA: + window_info.type = Core::Frontend::WindowSystemType::Cocoa; + window_info.render_surface = SDL_Metal_CreateView(render_window); + break; +#endif +#ifdef SDL_VIDEO_DRIVER_ANDROID + case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID: + window_info.type = Core::Frontend::WindowSystemType::Android; + window_info.render_surface = reinterpret_cast(wm.info.android.window); break; #endif default: - LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); + LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem); std::exit(EXIT_FAILURE); break; }