-
Notifications
You must be signed in to change notification settings - Fork 469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TOCTOU race condition on minImageExtent/maxImageExtent? #1144
Comments
practically a dup of more general #388. Hopefully it gets prioritized though. |
FWIW I sent a patchset to mesa that makes it return SUBOPTIMAL in the case of this "race condition". (That patchset also tried changing the min/max extent as per my recommendation, but they correctly pointed out that the current spec forbids this) (Side note: OUT_OF_DATE seems like an excessively harsh error to return for size mismatches. Using SUBOPTIMAL instead allows applications to handle resizes much more smoothly and gracefully) Simply removing the validation check, combined with the above patchset, allows this to be a non-issue in practice - but the theoretical problem remains (as tracked by #388). |
Depends what you mean by "gracefully". There would be artifacts if the framebuffer size does not match the window. They intentionally removed that possibility in spec on some platforms, because the output is practically useless(, though theoretically it is possible to present into it, I think). The expectation of The idea is that you get the
Then the spec only needs to state the obvious that the window size can change at any time in platform specific manner. |
In practice, the artifacts of framebuffer size mismatch are maybe a few pixels of lost content / black borders here and there (usually on the border you're resizing from), whereas the artifacts of excessive swapchain recreation is the entire window becoming visually frozen while resizing. It's possible to become so insistent on only rendering 'perfect' images that you end up not rendering anything at all. A few pixels of artifacts here and there are much more graceful than great swathes of unupdated, corrupted framebuffer contents that are the typical result of a failure to repaint in a timely fashion. |
Black frame can actually be better than a mangled image in an unspecified way... |
Yes, as-stated that's racy and impossible to actually satisfy reliably in the middle of a resize. I believe the way this should have been spec'd and the way you should have interpreted it is something more like this:
That may not be quite precise enough for spec text but I think it's pretty close and carries the intent. |
The new VK_EXT_surface_maintenance1 and VK_EXT_swapchain_maintenance1 extensions address this issue. Please see this blog post for a summary. However, leaving this open due to this remaining issue:
It would still be good to have |
@ShabbyX Can you elaborate what has changed here? The spec still explicitly says that all the extents must equal window size on win32 and Xlib\XCB platforms. |
The spec says:
And in the note below says:
You can then take a look at the
(note: there's currently a typo in the spec where some places say |
@ShabbyX Notes are only informative, so that would imply nothing has changed. If the extents are required to always be equal to window's size, then that implies they are unable to differ from the window size. |
Yes, that's the way window systems work. You have to create your swapchain the same size as the window. On some platforms like android, the window-system auto-scales but on most platforms you just get garbage or clipping or something. There's nothing that Khronos can do about that by writing spec text nor should the window systems necessarily change either. The only real problem here is that for a while it was in the VUs which technically means that the driver can segfault on you or something like that. That's obviously too harsh for this particular case. Worst case, you should get Yes, that means that you have to keep re-creating the swapchain until things settle. Again, this is nothing new and it's not something that we can fix. This is the way window systems have worked for decades. It's just that, with Vulkan, this loop is exposed to the client because it is manually managing swapchains instead of the driver re-creating them under the hood as-needed.
I'm not convinced we want to do that. It'll only mean additional round-trips to the compositor to check the size at swapchain creation time and still doesn't fix the race because the window can still resize between swapchain creation and the first present. |
The notes just guide you towards the "solution" of VkSwapchainPresentScalingCreateInfoEXT. You have to go read up on that structure to see how it can be used to avoid the need to recreate your swapchain if you're happy with some well-defined scaling/centering behavior instead, assuming the driver + platform you're running on supports such scaling. The spec doesn't currently require support for scaling. Other than that, as @gfxstrand says, there's nothing magic drivers can or should do here. Handling window resizes well is hard, and the driver can only do a worse job of it if you try to hide the handling in there compared to what a well-written application can do, at least if they're using the other mechanisms from [swapchain/surface]_maintenance1 aimed at making swapchain recreation a better-defined and lower-overhead workflow.
I've waffled on this quite a bit, but I do come down in favor of allowing vkCreateSwapchainKHR to return this error code now. There are many cases where we already know the sizes mismatch without a round trip, and we have to just create an empty shell of a swapchain and wait until someone tries to acquire from it to return an error. This also provides a sensible error code to replace the need for the impossible VUs saying various properties must match a moving target, like window sizes, fullscreen/non-fullscreen-only present modes, etc. |
Oh, ok, so the VU was changed. And I see there's a separate set of min and max caps. To make this distinction clear, perhaps the
PS: Are these new values |
Some platforms, like Xcb/Xlib/Win32, require that
minImageExtent == maxImageExtent == currentExtent
. However, this creates some problematic race conditions in practice.The problem, specifically, is that the window's extent can change (e.g. due to the window manager) in between the calls to
vkGetPhysicalDeviceSurfaceCapabilitiesKHR
andvkCreateSwapchainKHR
. When this happens, we might end up creating a swapchain with animageExtent
that is outside of the bounds of the permittedmin/max
at the time of the actual swapchain creation. As far as I can tell, this is technically undefined behavior? (In practice, one of the validation layers likes to error out on swapchain creation, so this is not just a theoretical concern - we have to work around it by suppressing errors related to swapchain creation from that validation layer).Even ignoring split second race conditions, I'm not sure how a field like
minImageExtent
ormaxImageExtent
being "dynamic" is supposed to make sense at all. The specification forvkCreateSwapchainKHR
only says:but the fact that
minImageExtent
andmaxImageExtent
can change over time means this wording is vague. There's no clear link between any particular call tovkGetPhysicalDeviceSurfaceCapabilitiesKHR
and the actual swapchain creation.Obviously the intent was to mean "at the time of swapchain creation", but this leads back into aforementioned race condition, because there's always going to ba delay in between those two calls.
I'm also not sure what purpose this design is supposed to serve. There's nothing stopping users from making swapchains with the "wrong" size, either in practice or in theory. In fact, doing so can sometimes be beneficial. The obvious solution to me would be to remove the
min == max == current
assumption and just havemin
andmax
always represent the (unchanging) hardware capabilities on all platforms.The text was updated successfully, but these errors were encountered: