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:
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
namespace Rendering::GPU {
|
namespace Rendering::GPU {
|
||||||
|
|
||||||
GpuFrameRenderer::~GpuFrameRenderer() { destroy(); }
|
GpuFrameRenderer::~GpuFrameRenderer() { destroy(); }
|
||||||
|
|
||||||
auto GpuFrameRenderer::init(SDL_Window* window, float logical_w, float logical_h) -> bool {
|
auto GpuFrameRenderer::init(SDL_Window* window, float logical_w, float logical_h) -> bool {
|
||||||
logical_w_ = logical_w;
|
logical_w_ = logical_w;
|
||||||
logical_h_ = logical_h;
|
logical_h_ = logical_h;
|
||||||
|
|
||||||
@@ -39,9 +39,9 @@ auto GpuFrameRenderer::init(SDL_Window* window, float logical_w, float logical_h
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpuFrameRenderer::createOffscreen() -> bool {
|
auto GpuFrameRenderer::createOffscreen() -> bool {
|
||||||
SDL_GPUDevice* dev = device_.get();
|
SDL_GPUDevice* dev = device_.get();
|
||||||
if (dev == nullptr) {
|
if (dev == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
@@ -79,9 +79,9 @@ auto GpuFrameRenderer::createOffscreen() -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpuFrameRenderer::destroyOffscreen() {
|
void GpuFrameRenderer::destroyOffscreen() {
|
||||||
SDL_GPUDevice* dev = device_.get();
|
SDL_GPUDevice* dev = device_.get();
|
||||||
if (dev == nullptr) {
|
if (dev == nullptr) {
|
||||||
offscreen_texture_ = nullptr;
|
offscreen_texture_ = nullptr;
|
||||||
@@ -96,18 +96,18 @@ void GpuFrameRenderer::destroyOffscreen() {
|
|||||||
SDL_ReleaseGPUSampler(dev, linear_sampler_);
|
SDL_ReleaseGPUSampler(dev, linear_sampler_);
|
||||||
linear_sampler_ = nullptr;
|
linear_sampler_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpuFrameRenderer::destroy() {
|
void GpuFrameRenderer::destroy() {
|
||||||
destroyOffscreen();
|
destroyOffscreen();
|
||||||
postfx_pipeline_.destroy();
|
postfx_pipeline_.destroy();
|
||||||
line_pipeline_.destroy();
|
line_pipeline_.destroy();
|
||||||
device_.destroy();
|
device_.destroy();
|
||||||
vertices_.clear();
|
vertices_.clear();
|
||||||
indices_.clear();
|
indices_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GpuFrameRenderer::beginFrame(float clear_r, float clear_g, float clear_b) -> bool {
|
auto GpuFrameRenderer::beginFrame(float clear_r, float clear_g, float clear_b) -> bool {
|
||||||
// Los clear_* se ignoran: el fondo lo pinta el postpro. Mantenemos la
|
// Los clear_* se ignoran: el fondo lo pinta el postpro. Mantenemos la
|
||||||
// firma para no romper el SDLManager.
|
// firma para no romper el SDLManager.
|
||||||
(void)clear_r;
|
(void)clear_r;
|
||||||
@@ -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;
|
||||||
@@ -161,9 +160,9 @@ auto GpuFrameRenderer::beginFrame(float clear_r, float clear_g, float clear_b) -
|
|||||||
vertices_.clear();
|
vertices_.clear();
|
||||||
indices_.clear();
|
indices_.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpuFrameRenderer::setViewport(float x, float y, float w, float h) {
|
void GpuFrameRenderer::setViewport(float x, float y, float w, float h) {
|
||||||
viewport_x_ = x;
|
viewport_x_ = x;
|
||||||
viewport_y_ = y;
|
viewport_y_ = y;
|
||||||
viewport_w_ = w;
|
viewport_w_ = w;
|
||||||
@@ -171,23 +170,55 @@ void GpuFrameRenderer::setViewport(float x, float y, float w, float h) {
|
|||||||
// El viewport solo se aplica en el pase final (composite). Si estamos
|
// El viewport solo se aplica en el pase final (composite). Si estamos
|
||||||
// ya dentro del composite, lo aplicaríamos inmediatamente, pero la API
|
// ya dentro del composite, lo aplicaríamos inmediatamente, pero la API
|
||||||
// está pensada para llamarse antes de endFrame/al cambiar de ventana.
|
// está pensada para llamarse antes de endFrame/al cambiar de ventana.
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
: SDL_GPU_PRESENTMODE_IMMEDIATE;
|
|
||||||
if (!SDL_SetGPUSwapchainParameters(dev, device_.window(),
|
|
||||||
SDL_GPU_SWAPCHAINCOMPOSITION_SDR, MODE)) {
|
|
||||||
std::cerr << "[GpuFrameRenderer] SDL_SetGPUSwapchainParameters: " << SDL_GetError() << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GpuFrameRenderer::applyFinalViewport() {
|
// A SDL_GPU, només VSYNC està garantit. IMMEDIATE i MAILBOX són opcionals
|
||||||
|
// i poden no estar disponibles segons backend/driver/compositor (típicament
|
||||||
|
// Wayland sense unredirect, X11 amb compositor agressiu, etc.). Si demanem
|
||||||
|
// un mode no suportat, SDL retorna error i la swapchain queda igual.
|
||||||
|
//
|
||||||
|
// 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() {
|
||||||
if (render_pass_ == nullptr) {
|
if (render_pass_ == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -202,10 +233,9 @@ void GpuFrameRenderer::applyFinalViewport() {
|
|||||||
vp.min_depth = 0.0F;
|
vp.min_depth = 0.0F;
|
||||||
vp.max_depth = 1.0F;
|
vp.max_depth = 1.0F;
|
||||||
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));
|
||||||
@@ -230,9 +260,9 @@ void GpuFrameRenderer::pushLine(float x1, float y1, float x2, float y2, float th
|
|||||||
indices_.push_back(BASE_INDEX + 1);
|
indices_.push_back(BASE_INDEX + 1);
|
||||||
indices_.push_back(BASE_INDEX + 3);
|
indices_.push_back(BASE_INDEX + 3);
|
||||||
indices_.push_back(BASE_INDEX + 2);
|
indices_.push_back(BASE_INDEX + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpuFrameRenderer::flushBatch() {
|
void GpuFrameRenderer::flushBatch() {
|
||||||
if (vertices_.empty() || indices_.empty()) {
|
if (vertices_.empty() || indices_.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -299,14 +329,17 @@ 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);
|
||||||
SDL_ReleaseGPUTransferBuffer(dev, tbo);
|
SDL_ReleaseGPUTransferBuffer(dev, tbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpuFrameRenderer::compositePass() {
|
void GpuFrameRenderer::compositePass() {
|
||||||
// Cierra el render pass actual (sobre offscreen).
|
// Cierra el render pass actual (sobre offscreen).
|
||||||
if (render_pass_ != nullptr) {
|
if (render_pass_ != nullptr) {
|
||||||
SDL_EndGPURenderPass(render_pass_);
|
SDL_EndGPURenderPass(render_pass_);
|
||||||
@@ -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;
|
||||||
@@ -380,9 +415,9 @@ void GpuFrameRenderer::compositePass() {
|
|||||||
|
|
||||||
// Fullscreen triangle: 3 vértices generados en el shader, sin VBO.
|
// Fullscreen triangle: 3 vértices generados en el shader, sin VBO.
|
||||||
SDL_DrawGPUPrimitives(render_pass_, 3, 1, 0, 0);
|
SDL_DrawGPUPrimitives(render_pass_, 3, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpuFrameRenderer::endFrame() {
|
void GpuFrameRenderer::endFrame() {
|
||||||
if (cmd_buffer_ == nullptr) {
|
if (cmd_buffer_ == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -395,6 +430,6 @@ void GpuFrameRenderer::endFrame() {
|
|||||||
SDL_SubmitGPUCommandBuffer(cmd_buffer_);
|
SDL_SubmitGPUCommandBuffer(cmd_buffer_);
|
||||||
cmd_buffer_ = nullptr;
|
cmd_buffer_ = nullptr;
|
||||||
swapchain_texture_ = nullptr;
|
swapchain_texture_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Rendering::GPU
|
} // namespace Rendering::GPU
|
||||||
|
|||||||
Reference in New Issue
Block a user