Hello everyone
I’m working on the VSync input latency of my game. In my understanding, that’s what SDL_WaitForGPUSwapchain() is for, to sync the start of the game loop with the framerate:
SDL_WaitForGPUSwapchain()
-- VBLANK --
measureTime()
handleEvents()
updateState()
SDL_AcquireGPUSwapchainTexture()
sendRenderCommands()
However, this doesn’t work on my system (Mint 22.1, X11, Vulkan, AMD Radeon). It seems that SDL_WaitForGPUSwapchain() doesn’t block at all. Instead, SDL_AcquireGPUSwapchainTexture() blocks for the entire frame regardless, even though it should set swapchain to NULL and return immediately when it isn’t ready.
Minimal example:
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("test", 640, 360, 0);
SDL_GPUDevice* device = SDL_CreateGPUDevice(0xFF, true, "vulkan");
SDL_assert(window);
SDL_assert(device);
SDL_assert(SDL_ClaimWindowForGPUDevice(device, window));
while (true) {
SDL_Event event;
while (SDL_PollEvent(&event))
if (event.type == SDL_EVENT_QUIT)
return 0;
SDL_GPUCommandBuffer* command = SDL_AcquireGPUCommandBuffer(device);
SDL_GPUTexture* swapchain;
Sint64 start = SDL_GetTicksNS();
SDL_assert(SDL_WaitForGPUSwapchain(device, window));
Sint64 wait = SDL_GetTicksNS();
SDL_assert(SDL_AcquireGPUSwapchainTexture(command, window, &swapchain, NULL, NULL));
Sint64 aquire = SDL_GetTicksNS();
SDL_Log("Wait: %8li Acquire: %8li", wait - start, aquire - wait);
if (swapchain) {
float pulse = 0.5f + 0.5f*SDL_cosf(SDL_GetTicks()/1000.0f);
SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(command,
&(SDL_GPUColorTargetInfo){
.texture = swapchain,
.clear_color = (SDL_FColor){0, pulse, 1, 1},
.load_op = SDL_GPU_LOADOP_CLEAR,
.store_op = SDL_GPU_STOREOP_STORE}, 1, NULL);
SDL_EndGPURenderPass(pass);
SDL_SubmitGPUCommandBuffer(command);
}
else {
SDL_Log("NULL swapchain");
SDL_CancelGPUCommandBuffer(command);
}
}
return 0;
}
Relevant output:
SDL revision: SDL-release-3.4.8-0-gd9d553670
SDL chose video backend 'x11'
SDL chose gpu backend 'vulkan'
Validation layers enabled, expect debug level performance!
Vulkan Device: AMD Radeon RX 6400 (RADV NAVI24)
Vulkan Driver: radv Mesa 25.2.8-0ubuntu0.24.04.1
...
Wait: 10960 Acquire: 16470012
Wait: 52030 Acquire: 16439692
Wait: 17530 Acquire: 16603893
...
From what I can tell, the blocking happens here. I come from OpenGL, so I’m not very familiar with low-level synchronization. But it seems that the fence disagrees with the semaphore on whether the swapchain is ready or not?
Am I just doing this incorrectly? Or have I encountered an actual issue? Any help is appreciated.