KhronosGroup / MoltenVK

MoltenVK is a Vulkan Portability implementation. It layers a subset of the high-performance, industry-standard Vulkan graphics and compute API over Apple's Metal graphics framework, enabling Vulkan applications to run on macOS, iOS and tvOS.
Apache License 2.0
4.85k stars 429 forks source link

Expose experimental Vulkan features using internal Metal API #1670

Closed spnda closed 10 months ago

spnda commented 2 years ago

As noted by @cdavis5e in #1657, there's a few things in Metal which are not documented or exposed. These features could possibly be used to experiment supporting some Vulkan features that would not be supportable otherwise. The initial idea is to have a compile-time option which would enable these experimental features, as using these private APIs would not allow shipping an app with MoltenVK into the App Store and should therefore not be the default. This issue shall act as some sort of a tracker of potential features and their implementations by looking into the symbols and Objective-C metadata.

5 patches have already been written to support some features (although not entirely stable): https://github.com/KhronosGroup/MoltenVK/issues/1657#issuecomment-1197438815

I have also just gone ahead and extracted the symbols of the Metal binary found in the Metal.framework shipped with the latest macOS 13 beta, meaning with support for Metal 3 and Metal IO. I couldn't get class-dump to not crash with this binary, so this is just the basic output of nm: metal_symbols.txt metalkit_symbols.txt

Some few things I've found in metal_symbols.txt:

billhollings commented 2 years ago

setLineWidth: (as used by one of the patches linked above) is not listed anymore.

Nice sleuthing.

Interestingly, -[_MTLDevice maxLineWidth] is still there.

Hmmm...unless it's moved to a different library that is accessible...this is the kind of thing where it can get really messy to try to support these kind of private-API calls...and frustrating for users if something arrives for a while and then gets taken away.

TellowKrinkle commented 2 years ago

Just a heads up: Just because the method is there, doesn't mean it works, or works well.

Some others I've found:

I'd expect setLineWidth: to continue to exist as long as OpenGL does, at least on Apple GPUs, since I'm pretty sure they use it internally for the OpenGL → Metal translation layer, which is used for OpenGL support on Apple. I think it's not showing up there because protocols aren't emitted into binaries, and no classes implementing MTLRenderCommandEncoder are in Metal.framework (they're all in the individual drivers).

The stand-in command encoder used by the Metal frame capture API (e.g. if you run from Xcode) implements more methods than the underlying command encoder may, and will blindly forward them. So just checking if the command encoder has a method isn't enough, you have to call it from a @try {} to check if it throws an exception (or detect capture and api validation encoders and get their underlying encoders). (e.g. capture encoders have a setPointSize: in addition to the setLineWidth:, which seems to actually exist on Apple GPUs but nothing else)

If you really wanted to expose them in MoltenVK, you'd have to either individually whitelist/blacklist GPUs, or test each feature at runtime to ensure they actually work.

italomandara commented 2 years ago

Just a heads up: Just because the method is there, doesn't mean it works, or works well.

Some others I've found:

  • Intel Skylake GPUs and up support framebuffer fetch, but the GPU locks up if you try to use both that and dual source blending at the same time
  • MTLRenderPipelineDescriptor has things for logic ops, but I've only gotten it to work on Intel Skylake+ (AMD, Nvidia, and older Intel act like blending is disabled when you set those)

    Test script and results from an AMD and Intel GPU ...

I'd expect setLineWidth: to continue to exist as long as OpenGL does, at least on Apple GPUs, since I'm pretty sure they use it internally for the OpenGL → Metal translation layer, which is used for OpenGL support on Apple. I think it's not showing up there because protocols aren't emitted into binaries, and no classes implementing MTLRenderCommandEncoder are in Metal.framework (they're all in the individual drivers).

The stand-in command encoder used by the Metal frame capture API (e.g. if you run from Xcode) implements more methods than the underlying command encoder may, and will blindly forward them. So just checking if the command encoder has a method isn't enough, you have to call it from a @try {} to check if it throws an exception (or detect capture and api validation encoders and get their underlying encoders). (e.g. capture encoders have a setPointSize: in addition to the setLineWidth:, which seems to actually exist on Apple GPUs but nothing else)

If you really wanted to expose them in MoltenVK, you'd have to either individually whitelist/blacklist GPUs, or test each feature at runtime to ensure they actually work.

and maybe polyfill to "wideline -> triangles" emulation where missing?

billhollings commented 10 months ago

PR #2137 fixes this for wide lines.