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
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
nvsvwaitms (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=0restores 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_flipsadvances 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 inpart->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 withCL_SUCCESSeverywhere, 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 ... -> oursand 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
libnvenc_h264/hevc.dylibandlibnvdec_h264/hevc.dylibship as binaries only. The repository has their loader in
plugin/NVMTLDevice.mbut no source, and they are not in the README's component table or inNOTICE. Will the source be
published? The NVENC failure could not be looked into further without it.- There is no build script for NVRM.kext (only
accel_build.shandbuild_agdc.sh), and NVIDIA'ssrc/nvidiadoes not
compile on macOS as shipped (#error "Unsupported target OS"innvport/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, withsrc/nvidia/_out/Darwin_x86_64/compile_cmds.shregenerated from
make -ninsrc/nvidiaof open-gpu-kernel-modules 610.57.04 (only its-Dflags 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
clangline frombuild/build_plugin.shwithRELEASE=1(plugin_build.sh, attached). - Testing without a restart: the plugin built as a
-dynamicliband 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.mandrtcl.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.
- 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
- 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 75/100
nullmoth/nvidia-macos-driver#126 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
nullmoth/nvidia-macos-driver#108 · 4 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
nullmoth/nvidia-macos-driver#28 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 5/5 Over a week Newbie friendliness 28/100
nullmoth/nvidia-macos-driver#135 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
nullmoth/nvidia-macos-driver#134 ·
Maintainers usually reply within 1 day
All issues in nullmoth/nvidia-macos-driver
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
swc-project/swc#12516 ·
Maintainers usually reply within 1 day
-
app bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
mls-rs-crypto-awslc: exact aws-lc-rs =1.16.3 pin blocks rustls security updatePossibly taken @muscariello claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
-
[work-item] adam-adae-worsening-emergence: conform spec.yaml to the specification style contract (REQ-1280)Possibly taken @muse-yamaa-bot claimed this today. Openwork-item
Difficulty 1/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day