Skip to content

Acquire the swapchain in endFrame, not beginFrame - #5

Merged
jdolan merged 2 commits into
mainfrom
fix/late-swapchain-acquire
Aug 17, 2026
Merged

Acquire the swapchain in endFrame, not beginFrame#5
jdolan merged 2 commits into
mainfrom
fix/late-swapchain-acquire

Conversation

@jdolan

@jdolan jdolan commented Aug 17, 2026

Copy link
Copy Markdown
Owner

beginFrame acquired the swapchain texture at the top of the frame, so the drawable was held across all of the caller's per-frame CPU work before the presenting blit finally submitted it. On Metal that starves CAMetalLayer's drawable pool: [layer nextDrawable] returns nil under contention, SDL does not check it, and the frame is silently never presented. Nothing needs the swapchain until the blit, so acquire it there.

Size the present framebuffer from SDL_GetWindowSizeInPixels rather than the swapchain dimensions, so a transient acquire hiccup can no longer tear down and rebuild every attachment (which also reset double-buffered attachment parity). The two agree by construction; the blit now scales if they ever disagree mid-resize. When no drawable is available the command buffer is still submitted, so the frame's GPU work completes and only presentation is skipped.

Also treat a NULL texture from either acquire wrapper as unavailable. SDL documents returning success with a NULL handle when the window is minimised or too many frames are in flight, and that handle must not be passed back into SDL; both backends do exactly this on the non-blocking path.

Refs jdolan/quetoo#945

beginFrame acquired the swapchain texture at the top of the frame, so the
drawable was held across all of the caller's per-frame CPU work before the
presenting blit finally submitted it. On Metal that starves CAMetalLayer's
drawable pool: [layer nextDrawable] returns nil under contention, SDL does
not check it, and the frame is silently never presented. Nothing needs the
swapchain until the blit, so acquire it there.

Size the present framebuffer from SDL_GetWindowSizeInPixels rather than the
swapchain dimensions, so a transient acquire hiccup can no longer tear down
and rebuild every attachment (which also reset double-buffered attachment
parity). The two agree by construction; the blit now scales if they ever
disagree mid-resize. When no drawable is available the command buffer is
still submitted, so the frame's GPU work completes and only presentation is
skipped.

Also treat a NULL texture from either acquire wrapper as unavailable. SDL
documents returning success with a NULL handle when the window is minimised
or too many frames are in flight, and that handle must not be passed back
into SDL; both backends do exactly this on the non-blocking path.

Refs jdolan/quetoo#945

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@jdolan
jdolan merged commit bad0587 into main Aug 17, 2026
3 checks passed
@jdolan
jdolan deleted the fix/late-swapchain-acquire branch August 17, 2026 17:27
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

Successfully merging this pull request may close these issues.

2 participants