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

RTX 4090 (AD102) on 1.9.0: desktop + Metal 3 at 4K@160 with 3 small patches; README BAR settings freeze boot, NVENC and OpenCL fail

Open
#93 2 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
20/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
c, macos, objective-c
Domain
backend

Research direction

Start with the three attached patches and the named entry points: kexts/NVRM/accel/nvrm-accel.cpp, kexts/NVRMFB/fb/nvrm-fb.cpp, plugin/NVMTLObjects.m and .h, and kexts/NVRM/os-xnu2.cpp. Reproduce the reported boot, refresh-rate, texture, NVENC, or OpenCL behavior on the stated RTX 4090 setup and compare it with the supplied logs and results. Done means the specific failure is fixed and its reported checks pass; the issue also asks about unavailable codec source and the missing NVRM build recipe.

Written by the indexing model from the issue text.

Description

RTX 40 is listed as "Pending" in docs/CARD-SUPPORT.md, so here is a full report from an RTX 4090. With three small patches
(attached) the card runs the desktop at 4K@160 with Metal 3 and no flicker after login. Two README settings hard-freeze
this card at boot, and NVENC and OpenCL do not work.

Environment

GPU RTX 4090 24 GB, AD102, 10DE:2684 (only dGPU; UHD 770 unused)
CPU / board i9-13900K, Gigabyte Z790 AORUS ELITE AX, BIOS F16
BIOS Above 4G Decoding on, Re-Size BAR on (firmware BAR1 = 32 GB), CSM off
Display LG ULTRAGEAR+ 4K over DisplayPort, EDID 1E6D:5BBF (preferred 4K@95, up to 4K@160)
Software macOS 15.8.1 (24H32), OpenCore 1.0.8, iMacPro1,1
Driver 1.9.0, installed with pkgroot/install.sh (1401.app was not used)

Summary

# Finding Status here
1 README BAR settings (ResizeGpuBars 13, ResizeAppleGpuBars -1) hard-freeze boot on a 32 GB-BAR card Worked around with the installer values
2 First minute after boot strobes: CPU-copy path shows stale frames, zero-copy flip starts only at 60 s Patch 0003, verified
3 A >60 Hz panel always starts at the EDID-preferred rate; changing the rate at run time halves the frame rate Patch 0001 for the start-up rate, verified. Run-time change not fixed
4 Textures made from no-copy buffers show stale or black content Patch 0002, verified in a test program
5 Host-pointer import of read-only memory always fails Not patched (needs an NVK or NVRM build)
6 NVENC (H.264 and HEVC) never opens; OpenCL on the GPU returns unchanged buffers Not patched
7 Codec libraries have no source; NVRM.kext has no build recipe Question

Patches are against the v1.9.0 tag and apply with patch -p1. Everything was built with the Command Line Tools only
(Apple clang 17).


1. README BAR settings hard-freeze boot when the firmware BAR1 is 32 GB

With the driver-mode values from the README and nullmoth-setup.sh:

ResizeGpuBars ResizeAppleGpuBars Result
13 -1 Hard freeze right after the ACPI lines, before "PCI configuration begin". Keyboard dead, no panic
-1 -1 Same freeze
-1 0 Boots. NVRM resizes BAR1 itself

With the last row, placeLargeBar1() does the job:

bar1: BAR1 is 64 MB; will resize it to 8192 MB
bar1: host bridge 64-bit window 0x4000000000-0x7fffffffff (ACPI _CRS), CPU reaches 46 bits
bar1: placing BAR1 8192 MB @0x7c00000000, BAR3 32 MB @0x7e00000000, root port window 0x7c00000000-0x7e01ffffff
bar1: PLACED — BAR1 8192 MB live at 0x7c00000000

Suggestion: for cards whose firmware BAR1 is larger than 8 GB, keep ResizeAppleGpuBars 0 / ResizeGpuBars -1 in driver
mode and let NVRM place BAR1.

2. The first minute after boot strobes (patch 0003)

What happens. NVRM::autoGo sets debug.nvaccel_iop_flip=1 60 s after the boot hold is released. Until then
NVDisplayPipe::performTransaction copies every frame from the IOSurface's system memory into the live scanout.
nvAccelSurfScanoutSync only try-locks the accelerator, and on a miss the copy goes ahead with stale (or never written)
system memory. The first eight accelerator lock busy, surface N stays pending lines appear within ~20 s of login on every boot.

This install has no com.nullmoth.wsreset (install.sh does not install it). That stopgap would also fire about when the
user logs in here (login is ~10 s after the hold is released).

Patch (kexts/NVRM/accel/nvrm-accel.cpp):

  • the copy path waits up to nvsvwait ms (default 8) for the accelerator lock; if it stays busy the frame is not copied, so
    the frame already on the panel stays instead of an older one (nvsvskip=0 restores the old behaviour);
  • boot-arg nvflipafter=<seconds> (2–59) turns the zero-copy flip on that long after the hooks open.

Result with nvflipafter=8:

1.9.0 patched
Zero-copy flip starts 60.0 s after the hold is released 8 s
Frames through the CPU-copy path in that boot ~2280 124
CPU-copy path still active after login for ~47 s no
Visible flicker after login 15–20 s none

In the patched boot the copy path ended before login, so the lock-wait/skip branch never ran (sv_lock_miss 0); the
measured improvement comes from nvflipafter.

Question: is there a reason for the 60 s other than leaving room for the wsreset stopgap?

3. Start-up refresh rate, and the half frame rate after a run-time change (patch 0001)

What happens. NVRM lights head 0 at the EDID-preferred mode (4K@95 here) and NVRMFB's boot pair keeps it, so mode 0x1 is
always 95 Hz. Changing the rate in System Settings commits without error, but WindowServer then presents at exactly half the
rate until reboot. Measured after 95 → 60 → 95 Hz:

  • CVDisplayLink still delivers 95.0 callbacks/s;
  • no flip is refused, each async flip takes about one vblank (~10 ms);
  • debug.nvaccel_iop_flips advances by 48/s instead of 96/s.

This looks like the "flashes after a refresh change" item in the release notes.

Patch (kexts/NVRMFB/fb/nvrm-fb.cpp): boot-arg nvfbhz=<Hz> makes the start-up mode the highest NVKMS-validated refresh
rate ≤ that value on the preferred raster, applied after the boot pair. Without the boot-arg nothing changes.

Result with nvfbhz=160:

NVRM-fb: nvfbhz=160: display 0x200 starts at 3840x2160 @160 Hz (EDID-preferred 95 Hz)
NVRM-fb: switchMode 0x1: COMMIT 3840x2160 -> raster 3840x2160 @159975 mHz pclk 1492250000 -> 1 (flipResult 0)

160.0 CVDisplayLink callbacks/s and ~164 flips/s, with no run-time mode change needed. The half rate after a run-time change
is not fixed by this.

4. Textures made from no-copy buffers show stale or black content (patch 0002)

What happens. WindowServer logs this on every boot:

buffer texture: refused on alignment - image types 0x7 of 0x7, bind at 16720 (buffer 16640 + 80) vs alignment 32
newTiledTextureWithDescriptor: linear view refused -> copied texture (30x32 bpr 544; said once)
vk: vkAllocateMemory refused the imported host pointer 0x37cb4d000 (81920 bytes, memory type 2)

Reproduced in a user process (tiled.m, attached): a texture created with newTiledTextureWithDescriptor:offset:bytesPerRow:
over a newBufferWithBytesNoCopy buffer is wrong in 6 of 8 cases.

Pages Offset Bytes written First frame After an in-place redraw
read-write 32 before / after creation ok ok
read-write 80 before creation ok stale
read-write 80 after creation black stale
read-only 32 or 80 before creation ok stale
read-only 32 or 80 after creation black stale

Two causes:

  • an offset that is not a multiple of 32 (CoreAnimation uses 80) falls back to a texture that is copied once at creation;
  • for read-only pages the host-pointer import is refused (see 5), the buffer becomes a COPIED stand-in, and a texture view
    over it is never resynced — the commit loop only syncs buffers that are themselves in part->resources.

Patch (plugin/NVMTLObjects.m, .h): nvmtl_tex_live_refresh() runs from -nvmtlSurfaceIn for non-surface textures.
A view over a COPIED stand-in re-copies its rows from the host pointer; a copied tiled texture remembers its source and
re-uploads when a hash of the source rows changes.

Result: 8 of 8 cases correct. An intermittent black bar in place of Finder's list-view header has not come back since,
but it was intermittent, so that is not proof.

5. Host-pointer import of read-only memory always fails (not patched)

os_lock_user_pages (kexts/NVRM/os-xnu2.cpp) pins with kIODirectionInOut, because NVK passes NVRM_HOST_OS02_FLAGS
without ALLOC_USER_READ_ONLY. The memory that clients share with WindowServer is read-only there, so prepare() fails:

NVRM-xnu: os_lock_user_pages(0x37079f000, 4 pages) prepare -> 0x2        (2883 of these in 45 minutes)
nvkmd_nvrm_mem.c:373: NV_ESC_RM_ALLOC_MEMORY(OS descriptor 0x11c82f000, 4100096 B) -> NV_STATUS 0x56
newBufferWithBytesNoCopy: COPIED 4100096 bytes at 0x11c82f000 (import alignment 4096) — resynced at every submission

Suggestion: in nvkmd_nvrm_import_host_mem, retry with DRF_DEF(OS02, _FLAGS, _ALLOC_USER_READ_ONLY, _YES) when the first
allocation fails. RM then calls os_lock_user_pages with WRITE=0 (the shim already maps that to kIODirectionOut) and marks
the device mapping read-only. Alternatively retry kIODirectionOut in the shim on a protection failure.

Separately, WindowServer uses 60–100 % of one core while a window redraws continuously. The sampled stack is
-[NVMTLRenderCommandEncoder setFragmentTexture:atIndex:] → -[NVMTLTexture nvmtlSurfaceIn] → nvmtl_vk_image_write →
memmove.

6. Feature check at 4K@160 (1.9.0 plus the three patches)

Working

  • Metal 3 device, shader compile, compute (16M floats, exact)
  • 4K render with MSAA 4x, sRGB, blending, D32S8; mipmap generation; readback
  • MPS Gaussian blur, Core Image, OpenGL 4.1 on Metal
  • Metal ray tracing (65 536 rays against a BLAS, hit count correct)
  • Hardware decode, H.264 and HEVC, 1080p and 4K (encode → decode round trip, pictures compared with the source)
  • Behind-window blur in WindowServer (NSVisualEffectView over a striped window, four materials)
  • CoreAnimation backdrop blur and blend modes through CARenderer

Not working

  • NVENC, H.264 and HEVC. The session never opens and VideoToolbox silently falls back to Apple's software encoders
    (VT_ENC=enable ./vttest).
    nvrm_xnu: IOConnectMapMemory64 -> 0xe00002c2
    nvkmd_nvrm_mem.c:450: nvRmApiMapMemory(33554432 B, system) -> NV_STATUS 0xffff      (then 0x63 for every later map)
    NVRM-xnu: map on fd 350 with no mapping context                                      (kernel)
    
  • OpenCL on the GPU. a[i] = a[i]*3 + b[i] over 1M floats builds and runs with CL_SUCCESS everywhere, but the output
    buffer is unchanged. The same program on the CPU device is correct (rtcl.m). The plugin logs
    GL: OpenCL kernel __entry_k lowered in process ... -> ours and creates the pipeline without error.
  • Copy engine on Ada. At every device creation:
    nvrm: copy-engine queue could not be built on this GPU (VkResult -13) - copy queue on a graphics channel
    NVRM: GPU0 chandesConstruct_IMPL: bad class 0xc7b5                                   (kernel)
    nvrm: b81 SET_LG_SECTOR_PROMOTION 64B rc 0x56
    

7. Two questions

  1. libnvenc_h264/hevc.dylib and libnvdec_h264/hevc.dylib ship as binaries only. The repository has their loader in
    plugin/NVMTLDevice.m but no source, and they are not in the README's component table or in NOTICE. Will the source be
    published? The NVENC failure could not be looked into further without it.
  2. There is no build script for NVRM.kext (only accel_build.sh and build_agdc.sh), and NVIDIA's src/nvidia does not
    compile on macOS as shipped (#error "Unsupported target OS" in nvport/debug.h). Could the Darwin build recipe be added?
    It would have let the fix in section 5 be tested here.

How the patches were built

  • NVAccel: build/accel_build.sh, with src/nvidia/_out/Darwin_x86_64/compile_cmds.sh regenerated from
    make -n in src/nvidia of open-gpu-kernel-modules 610.57.04 (only its -D flags are used).
  • NVRMFB: a script modelled on accel_build.sh (fb_build.sh, attached). An unmodified build has the same symbols,
    strings and Info.plist as the shipped kext.
  • Plugin: the clang line from build/build_plugin.sh with RELEASE=1 (plugin_build.sh, attached).
  • Testing without a restart: the plugin built as a -dynamiclib and loaded into one test process with
    DYLD_INSERT_LIBRARIES; its classes win over the system copy.

Attachments

rtx4090-report-attachments.zip:

  • 0001-nvrmfb-nvfbhz-startup-refresh.patch, 0002-plugin-live-buffer-textures.patch, 0003-nvaccel-stale-frame-early-flip.patch
  • tests: tiled.m (section 4), vttest.m and rtcl.m (section 6), caps.m, catest.m, miptest.m, blurprobe.m
  • build scripts: fb_build.sh, plugin_build.sh

Kernel and WindowServer logs are available on request.

rtx4090-report-attachments.zip

Dominant language
Rust
Stars
2.5k
Forks
233
PR merge metrics
No merged PRs in 30d

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.