Skip to content

Add Metal support for macOS (arm64) and iOS#88199

Merged
clayjohn merged 1 commit into
godotengine:masterfrom
stuartcarnie:metal-rdd
Aug 21, 2024
Merged

Add Metal support for macOS (arm64) and iOS#88199
clayjohn merged 1 commit into
godotengine:masterfrom
stuartcarnie:metal-rdd

Conversation

@stuartcarnie

@stuartcarnie stuartcarnie commented Feb 11, 2024

Copy link
Copy Markdown
Contributor

This PR introduces initial support for a Metal rendering device driver for macOS (arm64) and iOS.

I added metal=yes to the builds to ensure the code is compiled as part of CI

Edit: metal is enabled by default on macOS and iOS, so also included on CI.

Summary

This PR adds native Metal support to Godot for macOS and iOS. Metal is Apple's native graphics API for all its platforms. DirectX is to Windows, as Metal is to macOS, iOS and tvOS.

Bistro Demo screenshot Screenshot of the Bistro demo rendered using the Metal rendering device driver

Supported Features

This initial implementation should support all of Godot's 2D and 3D features, except multiple viewports.

Known Issues

  • The Visual Profiler and GPU frame times are not supported, as Godot's timestamp-based timing mechanism is not compatible with TBDR GPUs like Apple's M-series and mobile GPUs. Apple GPUs can reorder render passes based on input and output dependencies.
  • Multiple viewports are not supported, but will be in the future

Instruments, Xcode and profiling

Apple developers may be familiar with Instruments and Xcode's Metal debugging tools. We want to make sure that you have a good experience with these tools when developing with Godot.

Xcode frame debugging

The Metal RenderDeviceDriver utilises MTLCaptureScopes to create a Godot Frame for accurate frame boundaries, to simplify your experience in Xcode:

Render passes are also labeled, so you can visualise and understand where your frame costs are:

CleanShot 2024-08-27 at 08 36 49@2x

Instruments

As expected, you can use Instruments to profile your games. We plan to enhance the experience using signposts, so you can get accurate statistics about different parts of the Metal render driver. Once such example is shader compilation:

CleanShot 2024-08-27 at 08 49 13@2x

This image is showing all the shaders that were compiled to run the Bistro demo under the Godot editor.

Note

The macOS Metal shader cache for Godot was cleared, so this is worst-case.

FAQ

Can I still use Vulkan for my projects?

Metal is the default rendering driver for Apple platforms, as it should perform as well or better than the current MoltenVK / Vulkan implementation. However, if you want to use Vulkan via MoltenVK, you can by following these steps:

  • Open Project Settings

  • Enable Advanced Settings

  • Select Rendering Device

  • Choose vulkan for your target Apple platform

    CleanShot 2024-08-27 at 07 12 59@2x

Can I still launch the Godot editor with Vulkan?

Yes, you can launch the editor using your terminal and launching Godot from your project directory, specifying metal or vulkan for the rendering-driver argument. The following, with the --editor argument, will launch the Godot editor:

<path to Godot>/Godot.app/Contents/MacOS/Godot --rendering-driver vulkan --editor

Note

If you want to launch the game with a specific driver, drop the --editor flag.

@AThousandShips AThousandShips changed the title feat: Metal support for macOS (arm64) and iOS Metal support for macOS (arm64) and iOS Feb 11, 2024
Comment thread doc/classes/OS.xml Outdated
Comment on lines 763 to 807

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this to be consistent with RENDERING_DRIVER_D3D12, but I don't see how this is used anywhere.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These don't seem used anywhere indeed, we could flag this enum as deprecated.

It used to be used in 3.x for OS::get_current_video_driver() (7a79eee), and was refactored for 4.x in f82deaa, but the API that used it no longer exists. I'm not sure what replaced it in 4.x, CC @Calinou.

We also have this piece of dead code to remove eventually:

editor/plugins/node_3d_editor_plugin.cpp
5339:   //if (OS::get_singleton()->get_current_video_driver() == OS::RENDERING_DRIVER_OPENGL3) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what replaced it in 4.x, CC @Calinou.

We seem to have:

core/os/os.h:
        String get_current_rendering_driver_name() const { return _current_rendering_driver_name; }
        String get_current_rendering_method() const { return _current_rendering_method; }

but not exposed to scripting.

@Calinou Calinou Aug 18, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a PR to expose these: #85430

It's awaiting review (specifically about moving it from OS to Engine). It's not exposed currently, so moving it doesn't break compatibility.

Comment on lines 71 to 73

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove a series of deprecated warnings when building for newer macOS SDKs

Comment thread drivers/metal/SCsub Outdated
Comment on lines 6 to 7

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to use exceptions for this code as SPIRV-Cross uses them to communicate errors when parsing SPIRV or compiling SPIRV to Metal. The alternative is that it asserts and terminates the process.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually try to patch out exceptions from the third-party code instead, but it's probably ok in this case (it's always possible to do it later, if we want to), disabling exceptions is only important for the Web.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good – fortunately, we don't need SPIRV-Cross for Web so hopefully that is ok for the short term. I can look at how complex it might be to remove exceptions in a subsequent PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this related to this? Should be in a separate PR if it's not specifically because of the metal changes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It generates a number of warnings when compiling for arm64 with Metal enabled – happy to remove it, but it was a lot of noise.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as it's from this specific change then it's fine :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion would be to split this into a separate PR and merge it. It seems like an unrelated change even if it is triggered by the Metal build.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree a separate PR with that fix could be good, so we can also backport it to 4.3.x.
It's likely that this kind of deprecation warning will find its way even in non-Metal builds, I'm not sure why Metal specifically would enable it.

Comment thread main/main.cpp Outdated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generates a warning, as CFBundleSignatures can only be 4 characters

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest splitting the changes to that file to a separate PR, as it seems like things we'd need regardless of Metal.

Comment thread modules/spirv_cross/SCsub Outdated
Comment on lines 33 to 35

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted elsewhere, SPIRV-Cross requires exceptions, otherwise any errors parsing SPIRV or generating Metal source aborts.

Comment thread servers/rendering/rendering_device.cpp Outdated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope these are ok, as I noticed the loops weren't exiting after they found the index

Comment thread modules/camera/camera_macos.mm Outdated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated these to remove some compiler warnings for newer SDKs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could also be merged (maybe together with the coreaudio change) independently of the Metal backend.

@akien-mga akien-mga Aug 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I'd prefer these in a separate PR. They could even have been merged for 4.3 instead of waiting for the 4.4 dev cycle for a big feature like Metal.

@bruvzg bruvzg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only acceptable reasons to bump min. supported OS version are:

  • latest Xcode no longer support it (currently 10.12 is oldest supported one).
  • it's absolutely unusable due to core changes.

Comment thread misc/dist/macos_tools.app/Contents/Info.plist Outdated
Comment thread modules/camera/camera_macos.mm Outdated
Comment thread platform/macos/detect.py Outdated
Comment thread platform/macos/detect.py Outdated
Comment thread drivers/metal/metal_device_properties.mm Outdated
@stuartcarnie stuartcarnie force-pushed the metal-rdd branch 8 times, most recently from 8bcdb01 to 07bb489 Compare February 12, 2024 05:58
@stuartcarnie stuartcarnie marked this pull request as ready for review February 12, 2024 19:28
@stuartcarnie stuartcarnie requested a review from a team as a code owner February 12, 2024 19:28
Comment thread thirdparty/README.md Outdated
Comment on lines 842 to 843

@akien-mga akien-mga Aug 20, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't Vulkan SPIR-V generated via our copy of glslang (which we sync with other Vulkan SDK components)? That would still be a justification IMO to at least try to keep them in sync, as Khronos typically only supports all components being on the same known_good.json versions, which is best tracked via Vulkan SDK tags in my experience.

@stuartcarnie stuartcarnie Aug 20, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is correct - we use SPIRV-Cross to consume the SPIR-V generated from Godot's glslang and to transform it to Metal source files. Those shouldn't need to match, as it is only used as a code generator. Newer versions of the SPRIV-Cross code have fixes when producing Metal source that we want, particularly for iOS.

@akien-mga

akien-mga commented Aug 20, 2024

Copy link
Copy Markdown
Member

I added a second commit to do some tweaks directly, to be squashed in the main commit after review and testing.

Changes:

  • Enable metal by default as discussed. To avoid getting an annoying warnings on x86_64 when building with default options, I changed the message when falling back to metal=no to a comment. It's not uncommon that some options are just no-op if used on the wrong platform (e.g. using metal=yes on Linux would do nothing).
    • metal is still off by default in SConstruct to avoid enabling it on all platforms, which currently leads to compilation errors. So I've enabled it specifically in the macOS and iOS get_flags. d3d12 has the same problem, I'll rework this later on to make it more flexible.
  • Tweaked drivers/metal/SCsub to remove some duplicates/redundant instructions and streamline the format to match other SCsubs.
  • Fix up some includes further, there were a number of unused includes, and missing lines in .mm files after the "main" include: https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html#header-includes

I did these changes from Linux, please confirm that it still works as expected on macOS.

@akien-mga

akien-mga commented Aug 20, 2024

Copy link
Copy Markdown
Member

I extracted the fixes to Xcode compiler warnings to a separate PR: #95854.
This PR is rebased on top of that commit to still include the fixes.

Edit: I'm done force-pushing tweaks, 84201ef can be reviewed.

@stuartcarnie

Copy link
Copy Markdown
Contributor Author

@akien-mga I reviewed 84201ef and it looks great – thank you!

@akien-mga akien-mga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great to me!

@passivestar

passivestar commented Aug 20, 2024

Copy link
Copy Markdown
Contributor

I noticed that it's taking significantly more time to open a new project with this PR compared to the current master

Master: ~5 seconds
This PR: ~12 seconds or more

I'll test with non-empty projects too


Edit: The bistro scene opens in ~30 seconds with both Vulkan and Metal, however the Metal version actually freezes after the editor opens and it's becoming completely uninteractable with the "wait" cursor for a solid 40 seconds or so. Noticed that something was off yesterday but wanted to confirm that it's not some other PR's fault first

If this is to be merged in its current state I'm afraid I'll need the metal=yes back or some other easy way to disable it because it would significantly hinder my ability to test new PRs

@akien-mga

Copy link
Copy Markdown
Member

I confirmed that this builds fine with osxcross on our official buildsystem.

Here's a test build from this PR for macOS and iOS:
https://downloads.tuxfamily.org/godotengine/testing/4.4-dev-metal/

If this is to be merged in its current state I'm afraid I'll need the metal=yes back or some other easy way to disable it because it would significantly hinder my ability to test new PRs

You can disable it with metal=no.

@passivestar

Copy link
Copy Markdown
Contributor

You can disable it with metal=no

ah ok then

@bruvzg bruvzg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be working fine.

I do not get significant difference between Vulkan and Metal startup times (for a relatively small project, both are about 4-5 sec, only the first start with cleaned shader cache seems to be few seconds slower).

@passivestar

Copy link
Copy Markdown
Contributor

I do not get significant difference between Vulkan and Metal startup times (for a relatively small project, both are about 4-5 sec, only the first start with cleaned shader cache seems to be few seconds slower).

Give this one a shot when you have time

@bruvzg

bruvzg commented Aug 20, 2024

Copy link
Copy Markdown
Member

Give this one a shot when you have time

Metal Vulkan
Editor UI visible 8 sec 6 sec ~45 sec for a first start on both
Scene visible 25 sec 40 sec
Scene usable 40 sec (laggy) never (crashes after few minutes)

@stuartcarnie

Copy link
Copy Markdown
Contributor Author

@passivestar you can also switch drivers using the CLI:

--rendering-driver metal|vulkan

You will need to open the project directly from the shell to do that. The easiest way is to change to the project directory and launch Godot with the --rendering-driver metal --editor combination

@clayjohn

Copy link
Copy Markdown
Member

I am very happy to finally merge this. The work you have been doing is excellent and is going to benefit a lot of people. Let's sneak this in before dev 1 so we can get lots of early testing this release cycle!

@stuartcarnie

Copy link
Copy Markdown
Contributor Author

@passivestar I've found the difference between MoltenVK and our Metal renderer in Godot, and I expect to be able to significantly reduce that initial compilation time.

Going to prototype it tomorrow and push up a PR

@stuartcarnie

Copy link
Copy Markdown
Contributor Author

@passivestar / @bruvzg I have some very dramatic improvements to shader compilation, which are addressed in #96052

@eimfach

eimfach commented Aug 27, 2024

Copy link
Copy Markdown

How can I enable metal support for intel based mac for testing ? I have one.

@dsnopek

dsnopek commented Aug 27, 2024

Copy link
Copy Markdown
Contributor

@eimfach There's PR #96158 which aims to add support for this. You could help to test it?

@NatanAmorim

Copy link
Copy Markdown

How can I enable metal support for intel based mac for testing ? I have one.

@eimfach You can't, he already talked about this here #88199 (comment)

@MileyHollenberg

Copy link
Copy Markdown
Contributor

Hey there, found a small bug in this PR when trying to build the iOS simulator templates, this line https://github.com/godotengine/godot/blob/master/drivers/metal/pixel_formats.mm#L1203 uses mtlDevice rather than p_device and thus causes a compiler error when trying to compile via scons p=ios target=template_debug ios_simulator=yes arch=arm64 as mtlDevice doesn't exist in this scope. When changing it to p_device it fully compiles again.

@stuartcarnie

Copy link
Copy Markdown
Contributor Author

Hey there, found a small bug in this PR when trying to build the iOS simulator templates, this line https://github.com/godotengine/godot/blob/master/drivers/metal/pixel_formats.mm#L1203 uses mtlDevice rather than p_device and thus causes a compiler error when trying to compile via scons p=ios target=template_debug ios_simulator=yes arch=arm64 as mtlDevice doesn't exist in this scope. When changing it to p_device it fully compiles again.

Hey @MileyHollenberg – thanks for spotting that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.