Fullscreen and HDR: Windows' window rules from Wine, HDR10 from the Mac's own EDR
D3D12 games on the Mac layer can now go exclusive fullscreen and output HDR10 or scRGB, which macOS shows as extended dynamic range on an XDR screen; Wine's own DXGI conformance test now runs against the layer.
What changed
The layer now implements the two DXGI features a game touches before it draws anything: fullscreen and HDR. DXGI is the part of Direct3D that owns windows, displays and swap chains (the chain of images a game draws into and shows).
Exclusive fullscreen. SetFullscreenState restyles the game's window, stretches it over a display and may change the display mode. None of that involves Metal, and Wine's own Direct3D (wined3d) already does it, so I ported wined3d's window-state code (LGPL, like this project). To check it, I built the Direct3D 12 half of Wine's DXGI conformance test (dxgi.c) as a new test suite, one test function per process. The test expects what Windows does, which differs from wined3d in the window styles. The layer follows Windows. 16 of its 20 tests pass. The other 4 fail for reasons outside the layer: one needs Direct3D 10, one runs into a Wine assertion, one expects Windows' compositor to report other windows covering the fullscreen one, and one hits a Wine cursor race.
HDR. macOS does HDR as EDR (extended dynamic range): a Metal layer tagged with an HDR colour space may show values brighter than SDR white, up to the screen's headroom (16× on the built-in XDR panel). So each DXGI colour space is a layer set-up (see the diagram):
- sRGB stays SDR.
- scRGB (linear half-float) uses the extended linear sRGB colour space.
- HDR10 (10-bit PQ, BT.2020) uses the ITU-R 2100 PQ colour space.
The game's HDR10 mastering metadata becomes Core Animation's CAEDRMetadata, so macOS tone maps as a TV would. GetDesc1 reports each display's peak as 100 nits times its headroom: 1600 nits on the XDR panel.

The interesting part
One Wine test, test_swapchain_present, hung now and then just after entering fullscreen. The Wine debugger put the test thread in ShowWindow of a second window. The Mac's main thread, which does all of Wine's window work, was idle, and two AppKit animation threads were waiting.
Earlier the test minimizes the window and restores it at once. With Wine's driver trace on, the "did minimize" events arrived 2.5 s later, after the window had gone fullscreen: the minimize animation was still running. A 30-line program that makes the same window calls, with no Direct3D at all, hangs at the same line in 1 or 2 of 16 runs. So the bug is in Wine's Mac driver, not the layer, and the repro is in the repository.
Numbers
- Full run: 835 pass, 28 fail, 76 skip of 939, up from 818 of 918. Nothing newly failing. The new tests are api/hdr_colour_space and the 20 wine-dxgi tests.
- The HDR test preview: grey steps at 1, 10 and 99 nits in the PQ ramp come out as 26, 89 and 254 in the SDR preview. That is what sRGB encoding gives for 0.01, 0.1 and 0.99 of white.
- The hang: 6 of 8 runs of the full test before the HDR work, 4 of 8 after, and 1 or 2 of 16 runs of the repro without Direct3D.
I have not yet looked at the HDR output on the XDR panel myself: the test runs are unattended. The numbers above come from the layer's drawable read back, not from the screen.
- pass
- fail
- skip
suite · share of each row's total
- vkd3d-proton490 pass, 15 fail, 72 skip of 577
- vkd3d177 pass, 9 fail, 4 skip of 190
- apps77 pass, 0 fail, 0 skip of 77
- api (+1)71 pass, 0 fail, 0 skip of 71
- wine-dxgi (+16)16 pass, 4 fail, 0 skip of 20
- samples4 pass, 0 fail, 0 skip of 4