D3DMetal: present hangs permanently when the game window becomes occluded

Environment

  • macOS 27.0.1 (26A434), Apple M4 Pro
  • Apple Game Porting Toolkit 4.0b2 (D3DMetal.framework) via CrossOver 27
  • D3D12 game, borderless fullscreen window (2540x1650)

Symptom
When the game window becomes occluded — Mission Control, a system OSD
(volume/brightness), or another window being brought to the front — the game
never renders another frame. It does not crash: GPU utilization drops to 0%,
the process stays alive with near-zero CPU, and it never recovers. Killing and
restarting the game is the only way out.

D3DMetal log at the moment it happens:
[D3DMetal:FATAL:%llX][%s:%d] Failed to get drawable for HWND. Run with D3DM_NO_WINDOW=1 env.

Question

  1. When CAMetalLayer/nextDrawable has no drawable (window not visible), is there
    a supported way for D3DMetal to skip frames instead of blocking forever?
  2. Is there an environment variable or configuration that makes D3DMetal treat
    "no drawable" as a recoverable condition?
  3. Does D3DM_NO_WINDOW=1 apply here, or is it only for headless/offscreen use?

I understand apps should handle a nil drawable and continue, but this path is
inside D3DMetal. Any guidance would help.

Answered by DTS Engineer in 913722022

Thanks for the detailed environment and the exact log line.

When code calls nextDrawable() directly, it waits up to one second for a drawable and then returns nil. Setting allowsNextDrawableTimeout to false makes it wait indefinitely instead. How D3DMetal handles a nil drawable isn't documented, so I can't point to a supported way to make it skip frames.

The Read Me in the evaluation environment for Windows games lists the environment variables it supports. The 4.0 beta 3 Read Me lists five, and none of them addresses a missing drawable or an occluded window. D3DM_NO_WINDOW isn't among them, so I can't say what it does or whether it applies here.

One documented variable is still worth testing. The same Read Me says D3DMetal uses its Metal 4 backend by default in macOS 27. Setting D3DM_MTL4=0 switches to the Metal 3 backend. Running with D3DM_MTL4=0 shows whether the hang depends on the Metal 4 backend.

The Read Me asks that problems go through Feedback Assistant, and that you "attach and send the full logs without filtering to D3DM." Please file a report with the steps that cause the hang, the full log, and a sysdiagnose captured while the game is hung. Please also include the result with D3DM_MTL4=0 and, if you can, the result with 4.0 beta 3. Profiles and Logs has the macOS sysdiagnose instructions, and Bug Reporting: How and Why? has tips on creating your report. Please post the Feedback number here.

Thanks for the detailed environment and the exact log line.

When code calls nextDrawable() directly, it waits up to one second for a drawable and then returns nil. Setting allowsNextDrawableTimeout to false makes it wait indefinitely instead. How D3DMetal handles a nil drawable isn't documented, so I can't point to a supported way to make it skip frames.

The Read Me in the evaluation environment for Windows games lists the environment variables it supports. The 4.0 beta 3 Read Me lists five, and none of them addresses a missing drawable or an occluded window. D3DM_NO_WINDOW isn't among them, so I can't say what it does or whether it applies here.

One documented variable is still worth testing. The same Read Me says D3DMetal uses its Metal 4 backend by default in macOS 27. Setting D3DM_MTL4=0 switches to the Metal 3 backend. Running with D3DM_MTL4=0 shows whether the hang depends on the Metal 4 backend.

The Read Me asks that problems go through Feedback Assistant, and that you "attach and send the full logs without filtering to D3DM." Please file a report with the steps that cause the hang, the full log, and a sysdiagnose captured while the game is hung. Please also include the result with D3DM_MTL4=0 and, if you can, the result with 4.0 beta 3. Profiles and Logs has the macOS sysdiagnose instructions, and Bug Reporting: How and Why? has tips on creating your report. Please post the Feedback number here.

Filed as FB25396997, with a sysdiagnose captured while the app was frozen.

Additional data point requested above: I re-ran the same test with D3DM_MTL4=0 (Metal 3 backend) and the window freezes in exactly the same way — the process stays alive (~5-6% CPU) but no new frames are presented, and it never recovers. So the hang does not depend on the Metal 4 backend.

Attached to the Feedback report: full Wine/UE log of the frozen run, UE client log, a sample taken while frozen, and the sysdiagnose.

One remaining question: in an older build the log contained
[D3DMetal:FATAL] Failed to get drawable for HWND. Run with D3DM_NO_WINDOW=1 env.
but D3DM_NO_WINDOW is not in the GPTK 4.0b3 documented environment variables. Could you confirm whether it is a supported workaround for an occluded window, or whether it is only intended for headless use? Thank you.

Thanks for filing FB25396997, and for testing D3DM_MTL4=0 and capturing a sample of the frozen process. The Metal 3 result shows the hang doesn't depend on the Metal 4 backend.

D3DM_NO_WINDOW isn't in the 4.0 beta 3 Read Me. I can't confirm whether it's a supported workaround for an occluded window or meant only for headless use. The suggestion to use it comes from the D3DMetal log itself, so please add that question to FB25396997. That keeps the question together with your logs.

Please continue to test your software in release and pre-release versions of system software made available to you through your developer.apple.com account. When you do, add details about that into your bug report to keep it up to date. Please see developer.apple.com/download.