Skip to content

Fix back-face stencil packing masks, add two-sided API and GPU regres… #288

Fix back-face stencil packing masks, add two-sided API and GPU regres…

Fix back-face stencil packing masks, add two-sided API and GPU regres… #288

Workflow file for this run

name: CI
on:
push:
branches: [ "main", "master" ]
tags: [ "*" ]
pull_request:
branches: [ "main", "master" ]
workflow_dispatch:
jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Use the image's default Visual Studio generator (cl). The runner no
# longer ships the hardcoded "Visual Studio 17 2022" generator, and a bare
# Ninja generator picks up MinGW g++ which cannot link the MSVC deps.
- name: Windows
os: windows-latest
cmake_gen: ""
cmake_extra_args: ""
lib_tag: win
vdeps_args: ""
install_swiftshader: true
install_llvm: false
# Clang/LLVM must build AND link its own deps (lib/win_llvm). Mixing a
# clang-cl app with cl-built deps mismatches the MSVC STL ABI and aborts
# in debug std::sort ("invalid comparator") during device selection.
- name: Windows LLVM
os: windows-latest
cmake_gen: "-G Ninja"
cmake_extra_args: "-DCMAKE_C_COMPILER=clang-cl.exe -DCMAKE_CXX_COMPILER=clang-cl.exe -DVDEPS_USE_LLVM=ON"
lib_tag: win_llvm
vdeps_args: "--llvm"
install_swiftshader: true
install_llvm: true
- name: Linux
os: ubuntu-latest
cmake_gen: "-G Ninja"
# Installing Clang 21 as per user's environment
cmake_extra_args: "-DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21"
lib_tag: linux
vdeps_args: ""
install_swiftshader: false
install_llvm: false
- name: macOS
os: macos-14 # Apple Silicon (M1/M2)
cmake_gen: "-G Ninja"
# Explicitly using Homebrew Clang 17
cmake_extra_args: "-DCMAKE_C_COMPILER=$(brew --prefix llvm@17)/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix llvm@17)/bin/clang++"
lib_tag: mac
vdeps_args: ""
install_swiftshader: false
install_llvm: false
steps:
- name: Checkout
uses: actions/checkout@v4
with:
lfs: false
submodules: recursive
fetch-depth: 1
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install LLVM (Windows)
if: matrix.install_llvm
uses: KyleMayes/install-llvm-action@v2
with:
version: "21"
- name: Install Dependencies (Linux)
if: runner.os == 'Linux'
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt-get install -y ninja-build libx11-dev libxrandr-dev libxi-dev libxcursor-dev libxinerama-dev mesa-vulkan-drivers libc++-21-dev libc++abi-21-dev ccache
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-21 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 100
sudo update-alternatives --set clang /usr/bin/clang-21
sudo update-alternatives --set clang++ /usr/bin/clang++-21
- name: Install Dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install ninja llvm@17 ccache
- name: Configure ccache
if: runner.os != 'Windows'
run: |
echo "CCACHE_DIR=$HOME/.ccache" >> $GITHUB_ENV
echo "CCACHE_MAXSIZE=5G" >> $GITHUB_ENV
echo "CMAKE_C_COMPILER_LAUNCHER=ccache" >> $GITHUB_ENV
echo "CMAKE_CXX_COMPILER_LAUNCHER=ccache" >> $GITHUB_ENV
- name: Capture submodule status
run: git submodule status --recursive > .submodules.status
- name: Cache dependencies
id: deps-cache
uses: actions/cache@v4
with:
path: |
lib
tools
# Key on lib_tag, not runner.os: the Windows (cl) and Windows LLVM
# (clang-cl) jobs produce different ABIs and must not share a cache.
key: ${{ matrix.lib_tag }}-vdeps-${{ hashFiles('vdeps.py', 'vdeps.toml', 'vdeps/CMakeLists.txt', 'CMakeLists.txt', '.gitmodules', '.submodules.status') }}
restore-keys: |
${{ matrix.lib_tag }}-vdeps-
- name: Cache ccache (Linux/macOS)
if: runner.os != 'Windows'
uses: actions/cache@v4
with:
path: ~/.ccache
key: ${{ runner.os }}-ccache-${{ hashFiles('vdeps.py', 'vdeps.toml', 'vdeps/CMakeLists.txt', 'CMakeLists.txt', '.gitmodules', '.submodules.status') }}
restore-keys: |
${{ runner.os }}-ccache-
- name: Build Dependencies
if: steps.deps-cache.outputs.cache-hit != 'true'
run: python vdeps.py ${{ matrix.vdeps_args }}
# Temporarily disabled LFS due to budget exhaustion
# - name: Create LFS file list
# run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
# - name: Restore LFS cache
# uses: actions/cache@v4
# id: lfs-cache
# with:
# path: .git/lfs
# key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}
# - name: Git LFS Pull
# if: steps.lfs-cache.outputs.cache-hit != 'true'
# run: git lfs pull
- name: Setup Vulkan SDK
uses: jakoch/install-vulkan-sdk-action@v1
with:
vulkan_version: 1.4.335.0
cache: true
install_swiftshader: ${{ matrix.install_swiftshader }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Configure CMake
run: |
cmake -S . -B build ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build --config Debug
- name: Configure Environment (Windows)
if: runner.os == 'Windows'
run: |
$swiftShaderDll = "C:\hostedtoolcache\windows\swiftshader\5.0.0.1\x64\vk_swiftshader.dll"
$targetDir = if (Test-Path "build\Debug") { "build\Debug" } else { "build" }
$targetDll = Join-Path $targetDir "vulkan-1.dll"
if (Test-Path $swiftShaderDll) {
Copy-Item $swiftShaderDll $targetDll -Force
echo "Copied SwiftShader to $targetDll to bypass elevated loader restrictions."
} else {
echo "::error::SwiftShader DLL not found at $swiftShaderDll"
}
# NOTE: These MVK_CONFIG settings are REQUIRED for local testing on macOS.
# Without them, Graphics.Benchmark_2000DrawCalls crashes with SIGTRAP due to
# a race condition in MoltenVK's command submission. The bug manifests as crashes
# when running after other tests (cumulative state), but passes when run alone.
# To run tests locally, set these env vars:
# export MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0
# export MVK_CONFIG_USE_MTLHEAP=0
# export MVK_CONFIG_LOG_LEVEL=3
# export MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=1
# export MVK_CONFIG_USE_COMMAND_POOLING=0
- name: Configure Environment (macOS)
if: runner.os == 'macOS'
run: |
# Disable Metal Argument Buffers to prevent crash on Paravirt GPU
echo "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0" >> $GITHUB_ENV
# Disable MTLHeap usage to prevent OOM on Paravirt GPU
echo "MVK_CONFIG_USE_MTLHEAP=0" >> $GITHUB_ENV
# Enable debug logging for MoltenVK
echo "MVK_CONFIG_LOG_LEVEL=3" >> $GITHUB_ENV
# Fix for Paravirt stability/OOM
echo "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=1" >> $GITHUB_ENV
echo "MVK_CONFIG_USE_COMMAND_POOLING=0" >> $GITHUB_ENV
# Check common locations for MoltenVK ICD
if [ -f "$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json" ]; then
echo "Found MoltenVK at share/..."
echo "VK_ICD_FILENAMES=$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json" >> $GITHUB_ENV
elif [ -f "$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json" ]; then
echo "Found MoltenVK at etc/..."
echo "VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json" >> $GITHUB_ENV
else
echo "::warning::MoltenVK ICD not found in standard locations."
# Fallback to verify directory contents
ls -R "$VULKAN_SDK" || true
fi
# Also set VK_LAYER_PATH just in case
if [ -d "$VULKAN_SDK/share/vulkan/explicit_layer.d" ]; then
echo "VK_LAYER_PATH=$VULKAN_SDK/share/vulkan/explicit_layer.d" >> $GITHUB_ENV
elif [ -d "$VULKAN_SDK/etc/vulkan/explicit_layer.d" ]; then
echo "VK_LAYER_PATH=$VULKAN_SDK/etc/vulkan/explicit_layer.d" >> $GITHUB_ENV
fi
- name: Test
run: ctest --test-dir build -C Debug --verbose
# ==========================================================================
# Sanitizers - runs ASan/TSan/UBSan variants alongside the main build.
# Split into its own job so a sanitizer regression doesn't fail the main
# build (fail-fast: false already covers concurrent matrix entries, but
# keeping it separate avoids polluting the primary lib cache and lets each
# variant use an isolated cache key).
# ==========================================================================
sanitizers:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux ASan + UBSan combined: UBSan is unbounded and cheap to add
# alongside ASan (same instrumentation passes), and the pair is the
# closest stand-in for the "best-effort safe build" most teams run.
- name: Linux Address+UBSan
os: ubuntu-latest
cmake_gen: "-G Ninja"
cmake_extra_args: "-DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21 -DVDEPS_SANITIZE=address,undefined"
lib_tag: linux_address_undefined
vdeps_args: "--sanitize address,undefined"
sanitizer: address,undefined
# macOS Address only: macOS Clang also supports thread/memory
# but Apple's Clang is frozen on LLVM 17, which has a known
# TSan false positive on std::once_flag; keep this matrix entry
# narrow.
- name: macOS Address
os: macos-14
cmake_gen: "-G Ninja"
cmake_extra_args: "-DCMAKE_C_COMPILER=$(brew --prefix llvm@17)/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix llvm@17)/bin/clang++ -DVDEPS_SANITIZE=address"
lib_tag: mac_address
vdeps_args: "--sanitize address"
sanitizer: address
# Windows LLVM Address: clang-cl + ASan. Verified end-to-end locally
# (ctest 434/434 pass in ~6 min); the previous CI runs hit
# 0xc0000135 (DLL not found) because the CMake-side PATH injection
# was lost during an earlier git reset. The PATH is now restored so
# the ASan runtime DLL is discoverable.
- name: Windows LLVM Address
os: windows-latest
cmake_gen: "-G Ninja"
cmake_extra_args: "-DCMAKE_C_COMPILER=clang-cl.exe -DCMAKE_CXX_COMPILER=clang-cl.exe -DVDEPS_USE_LLVM=ON -DVDEPS_SANITIZE=address"
lib_tag: win_llvm_address
vdeps_args: "--llvm --sanitize address"
install_llvm: true
install_swiftshader: true
sanitizer: address
steps:
- name: Checkout
uses: actions/checkout@v4
with:
lfs: false
submodules: recursive
fetch-depth: 1
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install LLVM (Windows)
if: matrix.install_llvm
uses: KyleMayes/install-llvm-action@v2
with:
version: "21"
- name: Install Dependencies (Linux)
if: runner.os == 'Linux'
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt-get install -y ninja-build libx11-dev libxrandr-dev libxi-dev libxcursor-dev libxinerama-dev mesa-vulkan-drivers libc++-21-dev libc++abi-21-dev ccache
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-21 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 100
sudo update-alternatives --set clang /usr/bin/clang-21
sudo update-alternatives --set clang++ /usr/bin/clang++-21
- name: Install Dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install ninja llvm@17 ccache
- name: Capture submodule status
run: git submodule status --recursive > .submodules.status
- name: Cache dependencies
id: deps-cache
uses: actions/cache@v4
with:
path: |
lib
tools
# Sanitizer builds produce different ABIs (add tag suffix to lib_tag)
# so they need their own cache; the per-sanitize tag is in matrix.lib_tag.
key: ${{ matrix.lib_tag }}-vdeps-${{ hashFiles('vdeps.py', 'vdeps.toml', 'vdeps/CMakeLists.txt', 'CMakeLists.txt', '.gitmodules', '.submodules.status') }}
restore-keys: |
${{ matrix.lib_tag }}-vdeps-
# macOS Homebrew installs Clang to /opt/homebrew on Apple Silicon; vdeps
# hardcodes ``clang``/``clang++`` for the Unix path, so we must put the
# same Homebrew Clang (17) the consumer uses at the front of PATH so the
# ASan runtime ABI matches. Apple's system clang is older than Homebrew
# llvm@17, and a dep built with one and a consumer with the other fails
# to link __asan_version_mismatch_check_apple_clang_1500.
- name: Pin Homebrew Clang (macOS)
if: runner.os == 'macOS'
run: |
echo "$(brew --prefix llvm@17)/bin" >> "$GITHUB_PATH"
- name: Build Dependencies
if: steps.deps-cache.outputs.cache-hit != 'true'
run: python vdeps.py ${{ matrix.vdeps_args }}
- name: Setup Vulkan SDK
uses: jakoch/install-vulkan-sdk-action@v1
with:
vulkan_version: 1.4.335.0
cache: true
install_swiftshader: ${{ matrix.install_swiftshader }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Configure CMake
run: |
cmake -S . -B build ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build --config Debug
# macOS MoltenVK stability flags are REQUIRED locally; see main `build`
# job comment for the full rationale.
- name: Configure Environment (macOS)
if: runner.os == 'macOS'
run: |
echo "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0" >> $GITHUB_ENV
echo "MVK_CONFIG_USE_MTLHEAP=0" >> $GITHUB_ENV
echo "MVK_CONFIG_LOG_LEVEL=3" >> $GITHUB_ENV
echo "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=1" >> $GITHUB_ENV
echo "MVK_CONFIG_USE_COMMAND_POOLING=0" >> $GITHUB_ENV
if [ -f "$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json" ]; then
echo "VK_ICD_FILENAMES=$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json" >> $GITHUB_ENV
elif [ -f "$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json" ]; then
echo "VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json" >> $GITHUB_ENV
fi
# Linux/Mac: the test executable relies on -fsanitize=... only; no DLL
# discovery needed (everything is statically linked). Sanitizer runs add
# 5-10x overhead so we bump --timeout to 2400s (40 min); matches the
# worst observed run on macOS Address. -V + --output-on-failure keeps the
# runner's log useful when ctest is killed at the timeout boundary.
- name: Test
if: runner.os != 'Windows'
run: ctest --test-dir build -C Debug --timeout 2400 -V --output-on-failure
# Windows: the consumer project's CMakeLists.txt wires the ASan runtime
# DLL into the test's ENVIRONMENT at configure time (resolving clang's
# resource dir via clang-cl -print-resource-dir). ctest picks that up
# automatically. We do ctest directly rather than via CMake for parity
# with the local expected invocation.
- name: Configure Environment (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$swiftShaderDll = "C:\hostedtoolcache\windows\swiftshader\5.0.0.1\x64\vk_swiftshader.dll"
$targetDir = if (Test-Path "build\Debug") { "build\Debug" } else { "build" }
$targetDll = Join-Path $targetDir "vulkan-1.dll"
if (Test-Path $swiftShaderDll) {
Copy-Item $swiftShaderDll $targetDll -Force
echo "Copied SwiftShader to $targetDll to bypass elevated loader restrictions."
} else {
echo "::error::SwiftShader DLL not found at $swiftShaderDll"
exit 1
}
- name: Test (Windows)
if: runner.os == 'Windows'
# ASan instrumentation on Windows extends the suite; locally verified
# 434/434 passes in ~6 min. CI runners are slower so we give 40 min.
run: ctest --test-dir build -C Debug --timeout 2400 -V --output-on-failure
# ==========================================================================
# Release Job - runs on tag pushes only
# ==========================================================================
#
# IMPORTANT NOTES FOR FUTURE MAINTAINERS:
#
# 1. SHELL COMPATIBILITY: Steps that run on ALL platforms (no `if:`) must
# only use commands that work in both bash and pwsh. Windows default
# shell is pwsh, Linux/macOS is bash. Use explicit `shell: pwsh` or
# `shell: bash` when mixing. Do NOT use PowerShell cmdlets (New-Item,
# Copy-Item, Get-ChildItem, Test-Path, Write-Host) without `shell: pwsh`.
# Do NOT use bash syntax (mkdir -p, [ -d ], 2>/dev/null, ls -la)
# without an `if:` guard or `shell: bash`.
#
# 2. NINJA vs VISUAL STUDIO OUTPUT LAYOUT: VS (multi-config) puts build
# outputs in <build_dir>/<Config>/ subdirs (e.g. build_mt_release/
# RelWithDebInfo/vrhi.lib). Ninja (single-config) puts them directly
# in <build_dir>/ (e.g. build_mt_release/vrhi.lib). Any step that
# copies build outputs MUST handle both layouts. Use Get-ChildItem
# -Recurse to find files regardless of subdir structure. See also
# test/run_test_package.cmake which has the same try-both logic.
#
# 3. PLATFORM LIB SUBDIRS: vdeps.py outputs libraries to directories
# like lib/win_release, lib/win_llvm_debug, lib/win_md_release, etc.
# The platform prefix MUST match between vdeps.py, CMakeLists.txt,
# and this workflow. Use matrix.platform_lib_subdir (not hardcoded
# "win") to construct lib paths. Windows LLVM uses "win_llvm", not "win".
#
# 4. RELWITHDEBINFO vs RELEASE: On Windows, "release" builds use CMake
# config type RelWithDebInfo (for PDB generation). But vdeps.py names
# output dirs with "release" (e.g. lib/win_release). CMakeLists.txt
# maps RelWithDebInfo -> "release" via a $<IF:> generator expression.
# Do NOT assume $<LOWER_CASE:$<CONFIG>> produces "release" -- it
# produces "relwithdebinfo" which doesn't match vdeps output dirs.
#
# 5. VDEPS_USE_LLVM: Must be passed to ALL Windows CMake configure steps
# so CMakeLists.txt can set VRHI_LIB_PLATFORM and VRHI_PLATFORM_TAG
# to "win_llvm" instead of "win". Without this, the linker looks for
# dependency libs in lib/win_* instead of lib/win_llvm_*.
#
release:
name: Release
if: startsWith(github.ref, 'refs/tags/')
needs: build
runs-on: ${{ matrix.os }}
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- name: Windows
os: windows-latest
# Default Visual Studio generator (cl); Ninja here would pick MinGW g++.
cmake_gen: ""
cmake_extra_args: ""
zip_name: vrhi-${{ github.ref_name }}-windows-x64
platform_lib_subdir: "win"
is_windows: true
install_llvm: false
- name: Windows LLVM
os: windows-latest
cmake_gen: "-G Ninja"
cmake_extra_args: "-DCMAKE_C_COMPILER=clang-cl.exe -DCMAKE_CXX_COMPILER=clang-cl.exe"
zip_name: vrhi-${{ github.ref_name }}-windows-llvm-x64
# MUST be "win_llvm" not "win" -- vdeps.py outputs to lib/win_llvm_*
platform_lib_subdir: "win_llvm"
is_windows: true
install_llvm: true
- name: Linux
os: ubuntu-latest
cmake_gen: "-G Ninja"
cmake_extra_args: "-DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21"
zip_name: vrhi-${{ github.ref_name }}-linux-x64
platform_lib_subdir: "linux"
is_windows: false
install_llvm: false
- name: macOS
os: macos-14
cmake_gen: "-G Ninja"
cmake_extra_args: "-DCMAKE_C_COMPILER=$(brew --prefix llvm@17)/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix llvm@17)/bin/clang++"
zip_name: vrhi-${{ github.ref_name }}-macos-arm64
platform_lib_subdir: "mac"
is_windows: false
install_llvm: false
steps:
- name: Checkout
uses: actions/checkout@v4
with:
lfs: false
submodules: recursive
fetch-depth: 1
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install LLVM (Windows)
if: matrix.install_llvm
uses: KyleMayes/install-llvm-action@v2
with:
version: "21"
- name: Install Dependencies (Linux)
if: runner.os == 'Linux'
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt-get install -y ninja-build libx11-dev libxrandr-dev libxi-dev libxcursor-dev libxinerama-dev mesa-vulkan-drivers libc++-21-dev libc++abi-21-dev zip ccache
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-21 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-21 100
sudo update-alternatives --set clang /usr/bin/clang-21
sudo update-alternatives --set clang++ /usr/bin/clang++-21
- name: Install Dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install ninja llvm@17 zip ccache
- name: Configure ccache
if: runner.os != 'Windows'
run: |
echo "CCACHE_DIR=$HOME/.ccache" >> $GITHUB_ENV
echo "CCACHE_MAXSIZE=5G" >> $GITHUB_ENV
echo "CMAKE_C_COMPILER_LAUNCHER=ccache" >> $GITHUB_ENV
echo "CMAKE_CXX_COMPILER_LAUNCHER=ccache" >> $GITHUB_ENV
- name: Capture submodule status
run: git submodule status --recursive > .submodules.status
# =========================================================================
# Build Dependencies using vdeps CMake (Windows: MT + MD in one pass)
# =========================================================================
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
lib
tools
# Key on platform_lib_subdir so win / win_llvm variants don't share a cache.
key: ${{ matrix.platform_lib_subdir }}-vdeps-${{ hashFiles('vdeps.py', 'vdeps.toml', 'vdeps/CMakeLists.txt', 'CMakeLists.txt', '.gitmodules', '.submodules.status') }}
restore-keys: |
${{ matrix.platform_lib_subdir }}-vdeps-
- name: Configure Dependencies (Windows)
if: matrix.is_windows
shell: pwsh
run: |
cmake -S vdeps -B build_deps ${{ matrix.cmake_gen }} -DVDEPS_STATIC_RUNTIME=ON -DVDEPS_DYNAMIC_RUNTIME=ON -DVDEPS_USE_LLVM=${{ matrix.install_llvm }}
- name: Configure Dependencies (Non-Windows)
if: '!matrix.is_windows'
run: |
cmake -S vdeps -B build_deps -G Ninja ${{ matrix.cmake_extra_args }}
- name: Build Dependencies
run: cmake --build build_deps --target vdeps_all
- name: Cache ccache (Linux/macOS)
if: runner.os != 'Windows'
uses: actions/cache@v4
with:
path: ~/.ccache
key: ${{ runner.os }}-ccache-${{ hashFiles('vdeps.py', 'vdeps.toml', 'vdeps/CMakeLists.txt', 'CMakeLists.txt', '.gitmodules', '.submodules.status') }}
restore-keys: |
${{ runner.os }}-ccache-
- name: Setup Vulkan SDK
uses: jakoch/install-vulkan-sdk-action@v1
with:
vulkan_version: 1.4.335.0
cache: true
install_swiftshader: ${{ matrix.is_windows }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# =========================================================================
# Windows: Build all four vrhi variants (MT Debug/Release, MD Debug/Release)
# NOTE: -DVDEPS_USE_LLVM is required on every configure step so
# CMakeLists.txt resolves lib paths to win_llvm_* for LLVM builds.
# =========================================================================
- name: Configure CMake (MT Debug)
if: matrix.is_windows
run: |
cmake -S . -B build_mt_debug ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=Debug -DVDEPS_DYNAMIC_RUNTIME=OFF -DVDEPS_USE_LLVM=${{ matrix.install_llvm }}
- name: Build (MT Debug)
if: matrix.is_windows
run: cmake --build build_mt_debug --config Debug
- name: Configure CMake (MT Release)
if: matrix.is_windows
run: |
cmake -S . -B build_mt_release ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVDEPS_DYNAMIC_RUNTIME=OFF -DVDEPS_USE_LLVM=${{ matrix.install_llvm }}
- name: Build (MT Release)
if: matrix.is_windows
run: cmake --build build_mt_release --config RelWithDebInfo
- name: Configure CMake (MD Debug)
if: matrix.is_windows
run: |
cmake -S . -B build_md_debug ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=Debug -DVDEPS_DYNAMIC_RUNTIME=ON -DVDEPS_USE_LLVM=${{ matrix.install_llvm }}
- name: Build (MD Debug)
if: matrix.is_windows
run: cmake --build build_md_debug --config Debug
- name: Configure CMake (MD Release)
if: matrix.is_windows
run: |
cmake -S . -B build_md_release ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVDEPS_DYNAMIC_RUNTIME=ON -DVDEPS_USE_LLVM=${{ matrix.install_llvm }}
- name: Build (MD Release)
if: matrix.is_windows
run: cmake --build build_md_release --config RelWithDebInfo
# =========================================================================
# Non-Windows: Build Debug and Release
# =========================================================================
- name: Configure CMake (Release)
if: '!matrix.is_windows'
run: |
cmake -S . -B build_release ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=Release
- name: Build (Release)
if: '!matrix.is_windows'
run: cmake --build build_release --config Release
- name: Configure CMake (Debug)
if: '!matrix.is_windows'
run: |
cmake -S . -B build_debug ${{ matrix.cmake_gen }} ${{ matrix.cmake_extra_args }} -DCMAKE_BUILD_TYPE=Debug
- name: Build (Debug)
if: '!matrix.is_windows'
run: cmake --build build_debug --config Debug
# =========================================================================
# Package Creation
# =========================================================================
- name: Create Package Directory (Windows)
if: matrix.is_windows
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path package/lib
# NOTE: vrhi lib names are: vrhi.lib (MT release), vrhid.lib (MT debug),
# vrhi_md.lib (MD release), vrhi_mdd.lib (MD debug). No underscore
# before the trailing 'd' -- it's vrhi_mdd not vrhi_md_d.
- name: Copy vrhi Libraries (Windows MT)
if: matrix.is_windows
shell: pwsh
run: |
# Use recursive search so both VS (RelWithDebInfo/ subdir) and Ninja (no subdir) work
$f = Get-ChildItem -Path "build_mt_release" -Filter "vrhi.lib" -Recurse | Select-Object -First 1
Copy-Item $f.FullName "package/lib/vrhi.lib" -Force
$p = Get-ChildItem -Path "build_mt_release" -Filter "vrhi.pdb" -Recurse | Select-Object -First 1
if ($p) { Copy-Item $p.FullName "package/lib/vrhi.pdb" -Force }
$f = Get-ChildItem -Path "build_mt_debug" -Filter "vrhid.lib" -Recurse | Select-Object -First 1
Copy-Item $f.FullName "package/lib/vrhid.lib" -Force
$p = Get-ChildItem -Path "build_mt_debug" -Filter "vrhid.pdb" -Recurse | Select-Object -First 1
if ($p) { Copy-Item $p.FullName "package/lib/vrhid.pdb" -Force }
- name: Copy vrhi Libraries (Windows MD)
if: matrix.is_windows
shell: pwsh
run: |
# Use recursive search so both VS (RelWithDebInfo/ subdir) and Ninja (no subdir) work
$f = Get-ChildItem -Path "build_md_release" -Filter "vrhi_md.lib" -Recurse | Select-Object -First 1
Copy-Item $f.FullName "package/lib/vrhi_md.lib" -Force
$p = Get-ChildItem -Path "build_md_release" -Filter "vrhi_md.pdb" -Recurse | Select-Object -First 1
if ($p) { Copy-Item $p.FullName "package/lib/vrhi_md.pdb" -Force }
$f = Get-ChildItem -Path "build_md_debug" -Filter "vrhi_mdd.lib" -Recurse | Select-Object -First 1
Copy-Item $f.FullName "package/lib/vrhi_mdd.lib" -Force
$p = Get-ChildItem -Path "build_md_debug" -Filter "vrhi_mdd.pdb" -Recurse | Select-Object -First 1
if ($p) { Copy-Item $p.FullName "package/lib/vrhi_mdd.pdb" -Force }
# NOTE: Use matrix.platform_lib_subdir for lib paths, NOT hardcoded "win".
# Windows MSVC uses "win", Windows LLVM uses "win_llvm".
- name: Copy Dependency Libraries (Windows MT)
if: matrix.is_windows
shell: pwsh
run: |
$mtReleaseDir = "lib/${{ matrix.platform_lib_subdir }}_release"
$mtDebugDir = "lib/${{ matrix.platform_lib_subdir }}_debug"
# MT Release libs: copy as-is (no suffix)
Get-ChildItem -Path $mtReleaseDir -Filter "*.lib" | ForEach-Object {
$destPath = "package/lib/$($_.Name)"
if (-not (Test-Path $destPath)) {
Copy-Item $_.FullName $destPath -Force
}
}
# MT Release PDBs
Get-ChildItem -Path $mtReleaseDir -Filter "*.pdb" | ForEach-Object {
Copy-Item $_.FullName "package/lib/$($_.Name)" -Force -ErrorAction SilentlyContinue
}
# MT Debug libs: add _d suffix
Get-ChildItem -Path $mtDebugDir -Filter "*.lib" | ForEach-Object {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
$ext = $_.Extension
$destName = "${baseName}_d$ext"
if (-not (Test-Path "package/lib/$destName")) {
Copy-Item $_.FullName "package/lib/$destName" -Force
}
}
# MT Debug PDBs: add _d suffix
Get-ChildItem -Path $mtDebugDir -Filter "*.pdb" | ForEach-Object {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
Copy-Item $_.FullName "package/lib/${baseName}_d.pdb" -Force -ErrorAction SilentlyContinue
}
- name: Copy Dependency Libraries (Windows MD)
if: matrix.is_windows
shell: pwsh
run: |
$mdReleaseDir = "lib/${{ matrix.platform_lib_subdir }}_md_release"
$mdDebugDir = "lib/${{ matrix.platform_lib_subdir }}_md_debug"
# MD Release libs: add _md suffix
Get-ChildItem -Path $mdReleaseDir -Filter "*.lib" | ForEach-Object {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
$ext = $_.Extension
$destName = "${baseName}_md$ext"
if (-not (Test-Path "package/lib/$destName")) {
Copy-Item $_.FullName "package/lib/$destName" -Force
}
}
# MD Release PDBs: add _md suffix
Get-ChildItem -Path $mdReleaseDir -Filter "*.pdb" | ForEach-Object {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
Copy-Item $_.FullName "package/lib/${baseName}_md.pdb" -Force -ErrorAction SilentlyContinue
}
# MD Debug libs: add _md_d suffix
Get-ChildItem -Path $mdDebugDir -Filter "*.lib" | ForEach-Object {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
$ext = $_.Extension
$destName = "${baseName}_md_d$ext"
if (-not (Test-Path "package/lib/$destName")) {
Copy-Item $_.FullName "package/lib/$destName" -Force
}
}
# MD Debug PDBs: add _md_d suffix
Get-ChildItem -Path $mdDebugDir -Filter "*.pdb" | ForEach-Object {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name)
Copy-Item $_.FullName "package/lib/${baseName}_md_d.pdb" -Force -ErrorAction SilentlyContinue
}
- name: Create Package Directory (Non-Windows)
if: '!matrix.is_windows'
run: |
mkdir -p package/lib
- name: Copy vrhi Libraries (Non-Windows)
if: '!matrix.is_windows'
run: |
# Release
cp build_release/vrhi.a package/lib/libvrhi.a 2>/dev/null || \
cp build_release/libvrhi.a package/lib/ 2>/dev/null || \
cp build_release/libvrhi.a package/lib/libvrhi.a
# Debug
cp build_debug/vrhid.a package/lib/libvrhid.a 2>/dev/null || \
cp build_debug/libvrhid.a package/lib/ 2>/dev/null || \
cp build_debug/libvrhid.a package/lib/libvrhid.a
- name: Copy Dependency Libraries (Non-Windows)
if: '!matrix.is_windows'
run: |
LIB_DIR="lib/${{ matrix.platform_lib_subdir }}_release"
DEBUG_DIR="lib/${{ matrix.platform_lib_subdir }}_debug"
# Release libs: copy as-is with lib prefix
for lib in "$LIB_DIR"/*.a; do
if [ -f "$lib" ]; then
base=$(basename "$lib")
if [ ! -f "package/lib/$base" ]; then
cp "$lib" "package/lib/$base"
fi
fi
done
# Debug libs: add _d suffix
for lib in "$DEBUG_DIR"/*.a; do
if [ -f "$lib" ]; then
base=$(basename "$lib")
name="${base%.a}"
ext=".a"
# Skip if already has _d suffix
if [[ "$name" != *"_d" ]]; then
dest="${name}_d${ext}"
if [ ! -f "package/lib/$dest" ]; then
cp "$lib" "package/lib/$dest"
fi
else
if [ ! -f "package/lib/$base" ]; then
cp "$lib" "package/lib/$base"
fi
fi
fi
done
- name: Copy Headers (Windows)
if: matrix.is_windows
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path package/include | Out-Null
# Main headers
Copy-Item "vrhi.h" "package/include/" -Force
Copy-Item "src/vrhi_generated.h" "package/include/" -Force
# Dependency headers
if (Test-Path "include/glm") { Copy-Item "include/glm" "package/include/" -Recurse -Force }
if (Test-Path "include/nvrhi") { Copy-Item "include/nvrhi" "package/include/" -Recurse -Force }
if (Test-Path "include/vk-bootstrap") { Copy-Item "include/vk-bootstrap" "package/include/" -Recurse -Force }
if (Test-Path "include/rtxmu") { Copy-Item "include/rtxmu" "package/include/" -Recurse -Force }
if (Test-Path "include/renderdoc_app.h") { Copy-Item "include/renderdoc_app.h" "package/include/" -Force }
- name: Copy Headers (Non-Windows)
if: '!matrix.is_windows'
run: |
mkdir -p package/include
# Main headers
cp vrhi.h package/include/
cp src/vrhi_generated.h package/include/
# Dependency headers
cp -r include/glm package/include/ 2>/dev/null || true
cp -r include/nvrhi package/include/ 2>/dev/null || true
cp -r include/vk-bootstrap package/include/ 2>/dev/null || true
cp -r include/rtxmu package/include/ 2>/dev/null || true
cp include/renderdoc_app.h package/include/ 2>/dev/null || true
- name: Copy Tools (Windows)
if: matrix.is_windows
shell: pwsh
run: |
$toolsDir = "tools/${{ matrix.platform_lib_subdir }}_release"
if (Test-Path $toolsDir) {
New-Item -ItemType Directory -Force -Path package/tools | Out-Null
Copy-Item "$toolsDir/*" "package/tools/" -Recurse -Force -ErrorAction SilentlyContinue
}
- name: Copy Tools (Non-Windows)
if: '!matrix.is_windows'
run: |
TOOLS_DIR="tools/${{ matrix.platform_lib_subdir }}_release"
if [ -d "$TOOLS_DIR" ]; then
mkdir -p package/tools
cp -r "$TOOLS_DIR"/* package/tools/ 2>/dev/null || true
fi
- name: Copy Documentation
run: |
cp README.md package/
cp LICENSE package/
- name: Configure Environment (Windows)
if: matrix.is_windows
shell: pwsh
run: |
$swiftShaderDll = "C:\hostedtoolcache\windows\swiftshader\5.0.0.1\x64\vk_swiftshader.dll"
$targetDll = "package\lib\vulkan-1.dll"
if (Test-Path $swiftShaderDll) {
Copy-Item $swiftShaderDll $targetDll -Force
echo "Copied SwiftShader to $targetDll"
}
- name: Configure Environment (macOS)
if: runner.os == 'macOS'
run: |
echo "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0" >> $GITHUB_ENV
echo "MVK_CONFIG_USE_MTLHEAP=0" >> $GITHUB_ENV
echo "MVK_CONFIG_LOG_LEVEL=3" >> $GITHUB_ENV
echo "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=1" >> $GITHUB_ENV
echo "MVK_CONFIG_USE_COMMAND_POOLING=0" >> $GITHUB_ENV
if [ -f "$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json" ]; then
echo "VK_ICD_FILENAMES=$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json" >> $GITHUB_ENV
elif [ -f "$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json" ]; then
echo "VK_ICD_FILENAMES=$VULKAN_SDK/etc/vulkan/icd.d/MoltenVK_icd.json" >> $GITHUB_ENV
fi
- name: Test Package (Windows MT)
if: matrix.is_windows
shell: pwsh
run: |
$env:VRHI_PACKAGE_PATH = "$PWD/package"
cmake --build build_mt_release --config RelWithDebInfo --target test_package_vrhi
- name: Test Package (Non-Windows)
if: '!matrix.is_windows'
run: |
export VRHI_PACKAGE_PATH="$PWD/package"
cmake --build build_release --config Release --target test_package_vrhi
- name: List Package Contents (Windows)
if: matrix.is_windows
shell: pwsh
run: |
Write-Host "Package contents:"
Get-ChildItem package/
Write-Host ""
Write-Host "Library contents:"
Get-ChildItem package/lib/
- name: List Package Contents (Non-Windows)
if: '!matrix.is_windows'
run: |
echo "Package contents:"
ls -la package/
echo ""
echo "Library contents:"
ls -la package/lib/
- name: Create ZIP (Windows)
if: matrix.is_windows
shell: pwsh
run: |
Compress-Archive -Path package\* -DestinationPath ${{ matrix.zip_name }}.zip -Force
Write-Host "Created ${{ matrix.zip_name }}.zip"
- name: Create ZIP (Non-Windows)
if: '!matrix.is_windows'
run: |
cd package && zip -r ../${{ matrix.zip_name }}.zip . && cd ..
ls -la ${{ matrix.zip_name }}.zip
- name: Upload Release Assets
uses: softprops/action-gh-release@v2
with:
files: |
${{ matrix.zip_name }}.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}