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.74k stars 418 forks source link

MoltenVk still using intel card and not discrete GPU despite selecting discrete #418

Closed mlfarrell closed 5 years ago

mlfarrell commented 5 years ago

Noticed this last night and forgot to post.

No matter what I try, I simply cannot get my application to use the discrete (nvidia) GPU on my 2012 retina mac book pro. OpenGL would always just automatically switch. But with metal, it won't do it.

I'm creating the device with a physical device named "NVIDIA GeForce GT 650M", but can verify via gfxCardStatus (and the bad performance) that i'm on intel. It only works if I force discrete via the same gfxCardStatus utility.

I'm on macOS 10.13.6 To reproduce, build and run my repo's example project on a macbook with integrated+discrete GPU Note via gfxCardStatus that it doesn't switch to 'd'.

https://github.com/mlfarrell/VGL-Vulkan-Core

This one is critical for my application since on intel, its killing my performance (30 FPS).

mlfarrell commented 5 years ago

So this API call (MTLCreateSystemDefaultDevice) on the apple supplied metal examples triggers the graphics switch to occur properly. I notice molten vk does not call this on mac os. Is there an easy way we can detect if the GPU is indeed the "system default" and route the call through MTLCreateSystemDefaultDevice to ensure the graphics switch occurs properly? See documentation from apple below

/*!
 @brief Returns a reference to the preferred system default Metal device.
 @discussion On Mac OS X systems that support automatic graphics switching, calling
 this API to get a Metal device will cause the system to switch to the high power
 GPU.  On other systems that support more than one GPU it will return the GPU that
 is associated with the main display.
 */
MTL_EXTERN id <MTLDevice> __nullable MTLCreateSystemDefaultDevice(void) API_AVAILABLE(macos(10.11), ios(8.0)) NS_RETURNS_RETAINED;
mlfarrell commented 5 years ago

Fixed and tested on my fork. Haven't tested the integrated low power route. Will do that tomorrow. This brings me back to my old school ObjC days. Manual retain/release in 2018 - you guys are sadists :p

PR - https://github.com/KhronosGroup/MoltenVK/pull/420

billhollings commented 5 years ago

@mlfarrell

Have you tried inspecting the GPU activity with Apple's tools?

With MoltenVK (without your patch)...if I run an app that requests the high-power GPU (like the MoltenVK Hologram demo app) on my MacBook Pro...Apple's GPU tool shows the discrete GPU (AMD Radeon) spool up and run hard while the demo is running...and then spool down once the Hologram app is closed.

So...as far as I can tell...MoltenVK GPU selection is behaving as expected.

At the same time...the integrated Intel GPU still shows some activity (I assume from other windows).

All the while...gfxCardStatus shows i in the menu bar.

Are you using some special kind of GPU configuration (external, etc)?

mlfarrell commented 5 years ago

No special configuration.

Let me be clear. The nvidia GPU is indeed being used when I select it, however the critical "graphics switching" step on macbook pros like mine, is not triggered when you use a device returned from MTLCopyAllDevices, meaning the nvidia GPU is being somehow utilized to render offscreen, then the results are being transferred to the intel integrated GPU that is powering the display.

Let me paste the apple documentation below and you can see the critical verbiage regarding graphics switching.

/*!
 @brief Returns all Metal devices in the system.
 @discussion This API will not cause the system to switch devices and leaves the
 decision about which GPU to use up to the application based on whatever criteria
 it deems appropriate.
*/
MTL_EXTERN NSArray <id<MTLDevice>> *MTLCopyAllDevices(void) API_AVAILABLE(macos(10.11)) API_UNAVAILABLE(ios) NS_RETURNS_RETAINED;

Afaik, it is impossible to trigger the graphics switching step on a metal application without calling MTLCreateSystemDefaultDevice

When I run moltenvk without my fix, the macOS activity monitor on my mac shows "requires high performance graphics" field as "no". The 3rd party graphics switching utility called gfxCardStatus shows that my integrated card remains in use without switching.

With my above PR, the app startup delays a bit (as normal during a switch), gfxcardstatus utilty shows proper swicth to discrete, and the activity monitor field shows "yes" for the "requires high performance graphics" field for this application. More importantly, the performance of my application is drastically improved.

image

The above issue will affect everyone running molten VK applications on macs with dual GPUs.

billhollings commented 5 years ago

Okay. I think I understand the point you're raising now.

The graphics switching ensures that the system itself is converted to the GPU that is selected by MoltenVK. And as a result, the final system BLIT from the GPU used by the app to the GPU used by the system is not required.

Is that correct?

I'm curious...are there any other benefits/costs to enforcing graphics switching? Agreed that graphics performance is critical...and that's what we want...and why Vulkan was invented. But since your proposed solution forces the entire system to flip to the discrete GPU...I want to make sure there are no downsides that might cause us to perhaps make this step configurable in the MoltenVK configuration API.

In essence...there would seem to be three levels of GPU-based performance (lowest to highest)...

  1. Use integrated GPU for Vulkan rendering.
  2. Use discrete GPU for Vulkan rendering...but allow system to merge results onto integrated GPU for final display.
  3. Force discrete GPU for the entire system.

...and are there reasons why we might want to retain the middle option somehow?

PS - What an oblique API Apple invented with this! Talk about setting up a non-obvious side effect!

mlfarrell commented 5 years ago

The graphics switching ensures that the system itself is converted to the GPU that is selected by MoltenVK. And as a result, the final system BLIT from the GPU used by the app to the GPU used by the system is not required.

That's correct (or at least my understanding of how it works from an outside perspective)

The costs would be the slight delay on startup. In my experience, alongside the performance benefits, 99% of metal apps that aren't moltenvk (as it is today) and 99% OpenGL apps will behave this way, so it's good to follow the herd in this case.

2 is likely very useful for GPGPU computing and for other non-present non-graphics applications.

I do admit my solution my PR above isn't the most elegant (feel free to use it or some variant). My aim was to prevent the gfx switch from occurring for users who don't request that device.

billhollings commented 5 years ago

Okay. Makes sense.

Thanks for all the low-level detective work on this...and for the subsequent PR.

I just posted a review question on the PR. Once you've answered that...I'll pull the PR in.

I'm going to leave this issue open...until we've added a config to optionally turn off this behaviour to permit behaviour 2 above.

I will take care of that part as part of an update to the config features.

mlfarrell commented 5 years ago

No problem, glad to help!

billhollings commented 5 years ago

PR #450 adds config setting for GPU switching and enables it by default