I managed to figure this one out eventually.
Seemingly on nvidia GPU systems the SetSignal API doesn't do anything and instead a bunch of what is done via the WinRT APIs is in fact done by NvAPI. Testing on an intel system the APIs worked as I would have expected
It does however require a pro-range GPU that supports their PresentBarrier feature
Rough steps:
- Remove the display from desktop into a "Managed" state using https://www.nvidia.com/en-gb/drivers/ddisplay-utility/
- Sample App needs to be updated to use Dx12 / 11on12
- Enumerate Dedicated displays using NvAPI_DISP_GetNvManagedDedicatedDisplays
- Acquire displays NvAPI_DISP_AcquireDedicatedDisplay
- Open the shared handle from acquiring the display as IDisplayDeviceInterop and then convert to a winrt::DisplaySource
- Get display info for acquired display using NvAPI_Disp_GetDisplayIdInfo
- Find the matching winrt Target of that display by using winrt::DisplayManager::GetCurrentTargets() and comparing the NV_DISPLAY_ID_INFO_DATA adapterId, targetId with the DisplayTarget adapter LUID & AdapterRelativeId
- Create Primary instances using matched DisplayTarget
- Create scanout instances using interopped DisplaySource
- Create a present barrier using NvAPI_D3D12_CreateDDisplayPresentBarrierClient DisplaySource::SourceId()
- Create D3D12 fences and pass them to NvAPI_D3D12_RegisterPresentBarrierResources
- Join the present barrier NvAPI_JoinPresentBarrier
- Those fences can now be waited on using SetEventOnCompletion
- When the app is done - make sure you release the display NvAPI_DISP_ReleaseDedicatedDisplay
Microsoft support were unable to give any further answers as to whether this is expected as the D3D team did not respond to their enquiries - but seemingly this is the way it's done on nvidia