Skip to content

metal: load default.metallib by path when newDefaultLibrary returns nil#19166

Draft
vanreece wants to merge 1 commit into
libretro:masterfrom
vanreece:pr-macos-metal-library-load
Draft

metal: load default.metallib by path when newDefaultLibrary returns nil#19166
vanreece wants to merge 1 commit into
libretro:masterfrom
vanreece:pr-macos-metal-library-load

Conversation

@vanreece

@vanreece vanreece commented Jul 4, 2026

Copy link
Copy Markdown

Summary

On macOS, -[MTLDevice newDefaultLibrary] only resolves default.metallib
from inside a .app bundle's resources. For a bare executable — CLI builds,
non-.app installs, or a dev build run in place — it returns nil, leaving
the Metal driver with no shader library. Every -newFunctionWithName: then
returns nil.

That nil function is passed straight to
-newComputePipelineStateWithFunction:error: when building the pixel-format
conversion filters, which asserts (computeFunction must not be nil) and
aborts the process. Depending on timing it can instead surface as a
half-initialized driver or a plain "Cannot open video driver".

Fix

  • When newDefaultLibrary returns nil, fall back to loading default.metallib
    explicitly via -newLibraryWithURL:error: from the executable's own directory
    (where make install places it). The normal .app bundle path is unaffected.
  • Guard -newFunctionWithName: in +[Filter newFilterWithFunctionName:...]: a
    nil function now returns gracefully with an error log instead of tripping the
    NSAssert.

Testing

macOS (Apple Silicon, Metal), running the binary outside a .app bundle:
before, it aborts at init with the computeFunction must not be nil assertion;
after, it logs loaded shader library from …/default.metallib and runs
normally. The .app build path is unchanged — the fallback only runs when
newDefaultLibrary is nil.

🤖 Generated with Claude Code

On macOS, -[MTLDevice newDefaultLibrary] only resolves default.metallib
from inside a .app bundle's resources. For a bare executable (CLI builds,
non-.app installs, a dev build run in place) it returns nil, leaving the
Metal driver with no shader library -- every -newFunctionWithName: then
returns nil.

That nil function is passed straight to
-newComputePipelineStateWithFunction:error: when building the pixel-format
conversion filters, which asserts ("computeFunction must not be nil") and
aborts the process. Depending on timing it can instead surface as a
half-initialized driver or a plain "Cannot open video driver".

Two fixes:
 - When newDefaultLibrary returns nil, fall back to loading
   default.metallib explicitly via -newLibraryWithURL:error: from the
   executable's own directory (where `make install` places it). The normal
   .app bundle path is unaffected.
 - Guard -newFunctionWithName: in +[Filter newFilterWithFunctionName:...]:
   a nil function now returns gracefully with an error log instead of
   tripping the NSAssert inside newComputePipelineStateWithFunction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant