The bug was in the compiler, and a semaphore that never made anyone wait
A path tracer drew black because Wine's HLSL compiler dropped one conversion, not because of the layer; and the DXGI frame-latency object now actually paces games.
What changed
Three more Diligent Engine samples (Tutorial26, Atmosphere, Shadows) were supposed to need only an optional build component. With it built, all three still failed. The cause was the shader compiler, not the layer, so they stay out of the suite and the lean build stays.
The second change is pacing. With DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT, a game gets a semaphore (a counter that a thread can wait on until it is above zero) and waits on it before each frame. DXGI should release it only when an earlier frame has left the queue. We released it the moment Present returned, so the game never waited. Now a dxgi thread waits until the present has finished on the GPU, then releases it.

The interesting part
Tutorial26 is a small path tracer. Through the layer it drew a black frame with only the ceiling light. Diligent's D3D12 backend compiles HLSL with FXC, the old compiler that makes DXBC bytecode, and under Wine that is Wine's own reimplementation. With Microsoft's DXC (which makes DXIL) selected by a local edit, the same layer drew the right picture. So the fault was on the DXBC path. Bisecting the shader showed the clip position was always (-1, 1).
Before debugging our DXBC translation, I compiled the shader with the Wine prefix's compiler and read the bytecode (tools/wine_hlslc.c). The float2(XY) conversion from unsigned integers was missing whenever the same XY also fed a texture Load. The integer bits were then read as float, which gives tiny denormals, so every pixel mapped to the corner. An 8-line repro is in the note. Games ship bytecode from Microsoft's compiler, so this is not ours to fix. The lesson is to look at the bytecode first.
The review of the latency change found a real hang. Present waited for the GPU to finish the present three frames back, so it could reuse that frame's command allocator. If the application had made the queue wait on a fence it had not signalled yet, a fourth present waited forever for work that could not start. Wine's own DXGI test does exactly this. Now the whole present is encoded when the queue reaches it, so Present never waits for the GPU.
Numbers
- Full run: 774 pass, 27 fail, 108 skip of 909, against 773 of 908 in entry 038. 0 newly failing; the one new pass is the new test api/frame_latency.
- api/frame_latency holds 5 presents behind one queue wait. Before the fix it hung in
Present(a timeout, with the stack inwaitUntilSignaledValue).
- pass
- fail
- skip
suite · share of each row's total
- vkd3d-proton455 pass, 18 fail, 104 skip of 577
- vkd3d177 pass, 9 fail, 4 skip of 190
- apps77 pass, 0 fail, 0 skip of 77
- api (+1)61 pass, 0 fail, 0 skip of 61
- samples4 pass, 0 fail, 0 skip of 4