corregit postfx en windows

This commit is contained in:
2026-03-21 17:55:18 +01:00
parent 43a6cc2d7a
commit 9df3f1b929
6 changed files with 1061 additions and 52 deletions

View File

@@ -129,7 +129,7 @@ void Screen::render() {
// En el path SDL3GPU, los píxeles se suben directamente desde la Surface.
// En el path SDL_Renderer, primero copiamos la surface a la SDL_Texture.
if (!(Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated())) {
if (!(shader_backend_ && shader_backend_->isHardwareAccelerated())) {
surfaceToTexture();
}
@@ -209,17 +209,25 @@ void Screen::renderNotifications() const {
// Cambia el estado del PostFX
void Screen::togglePostFX() {
Options::video.postfx = !Options::video.postfx;
if (!Options::video.postfx && shader_backend_) {
// Al desactivar PostFX, limpiar el backend para liberar el swapchain de GPU
shader_backend_->cleanup();
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
if (Options::video.postfx) {
applyCurrentPostFXPreset();
} else {
// Pass-through: efectos a 0, el shader copia la textura sin modificar
shader_backend_->setPostFXParams(Rendering::PostFXParams{});
}
} else {
// Backend no inicializado aún — inicializarlo ahora
initShaders();
}
}
// Recarga el shader del preset actual sin toggle
void Screen::reloadPostFX() {
if (Options::video.postfx) {
if (Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
// El backend ya está activo: solo actualizar uniforms, sin recrear el pipeline
applyCurrentPostFXPreset();
} else if (Options::video.postfx) {
initShaders();
}
}
@@ -323,8 +331,8 @@ void Screen::surfaceToTexture() {
void Screen::textureToRenderer() {
SDL_Texture* texture_to_render = Options::video.border.enabled ? border_texture_ : game_texture_;
if (Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
// ---- SDL3 GPU path: convertir Surface → ARGB → upload → PostFX → present ----
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
// ---- SDL3 GPU path: convertir Surface → ARGB → upload → PostFX/pass-through → present ----
if (Options::video.border.enabled) {
// El border_surface_ solo tiene el color de borde; hay que componer encima el game_surface_
const int BORDER_W = static_cast<int>(border_surface_->getWidth());
@@ -452,11 +460,9 @@ void Screen::applyCurrentPostFXPreset() {
}
// Inicializa los shaders
// El device GPU se crea siempre (independientemente de postfx) para evitar
// conflictos SDL_Renderer/SDL_GPU al hacer toggle F4 en Windows/Vulkan.
void Screen::initShaders() {
if (!Options::video.postfx) {
return;
}
SDL_Texture* tex = Options::video.border.enabled ? border_texture_ : game_texture_;
if (!shader_backend_) {
@@ -464,7 +470,12 @@ void Screen::initShaders() {
}
shader_backend_->init(window_, tex, "", "");
applyCurrentPostFXPreset();
if (Options::video.postfx) {
applyCurrentPostFXPreset();
} else {
// Pass-through: todos los efectos a 0, el shader solo copia la textura
shader_backend_->setPostFXParams(Rendering::PostFXParams{});
}
}
// Obtiene información sobre la pantalla

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -164,7 +164,7 @@ namespace Rendering {
// Destructor
// ---------------------------------------------------------------------------
SDL3GPUShader::~SDL3GPUShader() {
cleanup();
destroy();
}
// ---------------------------------------------------------------------------
@@ -174,7 +174,9 @@ auto SDL3GPUShader::init(SDL_Window* window,
SDL_Texture* texture,
const std::string& /*vertex_source*/,
const std::string& /*fragment_source*/) -> bool {
// Si ya estaba inicializado, limpiar antes de reinicializar (p.ej. al cambiar borde)
// Si ya estaba inicializado (p.ej. al cambiar borde), liberar recursos
// de textura/pipeline pero mantener el device vivo para evitar conflictos
// con SDL_Renderer en Windows/Vulkan.
if (is_initialized_) {
cleanup();
}
@@ -187,35 +189,37 @@ auto SDL3GPUShader::init(SDL_Window* window,
SDL_GetTextureSize(texture, &fw, &fh);
tex_width_ = static_cast<int>(fw);
tex_height_ = static_cast<int>(fh);
uniforms_.screen_height = fh;
uniforms_.screen_height = fh; // Altura lógica del juego (no el swapchain físico)
// ----------------------------------------------------------------
// 1. Create GPU device
// 1. Create GPU device (solo si no existe ya)
// ----------------------------------------------------------------
#ifdef __APPLE__
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB;
#else
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_SPIRV;
#endif
device_ = SDL_CreateGPUDevice(PREFERRED, false, nullptr);
if (device_ == nullptr) {
SDL_Log("SDL3GPUShader: SDL_CreateGPUDevice failed: %s", SDL_GetError());
return false;
}
SDL_Log("SDL3GPUShader: driver = %s", SDL_GetGPUDeviceDriver(device_));
#ifdef __APPLE__
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB;
#else
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_SPIRV;
#endif
device_ = SDL_CreateGPUDevice(PREFERRED, false, nullptr);
if (device_ == nullptr) {
SDL_Log("SDL3GPUShader: SDL_CreateGPUDevice failed: %s", SDL_GetError());
return false;
}
SDL_Log("SDL3GPUShader: driver = %s", SDL_GetGPUDeviceDriver(device_));
// ----------------------------------------------------------------
// 2. Claim window (GPU device owns the swapchain from now on)
// ----------------------------------------------------------------
if (!SDL_ClaimWindowForGPUDevice(device_, window_)) {
SDL_Log("SDL3GPUShader: SDL_ClaimWindowForGPUDevice failed: %s", SDL_GetError());
SDL_DestroyGPUDevice(device_);
device_ = nullptr;
return false;
// ----------------------------------------------------------------
// 2. Claim window (una sola vez — no liberar hasta destroy())
// ----------------------------------------------------------------
if (!SDL_ClaimWindowForGPUDevice(device_, window_)) {
SDL_Log("SDL3GPUShader: SDL_ClaimWindowForGPUDevice failed: %s", SDL_GetError());
SDL_DestroyGPUDevice(device_);
device_ = nullptr;
return false;
}
SDL_SetGPUSwapchainParameters(device_, window_,
SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
SDL_GPU_PRESENTMODE_VSYNC);
}
SDL_SetGPUSwapchainParameters(device_, window_,
SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
SDL_GPU_PRESENTMODE_VSYNC);
// ----------------------------------------------------------------
// 3. Create scene texture (upload target + sampler source)
@@ -395,8 +399,6 @@ void SDL3GPUShader::render() {
return;
}
uniforms_.screen_height = static_cast<float>(sh);
// ---- Render pass: PostFX → swapchain ----
SDL_GPUColorTargetInfo color_target = {};
color_target.texture = swapchain;
@@ -423,7 +425,7 @@ void SDL3GPUShader::render() {
}
// ---------------------------------------------------------------------------
// cleanup
// cleanup — libera pipeline/texturas/buffer pero mantiene device + swapchain
// ---------------------------------------------------------------------------
void SDL3GPUShader::cleanup() {
is_initialized_ = false;
@@ -447,8 +449,20 @@ void SDL3GPUShader::cleanup() {
SDL_ReleaseGPUSampler(device_, sampler_);
sampler_ = nullptr;
}
// device_ y el claim de la ventana se mantienen vivos
}
}
SDL_ReleaseWindowFromGPUDevice(device_, window_);
// ---------------------------------------------------------------------------
// destroy — limpieza completa incluyendo device y swapchain (solo al cerrar)
// ---------------------------------------------------------------------------
void SDL3GPUShader::destroy() {
cleanup();
if (device_ != nullptr) {
if (window_ != nullptr) {
SDL_ReleaseWindowFromGPUDevice(device_, window_);
}
SDL_DestroyGPUDevice(device_);
device_ = nullptr;
}

View File

@@ -40,7 +40,8 @@ class SDL3GPUShader : public ShaderBackend {
void render() override;
void setTextureSize(float width, float height) override {}
void cleanup() override;
void cleanup() override; // Libera pipeline/texturas pero mantiene el device vivo
void destroy(); // Limpieza completa (device + swapchain); llamar solo al cerrar
[[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; }
// Sube píxeles ARGB8888 desde CPU; llamado antes de render()

View File

@@ -24,15 +24,13 @@ glslc "${SHADERS_DIR}/postfx.frag" -o /tmp/postfx.frag.spv
echo "Generating C++ headers..."
xxd -i /tmp/postfx.vert.spv | \
sed 's/unsigned char __tmp_postfx_vert_spv\[\]/static const uint8_t kpostfx_vert_spv[]/' | \
sed 's/unsigned int __tmp_postfx_vert_spv_len/static const size_t kpostfx_vert_spv_size/' | \
sed 's/= [0-9]*/\0/' \
sed 's/unsigned char .*postfx_vert_spv\[\]/static const uint8_t kpostfx_vert_spv[]/' | \
sed 's/unsigned int .*postfx_vert_spv_len/static const size_t kpostfx_vert_spv_size/' \
> "${HEADERS_DIR}/postfx_vert_spv.h"
xxd -i /tmp/postfx.frag.spv | \
sed 's/unsigned char __tmp_postfx_frag_spv\[\]/static const uint8_t kpostfx_frag_spv[]/' | \
sed 's/unsigned int __tmp_postfx_frag_spv_len/static const size_t kpostfx_frag_spv_size/' | \
sed 's/= [0-9]*/\0/' \
sed 's/unsigned char .*postfx_frag_spv\[\]/static const uint8_t kpostfx_frag_spv[]/' | \
sed 's/unsigned int .*postfx_frag_spv_len/static const size_t kpostfx_frag_spv_size/' \
> "${HEADERS_DIR}/postfx_frag_spv.h"
# Prepend required includes to the headers