KhronosGroup / KhronosGroup/Vulkan-Docs
[Roadmap Feedback] VK_KHR_present_wait needs more return values
- Dominant language
- JavaScript
- Stars
- 3.3k
- Forks
- 549
- Avg merge
- 5d 5h
- Merged PRs (30d)
- 2
Description
## Problem statement:
`VK_KHR_present_wait` added `vkWaitForPresentKHR` to wait until a specific swapchain is presented.
This works fine for fullscreen games, but it has problems for non-game applications; such as a Game Engine Editor or other windowed scenarios.
The problem is that on Windows 11 on NVIDIA, a fully occluded window will timeout (or stall indefinitely if timeout is unlimited) and return `VK_TIMEOUT`. This is not a driver bug. The driver should not be returning from `vkWaitForPresentKHR` when the swapchain hasn't been presented. It's working as intended.
This happens because on Windows, drivers are using DXGI under the hood which follows this behavior.
More specifically, [IDXGISwapChain::Present](https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-present) method has a `DXGI_STATUS_OCCLUDED` return value to signal this scenario.
Furthermore DXGI provides `RegisterOcclusionStatusWindow` to signal when occluded status changes and we should probe again to see if we can present again.
A battery-friendly D3D11/12 loop is meant to be written like this (pseudo code):
```cpp
void main()
{
m_occluded = false;
while(true)
{
if( m_occluded )
{
Sleep(100);
}
else
{
render();
HRESULT hr = swapchain->Present();
if( hr == DXGI_STATUS_OCCLUDED )
{
m_occluded = true;
dxgi->RegisterOcclusionStatusWindow( hWnd, WM_USER, &m_occlusionCookie );
}
}
while (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE) && (message.message != WM_QUIT))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
}
}
// Called in WM_USER. Unfortunately DXGI does not tell us if occlusion is now true or false.
// It only tells us it may have changed.
void OnOcclusion()
{
assert( m_occlusionCookie );
if (S_OK == swapchain->Present(0, DXGI_PRESENT_TEST))
{
dxgi->UnregisterOcclusionStatus(m_occlusionCookie);
m_occlusionCookie = 0;
m_occluded = true;
}
}
```
## Use Case Example(s):
Any app that isn't fullscreen (e.g. a Game Engine Editor) will run into this scenario as soon as the user Alt+Tabs to another window from a different process and the window happens to 100% occlude our window.
Ticket #2507 also makes an excellent point. On Linux, turning off the monitor should mean that Vulkan implementation should return `VK_SWAPCHAIN_OCCLUDED`.
## Suggested Solution(s) (via opening an MR on vulkan-docs repo and creating a Proposal Document) :
- Add a result value "VK_SWAPCHAIN_OCCLUDED" to `vkWaitForPresentKHR`, that returns as fast as possible, instead of returning VK_TIMEOUT (or deadlocking indefinitely). Other OSes who do not support this would simply never return this value.
- Of course there are details to this, since the app must opt-in to this new behavior otherwise old applications will get a return value that they're not expecting.
- Add a routine for testing for occlusion (i.e. analogous to `DXGI_PRESENT_TEST`). vkTestPresentOcclusion( swapchain ); which can return "VK_SWAPCHAIN_OCCLUDED" or `VK_SUCCESS`. Other OSes who do not support this would simply always return `VK_SUCCESS`.
- Add a routine where users can register a listener whenever occlusion changes, to avoid polling vkTestPresentOcclusion() continuously.
Contributor guide
Research direction
No repository files or tests are named. Start by reviewing the VK_KHR_present_wait specification and the referenced issue #2507, then examine the Vulkan-Docs proposal process. Done means producing a decided proposal document and corresponding vulkan-docs MR covering the requested occlusion results, testing routine, and listener registration.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend-api-design, operating-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100