From 87022a4833fd693274275e1153d80d2e56fe0b11 Mon Sep 17 00:00:00 2001
From: Feng Chen <chen.feng@glority.cn>
Date: Thu, 17 Aug 2023 09:17:56 +0800
Subject: [PATCH] Add macos moltenvk bundle, Add copy moltevk dylib script

---
 CMakeLists.txt                                 |  4 +++-
 CMakeModules/DownloadExternals.cmake           | 18 ++++++++++++++++++
 .../vulkan_common/vulkan_instance.cpp          |  8 +++++---
 .../vulkan_common/vulkan_library.cpp           | 16 ++++++++++------
 src/yuzu/CMakeLists.txt                        | 12 ++++++++++++
 5 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index af9f394f15..7858d0450e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,7 +49,7 @@ option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
 
 option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
 
-cmake_dependent_option(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
+CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
 
 CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
 
@@ -63,6 +63,8 @@ option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
 
 CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
 
+CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
+
 set(DEFAULT_ENABLE_OPENSSL ON)
 if (ANDROID OR WIN32 OR APPLE)
     # - Windows defaults to the Schannel backend.
diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake
index 972f5ca741..a52148bd8f 100644
--- a/CMakeModules/DownloadExternals.cmake
+++ b/CMakeModules/DownloadExternals.cmake
@@ -36,3 +36,21 @@ endif()
 message(STATUS "Using bundled binaries at ${prefix}")
 set(${prefix_var} "${prefix}" PARENT_SCOPE)
 endfunction()
+
+function(download_moltenvk_external platform version)
+    set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
+    set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
+    if (NOT EXISTS ${MOLTENVK_DIR})
+        if (NOT EXISTS ${MOLTENVK_TAR})
+            file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar
+                ${MOLTENVK_TAR} SHOW_PROGRESS)
+        endif()
+
+        execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
+            WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
+    endif()
+
+    # Add the MoltenVK library path to the prefix so find_library can locate it.
+    list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
+    set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
+endfunction()
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp
index 72aedb8d8a..bc16145be5 100644
--- a/src/video_core/vulkan_common/vulkan_instance.cpp
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -41,9 +41,6 @@ namespace {
     bool enable_validation) {
     std::vector<const char*> extensions;
     extensions.reserve(6);
-#ifdef __APPLE__
-    extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
-#endif
     switch (window_type) {
     case Core::Frontend::WindowSystemType::Headless:
         break;
@@ -74,6 +71,11 @@ namespace {
     if (window_type != Core::Frontend::WindowSystemType::Headless) {
         extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
     }
+#ifdef __APPLE__
+    if (AreExtensionsSupported(dld, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME})) {
+        extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
+    }
+#endif
     if (enable_validation) {
         const bool debug_utils =
             AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp
index 47f6f2a036..0130f6a0d9 100644
--- a/src/video_core/vulkan_common/vulkan_library.cpp
+++ b/src/video_core/vulkan_common/vulkan_library.cpp
@@ -19,13 +19,17 @@ std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
 #else
     auto library = std::make_shared<Common::DynamicLibrary>();
 #ifdef __APPLE__
+    const auto libvulkan_filename =
+        Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.1.dylib";
+    const auto libmoltenvk_filename =
+        Common::FS::GetBundleDirectory() / "Contents/Frameworks/libMoltenVK.dylib";
+    const char* library_paths[] = {std::getenv("LIBVULKAN_PATH"), libvulkan_filename.c_str(),
+                                   libmoltenvk_filename.c_str()};
     // Check if a path to a specific Vulkan library has been specified.
-    char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
-    if (!libvulkan_env || !library->Open(libvulkan_env)) {
-        // Use the libvulkan.dylib from the application bundle.
-        const auto filename =
-            Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib";
-        void(library->Open(Common::FS::PathToUTF8String(filename).c_str()));
+    for (const auto& library_path : library_paths) {
+        if (library_path && library->Open(library_path)) {
+            break;
+        }
     }
 #else
     std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 2e4da696c0..8f86a15535 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -313,6 +313,18 @@ if (APPLE)
     target_sources(yuzu PRIVATE ${MACOSX_ICON})
     set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
     set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
+
+    if (NOT USE_SYSTEM_MOLTENVK)
+        set(MOLTENVK_PLATFORM "macOS")
+        set(MOLTENVK_VERSION "v1.2.5")
+        download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
+    endif()
+    find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
+    message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
+    set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks
+                                    XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
+    target_sources(yuzu PRIVATE ${MOLTENVK_LIBRARY})
+
 elseif(WIN32)
     # compile as a win32 gui application instead of a console application
     if (QT_VERSION VERSION_GREATER_EQUAL 6)