diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index e14f4b955..d6cbc0ab2 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -21,13 +21,13 @@ jobs: strategy: matrix: config: - - {name: i686-pc-windows-msvc, os: windows-2022, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release} - - {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DUSE_DISCORD=ON, destDir: osx, buildType: RelWithDebInfo} - - {name: x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: linux, buildType: RelWithDebInfo} - - {name: x86_64-pc-windows-msvc, os: windows-2022, shell: cmd, arch: x64, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, buildType: Release} - - {name: x86_64-w64-mingw32, os: windows-2022, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: win, buildType: RelWithDebInfo} - - {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release} - - {name: libretro-x86_64-w64-mingw32, os: windows-2022, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -G Ninja, buildType: Release} + - { name: i686-pc-windows-msvc, os: windows-2022, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release } + - { name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DUSE_DISCORD=ON -DMOLTENVK_DYLIB=$MOLTENVK_DYLIB, destDir: osx, buildType: RelWithDebInfo, packagePath: artifact/flycast-apple-darwin.zip } + - { name: x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: linux, buildType: RelWithDebInfo } + - { name: x86_64-pc-windows-msvc, os: windows-2022, shell: cmd, arch: x64, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, buildType: Release } + - { name: x86_64-w64-mingw32, os: windows-2022, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: win, buildType: RelWithDebInfo, packagePath: artifact/flycast-x86_64-w64-mingw32.zip } + - { name: libretro-x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release } + - { name: libretro-x86_64-w64-mingw32, os: windows-2022, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -G Ninja, buildType: Release } steps: - name: Set up build environment (macOS) @@ -37,12 +37,19 @@ jobs: brew update || : brew install libao ldid pulseaudio brew uninstall --ignore-dependencies zstd - VULKAN_VER=1.4.341.1 && aria2c https://sdk.lunarg.com/sdk/download/$VULKAN_VER/mac/vulkan_sdk.zip?Human=true -o vulkan_sdk.zip - unzip -q vulkan_sdk.zip - ./vulkansdk-macOS-$VULKAN_VER.app/Contents/MacOS/vulkansdk-macOS-$VULKAN_VER --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install copy_only=1 - rm -f vulkan_sdk.zip - rm -rf ./vulkansdk-macOS-$VULKAN_VER.app - echo "VULKAN_SDK=$HOME/VulkanSDK/macOS" >> $GITHUB_ENV + + moltenvk_tag="v1.4.2" + moltenvk_root="$RUNNER_TEMP/MoltenVK-$moltenvk_tag" + rm -rf "$moltenvk_root" + mkdir -p "$moltenvk_root" + aria2c "https://github.com/KhronosGroup/MoltenVK/releases/download/$moltenvk_tag/MoltenVK-macos.tar" -d "$RUNNER_TEMP" -o "MoltenVK-macos-$moltenvk_tag.tar" + tar -xf "$RUNNER_TEMP/MoltenVK-macos-$moltenvk_tag.tar" -C "$moltenvk_root" + moltenvk_dylib="$(find "$moltenvk_root" -type f -path '*/macOS/*' -name libMoltenVK.dylib | head -n 1)" + if [ -z "$moltenvk_dylib" ]; then + echo "MoltenVK $moltenvk_tag was downloaded, but macOS libMoltenVK.dylib was not found." >&2 + exit 1 + fi + echo "MOLTENVK_DYLIB=$moltenvk_dylib" >> $GITHUB_ENV if: runner.os == 'macOS' - name: Set up build environment (Linux) @@ -146,25 +153,29 @@ jobs: rm artifact/bin/flycast if: matrix.config.name == 'x86_64-pc-linux-gnu' - - uses: actions/upload-artifact@v6 - with: - name: flycast-${{ matrix.config.name }} - path: | - artifact/bin - artifact/lib/libretro - - name: Package app (macos) run: | cd artifact/bin + codesign --verify --deep --strict --all-architectures --verbose=4 Flycast.app zip -rm flycast.app.zip Flycast.app + cp flycast.app.zip "../../${{ matrix.config.packagePath }}" if: matrix.config.name == 'apple-darwin' - name: Package app (windows) run: | powershell Compress-Archive artifact/bin/flycast.exe artifact/bin/flycast.zip rm artifact/bin/flycast.exe + cp artifact/bin/flycast.zip "${{ matrix.config.packagePath }}" if: matrix.config.name == 'x86_64-w64-mingw32' + - uses: actions/upload-artifact@v7 + with: + name: flycast-${{ matrix.config.name }} + archive: ${{ !matrix.config.packagePath }} + path: | + ${{ matrix.config.packagePath || 'artifact/bin' }} + ${{ !matrix.config.packagePath && 'artifact/lib/libretro' || '' }} + - name: Setup Rclone uses: AnimMouse/setup-rclone@v1 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 931d9cf3d..2affcc668 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ option(USE_HOST_SDL "Use host SDL library" ${USE_HOST_SDL_DEFAULT}) option(USE_HOST_LIBCHDR "Use host libchdr" OFF) option(USE_OPENMP "Use OpenMP if available" ON) option(USE_VULKAN "Build with Vulkan support" ON) +set(MOLTENVK_DYLIB "" CACHE FILEPATH "Path to macOS MoltenVK dylib for macOS Vulkan builds") option(USE_DX9 "Build with Direct3D 9 support" ON) option(USE_DX11 "Build with Direct3D 11 support" ON) option(LIBRETRO "Build libretro core" OFF) @@ -1416,9 +1417,15 @@ if(NOT LIBRETRO) ${IOSURFACE_LIBRARY} ${MULTITOUCH_SUPPORT_LIBRARY}) - add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy "$ENV{VULKAN_SDK}/lib/libMoltenVK.dylib" - $/../Frameworks/libvulkan.dylib) + if(USE_VULKAN) + set(MOLTENVK_DYLIB_PATH "${MOLTENVK_DYLIB}") + if(NOT MOLTENVK_DYLIB_PATH OR NOT EXISTS "${MOLTENVK_DYLIB_PATH}") + message(FATAL_ERROR "A macOS MoltenVK dylib is required for macOS Vulkan builds. Run shell/apple/generate_xcode_project.command to download the configured MoltenVK release, or pass -DMOLTENVK_DYLIB=/path/to/libMoltenVK.dylib.") + endif() + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${MOLTENVK_DYLIB_PATH}" + $/../Frameworks/libMoltenVK.dylib) + endif() endif() elseif(UNIX) if(NOT BUILD_TESTING) diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index 6ba481388..2cb703a9c 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -149,6 +149,8 @@ bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr; #if defined(__ANDROID__) && HOST_CPU == CPU_ARM64 vkGetInstanceProcAddr = loadVulkanDriver(); +#elif defined(__APPLE__) && defined(USE_SDL) + vkGetInstanceProcAddr = reinterpret_cast(SDL_Vulkan_GetVkGetInstanceProcAddr()); #else static vk::detail::DynamicLoader dl; vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index c897f985b..40df2ec1f 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -962,7 +962,7 @@ void sdl_window_create() die("error initializing SDL Video subsystem"); } #if defined(__APPLE__) && defined(USE_VULKAN) - SDL_Vulkan_LoadLibrary("libvulkan.dylib"); + SDL_Vulkan_LoadLibrary("@executable_path/../Frameworks/libMoltenVK.dylib"); #endif } sdlDeInit.initialized = true; diff --git a/shell/apple/generate_xcode_project.command b/shell/apple/generate_xcode_project.command index fca7817ef..db1b466ba 100755 --- a/shell/apple/generate_xcode_project.command +++ b/shell/apple/generate_xcode_project.command @@ -5,6 +5,12 @@ set -euo pipefail script_dir="$(cd "$(dirname "$0")" && pwd)" cd "$script_dir/../../" +MOLTENVK_TAG="v1.4.2-pre.973bb08" +MOLTENVK_ROOT="$PWD/build/deps/MoltenVK-${MOLTENVK_TAG}" + +moltenvk_root="" +moltenvk_dylib="" + install_homebrew() { /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" if [ -x /opt/homebrew/bin/brew ]; then @@ -18,6 +24,19 @@ install_homebrew() { fi } +ensure_homebrew() { + if command -v brew >/dev/null 2>&1; then + return + fi + + read -p $'\033[1mHomebrew is required to install missing build tools.\033[0m Type \033[1;32my\033[0m to install it now: ' b + if [ "$b" = "y" ]; then + install_homebrew + else + exit 1 + fi +} + init_submodules() { if [ -d .git ]; then if git rev-parse --verify HEAD >/dev/null 2>&1; then @@ -36,42 +55,50 @@ init_submodules() { fi } -install_vulkan_sdk() { - local installer="" - local install_root="" +find_molten_vk() { + local candidate="" - echo 'Downloading the latest Vulkan SDK from LunarG' - curl -fL "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan_sdk.zip?Human=true" -o vulkan_sdk.zip + if [ ! -d "$MOLTENVK_ROOT" ]; then + return 1 + fi - echo 'Extracting the Vulkan SDK installer' - unzip -q vulkan_sdk.zip + while IFS= read -r candidate; do + case "$candidate" in + */macOS/*|*/macos-*) ;; + *) continue ;; + esac - installer="$(find . -type f -path './vulkansdk-macOS-*.app/Contents/MacOS/*' -print | head -n 1)" - install_root="$HOME/VulkanSDK" + moltenvk_root="$MOLTENVK_ROOT" + moltenvk_dylib="$candidate" + return 0 + done < <(/usr/bin/find "$MOLTENVK_ROOT" -type f -name libMoltenVK.dylib) - echo "Installing Vulkan SDK into $install_root" - "$installer" --root "$install_root" --accept-licenses --default-answer --confirm-command install copy_only=1 - echo >> ~/.zprofile - echo "export VULKAN_SDK=$HOME/VulkanSDK/macOS" >> ~/.zprofile - echo "VULKAN_SDK is now set in .zprofile" - export VULKAN_SDK="$HOME/VulkanSDK/macOS" - - rm -f vulkan_sdk.zip - rm -rf ./vulkansdk-macOS-*.app + return 1 } -if ! command -v brew >/dev/null 2>&1; then - read -p $'\033[1mHomebrew is required.\033[0m Type \033[1;32my\033[0m to install it now: ' b - if [ "$b" = "y" ]; then - install_homebrew - else +download_molten_vk() { + local extract_tmp="$MOLTENVK_ROOT.tmp" + local archive="$PWD/build/deps/MoltenVK-macos-${MOLTENVK_TAG}.tar" + local url="https://github.com/vkedwardli/MoltenVK/releases/download/${MOLTENVK_TAG}/MoltenVK-macos.tar" + + mkdir -p "$(dirname "$archive")" + curl -fL "$url" -o "$archive" + rm -rf "$extract_tmp" + mkdir -p "$extract_tmp" + tar -xf "$archive" -C "$extract_tmp" + rm -rf "$MOLTENVK_ROOT" + mv "$extract_tmp" "$MOLTENVK_ROOT" + + if ! find_molten_vk; then + echo "MoltenVK ${MOLTENVK_TAG} was downloaded, but macOS libMoltenVK.dylib was not found." >&2 exit 1 fi -fi +} if ! command -v cmake >/dev/null 2>&1; then read -p $'\033[1mCMake is required.\033[0m Type \033[1;32my\033[0m to install it with Homebrew: ' c if [ "$c" = "y" ]; then + ensure_homebrew brew install cmake else exit 1 @@ -130,6 +157,7 @@ if [ -z "$xcode_app" ]; then read -p $'Or type \033[1;32my\033[0m to install Xcode '"$xcode_version"$' with Homebrew (you will be prompted to sign in with your Apple account): ' c fi if [ "$c" = "y" ]; then + ensure_homebrew brew install xcodes if [ "$xcode_version" = "latest" ]; then xcodes install --latest --no-superuser @@ -157,22 +185,6 @@ if [ ! -f core/deps/glslang/CMakeLists.txt ]; then fi fi -if [[ -n "${VULKAN_SDK:-}" && -d "${VULKAN_SDK}" ]]; then - echo "Using Vulkan SDK from $VULKAN_SDK" -elif [ -f "$HOME/VulkanSDK/setup-env.sh" ]; then - export VULKAN_SDK="$HOME/VulkanSDK/macOS" - echo "Using Vulkan SDK from $VULKAN_SDK" -else - echo $'\033[1mVulkan SDK is required.\033[0m VULKAN_SDK is not configured.' - read -p $'Type \033[1;32my\033[0m to install the latest Vulkan SDK: ' v - if [ "$v" = "y" ]; then - install_vulkan_sdk - echo "Using Vulkan SDK from $VULKAN_SDK" - else - echo 'Vulkan will be disabled' >&2 - fi -fi - echo "1) macOS ($(uname -m))" echo "2) iOS" read -p "Choose your target platform: " x @@ -187,11 +199,26 @@ if [ "${x:-1}" = "2" ]; then echo 'Building iOS xcodeproj for debugging' echo 'Remove CODE_SIGNING_ALLOWED=NO in Build Settings if you are using your Apple Developer Certificate for signing' else - option="-DCMAKE_OSX_ARCHITECTURES=$(uname -m) -DUSE_VULKAN=" - if [[ -n "${VULKAN_SDK:-}" ]]; then - option+="ON" + if find_molten_vk; then + echo "Using MoltenVK from $moltenvk_root" + use_vulkan="ON" else - option+="OFF" + echo $'\033[1mMoltenVK is required for Vulkan.\033[0m' + echo "Download URL: https://github.com/vkedwardli/MoltenVK/releases/download/${MOLTENVK_TAG}/MoltenVK-macos.tar" + read -p $'Type \033[1;32my\033[0m to download MoltenVK from the configured release URL: ' v + if [ "$v" = "y" ]; then + download_molten_vk + echo "Using MoltenVK from $moltenvk_root" + use_vulkan="ON" + else + echo 'Vulkan will be disabled' >&2 + use_vulkan="OFF" + fi + fi + + option="-DCMAKE_OSX_ARCHITECTURES=$(uname -m) -DUSE_VULKAN=$use_vulkan" + if [ "$use_vulkan" = "ON" ]; then + option+=" -DMOLTENVK_DYLIB=$moltenvk_dylib" fi lldbinitfolder="emulator-osx" echo 'Building macOS xcodeproj for debugging'