Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[Feature] Wine/Vulkan Metal WSI: BeamNG.drive working on RTX 4070 Ti SUPER (NVK staging patches + results)

Open
#325 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 2 days

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
c, rust
Domain
backend

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

BeamNG.drive at Hirochi Raceway on macOS with RTX 4070 Ti SUPER

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
  1. 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.
  2. MoltenVK was tested as a fallback, but on this machine the required drawIndirectCount feature was unavailable. We did not force feature flags or spoof Vulkan feature support.
  3. After enabling Metal WSI, the game requested four swapchain images. Passing that count directly to CAMetalLayer.maximumDrawableCount was 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.maximumDrawableCount to 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from nullmoth/nvidia-macos-driver

All issues in nullmoth/nvidia-macos-driver

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.