fix(vsync): comprovar suport de present mode i loggejar el mode efectiu

setVSync demanava SDL_GPU_PRESENTMODE_IMMEDIATE sense comprovar suport.
A SDL_GPU només VSYNC està garantit; IMMEDIATE i MAILBOX són opcionals.
Si no estaven suportats (típicament Wayland/X11 amb compositor), SDL
retornava error i la swapchain es quedava en VSYNC sense que ho sabéssim.

Ara:
- Consultem SDL_WindowSupportsGPUPresentMode abans de fer la crida.
- En VSync OFF: provem IMMEDIATE → fallback a MAILBOX → si cap, ens
  quedem en VSYNC i avisem (driver/compositor força VSync).
- Loggejem sempre el mode efectiu (no només els errors), perquè ara mateix
  no hi havia forma de saber des de fora si el toggle havia tingut efecte.
This commit is contained in:
2026-05-20 20:17:28 +02:00
parent 7c2499cd91
commit 6063309932
@@ -125,8 +125,7 @@ auto GpuFrameRenderer::beginFrame(float clear_r, float clear_g, float clear_b) -
return false; return false;
} }
if (!SDL_WaitAndAcquireGPUSwapchainTexture(cmd_buffer_, device_.window(), if (!SDL_WaitAndAcquireGPUSwapchainTexture(cmd_buffer_, device_.window(), &swapchain_texture_, nullptr, nullptr)) {
&swapchain_texture_, nullptr, nullptr)) {
std::cerr << "[GpuFrameRenderer] WaitAndAcquire: " << SDL_GetError() << '\n'; std::cerr << "[GpuFrameRenderer] WaitAndAcquire: " << SDL_GetError() << '\n';
SDL_SubmitGPUCommandBuffer(cmd_buffer_); SDL_SubmitGPUCommandBuffer(cmd_buffer_);
cmd_buffer_ = nullptr; cmd_buffer_ = nullptr;
@@ -175,16 +174,48 @@ void GpuFrameRenderer::setViewport(float x, float y, float w, float h) {
void GpuFrameRenderer::setVSync(bool enabled) { void GpuFrameRenderer::setVSync(bool enabled) {
SDL_GPUDevice* dev = device_.get(); SDL_GPUDevice* dev = device_.get();
if (dev == nullptr || device_.window() == nullptr) { SDL_Window* win = device_.window();
if (dev == nullptr || win == nullptr) {
return; return;
} }
const SDL_GPUPresentMode MODE = enabled
? SDL_GPU_PRESENTMODE_VSYNC // A SDL_GPU, només VSYNC està garantit. IMMEDIATE i MAILBOX són opcionals
: SDL_GPU_PRESENTMODE_IMMEDIATE; // i poden no estar disponibles segons backend/driver/compositor (típicament
if (!SDL_SetGPUSwapchainParameters(dev, device_.window(), // Wayland sense unredirect, X11 amb compositor agressiu, etc.). Si demanem
SDL_GPU_SWAPCHAINCOMPOSITION_SDR, MODE)) { // un mode no suportat, SDL retorna error i la swapchain queda igual.
std::cerr << "[GpuFrameRenderer] SDL_SetGPUSwapchainParameters: " << SDL_GetError() << '\n'; //
// Estratègia: si l'usuari demana VSync OFF, provem IMMEDIATE i si no està
// suportat fem fallback a MAILBOX (no és no-VSync però sí permet superar
// els 60Hz sense tearing). Si cap dels dos, ens quedem amb VSYNC i avisem.
auto try_set = [&](SDL_GPUPresentMode mode, const char* name) -> bool {
if (!SDL_WindowSupportsGPUPresentMode(dev, win, mode)) {
return false;
} }
if (!SDL_SetGPUSwapchainParameters(dev, win, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, mode)) {
std::cerr << "[GpuFrameRenderer] SDL_SetGPUSwapchainParameters("
<< name << "): " << SDL_GetError() << '\n';
return false;
}
std::cout << "[GpuFrameRenderer] Present mode: " << name << '\n';
return true;
};
if (enabled) {
try_set(SDL_GPU_PRESENTMODE_VSYNC, "VSYNC");
return;
}
if (try_set(SDL_GPU_PRESENTMODE_IMMEDIATE, "IMMEDIATE")) {
return;
}
if (try_set(SDL_GPU_PRESENTMODE_MAILBOX, "MAILBOX (fallback)")) {
return;
}
// Tots dos rebutjats: el driver/compositor força VSync. Hi tornem
// explícitament perquè la swapchain quedi en estat conegut.
std::cerr << "[GpuFrameRenderer] VSync OFF no disponible (driver/compositor "
"força VSYNC). Mantenim VSYNC.\n";
try_set(SDL_GPU_PRESENTMODE_VSYNC, "VSYNC (forçat)");
} }
void GpuFrameRenderer::applyFinalViewport() { void GpuFrameRenderer::applyFinalViewport() {
@@ -204,8 +235,7 @@ void GpuFrameRenderer::applyFinalViewport() {
SDL_SetGPUViewport(render_pass_, &vp); SDL_SetGPUViewport(render_pass_, &vp);
} }
void GpuFrameRenderer::pushLine(float x1, float y1, float x2, float y2, float thickness, void GpuFrameRenderer::pushLine(float x1, float y1, float x2, float y2, float thickness, float r, float g, float b, float a) {
float r, float g, float b, float a) {
const float DX = x2 - x1; const float DX = x2 - x1;
const float DY = y2 - y1; const float DY = y2 - y1;
const float LEN = std::sqrt((DX * DX) + (DY * DY)); const float LEN = std::sqrt((DX * DX) + (DY * DY));
@@ -299,7 +329,10 @@ void GpuFrameRenderer::flushBatch() {
SDL_DrawGPUIndexedPrimitives(render_pass_, SDL_DrawGPUIndexedPrimitives(render_pass_,
static_cast<uint32_t>(indices_.size()), static_cast<uint32_t>(indices_.size()),
1, 0, 0, 0); 1,
0,
0,
0);
SDL_ReleaseGPUBuffer(dev, vbo); SDL_ReleaseGPUBuffer(dev, vbo);
SDL_ReleaseGPUBuffer(dev, ibo); SDL_ReleaseGPUBuffer(dev, ibo);
@@ -341,9 +374,11 @@ void GpuFrameRenderer::compositePass() {
// contribuciones (intensidad / amplitud / max=min) en lugar de tener // contribuciones (intensidad / amplitud / max=min) en lugar de tener
// un branch en el shader. // un branch en el shader.
const float BLOOM_INTENSITY = postfx_params_.bloom_enabled const float BLOOM_INTENSITY = postfx_params_.bloom_enabled
? postfx_params_.bloom_intensity : 0.0F; ? postfx_params_.bloom_intensity
: 0.0F;
const float FLICKER_AMPLITUDE = postfx_params_.flicker_enabled const float FLICKER_AMPLITUDE = postfx_params_.flicker_enabled
? postfx_params_.flicker_amplitude : 0.0F; ? postfx_params_.flicker_amplitude
: 0.0F;
const float BG_MIN_R = postfx_params_.background_enabled ? postfx_params_.background_min_r : 0.0F; const float BG_MIN_R = postfx_params_.background_enabled ? postfx_params_.background_min_r : 0.0F;
const float BG_MIN_G = postfx_params_.background_enabled ? postfx_params_.background_min_g : 0.0F; const float BG_MIN_G = postfx_params_.background_enabled ? postfx_params_.background_min_g : 0.0F;
const float BG_MIN_B = postfx_params_.background_enabled ? postfx_params_.background_min_b : 0.0F; const float BG_MIN_B = postfx_params_.background_enabled ? postfx_params_.background_min_b : 0.0F;