[Feature] Wine/Vulkan Metal WSI: BeamNG.drive working on RTX 4070 Ti SUPER (NVK staging patches + results)
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
Research direction
Start by reviewing the reported NVK Metal WSI patches, especially changes to nvk_physical_device.h, nvk_instance.c, nvk_wsi.c, and the Mesa Vulkan WSI staging path. The issue includes exact tested revisions and manual smoke-test results, but asks whether the approach fits project direction and how NVMTL should share presentable images. A contribution would need an agreed design, broader compatibility testing, and documented results.
Written by the indexing model from the issue text.
Description
Hirochi Raceway running on macOS.
What should it do, and why does it matter?
Please consider enabling a Wine-compatible Metal surface/swapchain path for NVK on macOS. We have BeamNG.drive 0.40.1.0 running with GPU rendering on an RTX 4070 Ti SUPER using a locally built NVK with Mesa's existing CPU-staging Metal WSI. I am sharing the working experiment, exact source revisions and patches in case they help others or an upstream implementation.
Gameplay and gamepad operation were tested manually. The patches below are experimental.
Hardware and software
| Component | Tested configuration |
|---|---|
| Machine | x86_64 Hackintosh; Intel Core i5-13600KF; 48 GB RAM |
| GPU | NVIDIA GeForce RTX 4070 Ti SUPER, physical 16 GB VRAM |
| OS | macOS Tahoe 26.7.1, build 25G241 |
| Installed driver | NullMoth 2.4.3, already installed before this work |
| Game | Steam Windows x64 BeamNG.drive 0.40.1.0; App 284160; build 26084235 |
| Wine | Gcenx Wine Devel 11.18 x86_64, isolated prefix configured as Windows 10 |
| Experimental Vulkan driver | Mesa NVK 26.3.0-devel, commit 17ca6174dcc6cb22059ac343bc29f8af7800f42e |
| Base macOS changes | NullMoth v2.4.3 nvk/nvk-macos.patch, source commit 47f818b11cef59acb480210afdf9065fdd44e356 |
| NVIDIA build headers | open-gpu-kernel-modules 610.57.04, user-space build inputs only |
No system NVK/loader replacement, kext installation, firmware change, EFI/OpenCore edit, or security-setting change was made during this work. The original installed system NVK and Vulkan loader SHA-256 values were checked unchanged.
Initial failures
- Native and Wine headless Vulkan compute/readback worked on the installed NVK, but the required host window-system presentation path was unavailable. The initial game launch failed through Wine's surface creation path; the game also displayed an unusable Vulkan GPU assertion during early attempts.
- MoltenVK was tested as a fallback, but on this machine the required
drawIndirectCountfeature was unavailable. We did not force feature flags or spoof Vulkan feature support. - After enabling Metal WSI, the game requested four swapchain images. Passing that count directly to
CAMetalLayer.maximumDrawableCountwas incompatible with its supported range of two to three. Keeping Vulkan backing image count separate from Metal drawable slot count resolved that obstacle.
Working render/present path
Windows BeamNG Vulkan
-> Wine winevulkan
-> isolated patched NVK (actual RTX GPU rendering)
-> Mesa Metal WSI CPU staging
-> installed NVMTL / its NVK path
-> CAMetalLayer / display
The Apple-only wsi_device_options.sw_device = true selects the existing staging presentation implementation. It does not make the game's rendering software-based. This is not a zero-copy path and the game's Vulkan rendering is not being translated through MoltenVK.
Four local source patches were applied after the NullMoth macOS patch:
- Enable Metal as an NVK WSI platform, expose
VK_EXT_metal_surface, select the Apple staging path, disable DRM modifiers for that path, and link Foundation/QuartzCore/Metal. - Remove an unconditional newer-Clang header include to allow the LLVM 20 build; the existing version-guarded include remains.
- Guard a host-only warning using
fprintf(stderr, ...)from being compiled into the OpenCL shader library. - Clamp only
CAMetalLayer.maximumDrawableCountto 2–3, preserving the Vulkan swapchain's four backing images.
Exact local diffs are included below. Wine itself was not rebuilt or patched for the working configuration. An earlier candidate Wine missing-WSI error guard was never installed and is not part of these results.
Build notes
Build tools were kept local to the project: Apple clang 21 / Xcode 26.5, Meson/Ninja/Python, Rust 1.99.1, bindgen-cli 0.72.1, cbindgen 0.29.2, glslang 16.6.0, LLVM 20.1.8, SPIRV-LLVM-Translator 20.1.4 and SPIRV-Tools 1.4.321.0. LLVM and related Intel Sonoma bottles were extracted and relocated locally; no global Homebrew installation was needed.
The Meson configuration used was:
meson setup BUILD_DIR MESA_SOURCE \
-Dbuildtype=debugoptimized -Dvulkan-drivers=nouveau -Dgallium-drivers= \
-Dplatforms=macos -Degl=disabled -Dglx=disabled -Dglvnd=disabled \
-Dllvm=enabled -Dshared-llvm=enabled -Dmesa-clc=enabled \
-Dshared-glapi=disabled -Dvulkan-layers= -Dtools= -Dbuild-tests=false \
-Dexpat=disabled -Dzstd=disabled -Dlibunwind=disabled -Dlmsensors=disabled \
-Dvalgrind=disabled -Dxlib-lease=disabled -Dgallium-rusticl=false \
-Dspirv-tools=enabled
This is a record of the tested build configuration, not a standalone build recipe: the macOS base patch, local patches, SDK and compiler/dependency paths must be configured first. The final runtime packages libvulkan_nouveau.dylib, libSPIRV-Tools.dylib and a relative-path ICD JSON, with local @loader_path dependencies.
Launch configuration
The isolated runtime is selected only for the game's Wine process, using VK_DRIVER_FILES pointing to the packaged NVK ICD and WINEPREFIX pointing to a dedicated prefix. The game executable is Bin64/BeamNG.drive.x64.exe with -gfx vk. No global ICD configuration was changed.
Conceptually:
WINEPREFIX="$PREFIX" VK_DRIVER_FILES="$RUNTIME/nvk_icd.json" \
"$WINE" "$GAME/Bin64/BeamNG.drive.x64.exe" -gfx vk
A macOS launcher app bundles the tested Wine and NVK runtime, verifies core runtime hashes, and writes dated logs. The licensed game and prefix remain external. Repeat launch through the app was checked successfully.
Validation and gameplay
- Native Vulkan and Wine Vulkan compute returned the expected readback value (42).
- A native GPU clear/copy/readback test verified all image pixels.
- Native Metal-surface/swapchain and Windows-through-Wine WSI smoke tests each presented 120 frames, including tests with four Vulkan backing images (and earlier three-image tests).
- The packaged relocatable runtime passed load, compute and presentation checks.
- Reverse-application checks confirmed all four patches were present in the tested sources.
- Smallgrid and Gridmap V2 loaded and rendered. Driving, steering, braking, crash deformation, smoke, shadows and UI were observed. I subsequently tested the game manually and confirmed gamepad operation too.
- A later screenshot also shows Hirochi Raceway with a vehicle, alongside macOS System Settings showing the NVIDIA GPU and OS version.
- The first logged playable session ended cleanly with exit code 0 after approximately 434 seconds. A formal controlled 15–30 minute stress test and a complete regression matrix were not recorded.
Observed performance (not a standardized benchmark)
| Scene | Settings / observation |
|---|---|
| Smallgrid | 1280×720 screenshot: 160.9 FPS instantaneous, 150.5 average; 6.22 ms frame, CPU 6.08 ms, GPU 3.39 ms |
| Gridmap V2 | 2560×1440, Ultra, FSR 3 Quality as selected in-game: 101.3 FPS instantaneous, 102.6 average, displayed range 82.7–121.9 FPS; frame 9.87 ms, CPU 7.41 ms, GPU 5.40 ms |
The Gridmap log records fsrCustom 1690×950 -> 2560×1440. The counters above are from individual gameplay screenshots, with no controlled camera route, thermal comparison, multi-vehicle workload or Windows baseline. Frame generation status was not independently verified. These numbers should not be treated as general expected performance.
Caveats and possible follow-up
- Presentation still incurs CPU staging. Its cost has not been profiled separately, so no specific FPS gain is claimed for a future shared-memory/zero-copy implementation.
- This was tested on one machine/GPU and one game version. The global Mesa Metal drawable clamp should be reviewed and tested against other users of that WSI implementation before upstreaming.
- BeamNG's hardware screen reports 24568 MB VRAM. A separate Vulkan heap probe reported 16376 MiB local VRAM plus another 8192 MiB device-local, host-visible/coherent heap associated with the mapped/BAR path. The sum explains that UI number; the physical GPU is still 16 GB. No memory-reporting patch was applied, and probe budget/usage does not represent in-game usage.
It would be useful to know whether this staging WSI approach fits the project's direction and what mechanism is intended for sharing presentable images with NVMTL without a CPU round trip.
Runtime identifiers
Game EXE SHA256:
3172148e50033089d4b6d32e0d6fe7708aee7280ef3ff20753422a1ace701a11
Packaged NVK SHA256:
ed37034e92441a314b9c4bc43a2eea35647704946c98383c3166469556cf8551
Packaged SPIRV-Tools SHA256:
c66187dce2b49d54bea2f51e229e3ddbf09b16d8a0f9c73fdf34eff5dda6a5ea
Wine executable SHA256:
6a6189edccf4d780329348a53e07ab872f6960854d17f78ac57527bcf62d1359
Applied local patches
nvk-macos-metal-wsi-staging.patch
--- a/src/nouveau/vulkan/nvk_physical_device.h
+++ b/src/nouveau/vulkan/nvk_physical_device.h
@@ -106,7 +106,8 @@
#if defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
defined(VK_USE_PLATFORM_XCB_KHR) || \
defined(VK_USE_PLATFORM_XLIB_KHR) || \
- defined(VK_USE_PLATFORM_DISPLAY_KHR)
+ defined(VK_USE_PLATFORM_DISPLAY_KHR) || \
+ defined(VK_USE_PLATFORM_METAL_EXT)
#define NVK_USE_WSI_PLATFORM
#endif
--- a/src/nouveau/vulkan/nvk_instance.c
+++ b/src/nouveau/vulkan/nvk_instance.c
@@ -39,6 +39,9 @@
.KHR_surface_protected_capabilities = true,
.EXT_surface_maintenance1 = true,
.EXT_swapchain_colorspace = true,
+#endif
+#ifdef VK_USE_PLATFORM_METAL_EXT
+ .EXT_metal_surface = true,
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
.KHR_wayland_surface = true,
--- a/src/nouveau/vulkan/nvk_wsi.c
+++ b/src/nouveau/vulkan/nvk_wsi.c
@@ -23,7 +23,12 @@
if (pdev->vk.instance->enabled_extensions.KHR_display)
display_fd = nvkmd_pdev_get_drm_primary_fd(pdev->nvkmd);
struct wsi_device_options wsi_options = {
+ #ifdef __APPLE__
+ /* NVK renders on the GPU; Metal WSI presents through its existing CPU staging path. */
+ .sw_device = true
+#else
.sw_device = false
+#endif
};
result = wsi_device_init(&pdev->wsi_device,
nvk_physical_device_to_handle(pdev),
@@ -35,8 +40,12 @@
return result;
pdev->wsi_device.supports_scanout = false;
+ #ifdef __APPLE__
+ pdev->wsi_device.supports_modifiers = false;
+#else
pdev->wsi_device.supports_modifiers =
pdev->vk.supported_extensions.table.EXT_image_drm_format_modifier;
+#endif
pdev->vk.wsi_device = &pdev->wsi_device;
--- a/src/nouveau/vulkan/meson.build
+++ b/src/nouveau/vulkan/meson.build
@@ -300,7 +300,7 @@
nvk_flags = ['-DNVTYPES_USE_STDINT=1']
if host_machine.system() == 'darwin'
- nvk_deps += dependency('appleframeworks', modules : ['IOKit', 'CoreFoundation'])
+ nvk_deps += dependency('appleframeworks', modules : ['IOKit', 'CoreFoundation', 'Foundation', 'QuartzCore', 'Metal'])
endif
nvk_build_id = get_option('nvk-build-id')
mesa-clc-llvm20-include.patch
--- a/src/compiler/clc/clc_helpers.cpp
+++ b/src/compiler/clc/clc_helpers.cpp
@@ -54,7 +54,6 @@
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Frontend/Utils.h>
#include <clang/Basic/TargetInfo.h>
-#include <clang/Options/OptionUtils.h>
#include <spirv-tools/libspirv.h>
#include <spirv-tools/libspirv.hpp>
nvk-host-warning-opencl-guard.patch
--- a/src/nouveau/headers/nv_push.h
+++ b/src/nouveau/headers/nv_push.h
@@ -132,6 +132,7 @@
* vk_meta_draw_volume) reached here with an empty method and aborted Chess,
* mediaanalysisd and several video apps. Warn once and continue, as the
* stale rasterization-samples assert in nvk_cmd_draw.c was downgraded. */
+#if !defined(__OPENCL_C_VERSION__) && !defined(__OPENCL_CPP_VERSION__)
if (last_count == 0) {
static int warned;
if (!warned) {
@@ -139,6 +140,7 @@
fprintf(stderr, "nvk: empty push method header (count 0); continuing\n");
}
}
+#endif
}
static inline void
mesa-metal-drawable-limit.patch
--- a/src/vulkan/wsi/wsi_common_metal_layer.m
+++ b/src/vulkan/wsi/wsi_common_metal_layer.m
@@ -167,7 +167,11 @@
metal_layer.allowsNextDrawableTimeout = YES;
metal_layer.framebufferOnly = framebuffer_only;
- metal_layer.maximumDrawableCount = image_count;
+ /* Vulkan swapchain images and CAMetalLayer drawable slots have separate
+ * lifetimes. Metal only permits two or three drawable slots, including
+ * when the Vulkan swapchain has four or more backing images. */
+ metal_layer.maximumDrawableCount = image_count < 2 ? 2 :
+ image_count > 3 ? 3 : image_count;
metal_layer.drawableSize = (CGSize){.width = width, .height = height};
metal_layer.opaque = enable_opaque;
metal_layer.displaySyncEnabled = !enable_immediate;
- Dominant language
- Rust
- Stars
- 2.5k
- Forks
- 233
- Avg merge
- 21h 20m
- Merged PRs (30d)
- 3
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from nullmoth/nvidia-macos-driver
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
nullmoth/nvidia-macos-driver#141 · 1 comment ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
nullmoth/nvidia-macos-driver#28 ·
Maintainers usually reply within 2 days
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 55/100
nullmoth/nvidia-macos-driver#336 ·
Maintainers usually reply within 2 days
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 45/100
nullmoth/nvidia-macos-driver#335 ·
Maintainers usually reply within 2 days
-
bug
Difficulty 5/5 Over a week Newbie friendliness 25/100
nullmoth/nvidia-macos-driver#334 ·
Maintainers usually reply within 2 days
All issues in nullmoth/nvidia-macos-driver
Similar issues
-
documentation priority:p2 type:chore
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
facebookincubator/scrut#60 ·
-
dispatch:sol-high documentation
Difficulty 1/5 1-3 hours Newbie friendliness 85/100
carrick-sh/carrick#768 · 1 comment ·
Maintainers usually reply within 1 day
-
correctness postgres tursopg
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
tursodatabase/turso#10442 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 82/100
ankitects/anki#5864 · 1 reaction ·
Maintainers usually reply within 2 days