Skip to content
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

SDL_Vulkan_GetDrawableSize() off while drag-resizing window #3287

Closed
SDLBugzilla opened this issue Feb 11, 2021 · 0 comments
Closed

SDL_Vulkan_GetDrawableSize() off while drag-resizing window #3287

SDLBugzilla opened this issue Feb 11, 2021 · 0 comments

Comments

@SDLBugzilla
Copy link
Collaborator

This bug report was migrated from our old Bugzilla tracker.

Reported in version: 2.0.9
Reported for operating system, platform: Linux, x86_64

Comments on the original bug report:

On 2019-06-17 22:44:46 +0000, wrote:

When creating a swapchain I use SDL_Vulkan_GetDrawableSize() to get information for the extent immediately before calling vkCreateSwapchainKHR(). This works fine until I drag-resize the window. When I drag-resize the window I tear down my swapchain and build it again calling SDL_Vulkan_GetDrawableSize() many times as I drag, but the validation layers start giving out messages like these:

vkCreateSwapchainKHR() called with imageExtent = (1194,720), which is outside the bounds returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (1102,720), minImageExtent = (1102,720), maxImageExtent = (1102,720). The Vulkan spec states: imageExtent must be between minImageExtent and maxImageExtent, inclusive, where minImageExtent and maxImageExtent are members of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface

The original window width was 1280 and I was in the middle of dragging it down.

I'm currently working around this by manually clamping the results returned by SDL_Vulkan_GetDrawableSize() to the min and max extents in the VkSurfaceCapabilitiesKHR struct and the validation errors go away. My code is as follows:

int width, height;
SDL_Vulkan_GetDrawableSize(win, &width, &height);
width = CLAMP(width, sc.capabilities.minImageExtent.width, sc.capabilities.maxImageExtent.width);
height = CLAMP(height, sc.capabilities.minImageExtent.height, sc.capabilities.maxImageExtent.height);
swapchainExtent.width = width;
swapchainExtent.height = height;
const VkSwapchainCreateInfoKHR createInfo = ...;
vkCreateSwapchainKHR(...);

I'm using GNOME with proprietary NVIDIA drivers, but IIRC the same thing happens on Intel Integrated with Mesa.

On 2019-06-20 23:42:13 +0000, Ryan C. Gordon wrote:

I assume this is X11 and not Wayland, right? For X11, SDL_Vulkan_GetDrawableSize() is literally just SDL_GetWindowSize().

I would say clamping to the min/maxImageExtent is the correct approach and not a workaround, unless you never get a resize event that puts you at the correct dimensions when dragging completes.

Something worth trying: use an SDL event filter to catch resize events as X11 sends them. Otherwise they're going into a separate queue and when you get the event from SDL from SDL_PollEvents, it's possible the X server has moved on and resized the window further and you don't have that information yet.

Also worth trying, first: make note of resizes, but don't actually create a swapchain until the event queue is empty (SDL_PollEvent() returns 0). This is a better idea in any case: if a big pile of resize events have queued up, you only want to do this once per frame.

These are just ideas, though. Let me know what you find.

--ryan.

On 2019-06-22 07:12:38 +0000, wrote:

(In reply to Ryan C. Gordon from comment # 1)

I assume this is X11 and not Wayland, right? For X11,
SDL_Vulkan_GetDrawableSize() is literally just SDL_GetWindowSize().

I would say clamping to the min/maxImageExtent is the correct approach and
not a workaround, unless you never get a resize event that puts you at the
correct dimensions when dragging completes.

Something worth trying: use an SDL event filter to catch resize events as
X11 sends them. Otherwise they're going into a separate queue and when you
get the event from SDL from SDL_PollEvents, it's possible the X server has
moved on and resized the window further and you don't have that information
yet.

Also worth trying, first: make note of resizes, but don't actually create a
swapchain until the event queue is empty (SDL_PollEvent() returns 0). This
is a better idea in any case: if a big pile of resize events have queued up,
you only want to do this once per frame.

These are just ideas, though. Let me know what you find.

--ryan.

Yes this is X, not Wayland. I always loop my events until SDL_PollEvent() returns 0, but I suspect there's a race condition where the event queue starts filling up again by the time it recreates the swapchain.

I've tried each possibility. I've recreated the swapchain when vkAcquireNextImageKHR() returns OUT_OF_DATE or SUBOPTIMAL. I've filtered (emptied the entire queue of) events for SDL_WINDOWEVENT_RESIZED and passed the event-given coordinates (data1 and data2) but I suspect a race condition between emptying the queue and recreating the swapchain where the "new" coordinates given by the resize event are already outdated.

I do see that the canonical solution is to simply CLAMP() the given coordinates between min and max image extents, in which case the "bug-fix" would just be adding a note of this in the header comments of SDL_Vulkan_GetDrawableSize().

"This function may return spurious or out-of-date results if the window is in the middle of being resized. The width and height should be clamped between their respective minImageExtent and maxImageExtent of their VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR()."

On 2019-06-22 08:33:38 +0000, wrote:

Although I wonder why one should use SDL_Vulkan_GetDrawableSize() over currentExtent in the first place.

On 2019-06-22 17:52:39 +0000, Ryan C. Gordon wrote:

(In reply to colaeuphoria from comment # 3)

Although I wonder why one should use SDL_Vulkan_GetDrawableSize() over
currentExtent in the first place.

I imagine the thinking is to match SDL_GL_GetDrawableSize(), which takes into account DPI scaling, but I'm not super-familiar with this piece of SDL yet.

--ryan.

sulix added a commit to sulix/SDL that referenced this issue Aug 8, 2021
SDL_Vulkan_GetDrawableSize() doesn't always return a size which is
within the Vulkan swapchain's allowed image extent range.

(This happens on X11 a lot when resizing, which is bug libsdl-org#3287)

Clamp the value we get back from SDL_Vulkan_GetDrawableSize() to this
range. Given the range usually is just a single value, this is almost
always equivalent to just using the min or max image extent, but this
seems logically most correct.
slouken pushed a commit that referenced this issue Aug 9, 2021
SDL_Vulkan_GetDrawableSize() doesn't always return a size which is
within the Vulkan swapchain's allowed image extent range.

(This happens on X11 a lot when resizing, which is bug #3287)

Clamp the value we get back from SDL_Vulkan_GetDrawableSize() to this
range. Given the range usually is just a single value, this is almost
always equivalent to just using the min or max image extent, but this
seems logically most correct.
@slouken slouken removed the bug label May 11, 2022
@slouken slouken closed this as completed Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants