supersampling ara aplica al tamany de la finestra, no a la textura base

This commit is contained in:
2026-03-25 22:00:10 +01:00
parent 1dbfff2c17
commit 6914f7df93
2 changed files with 66 additions and 50 deletions

View File

@@ -273,25 +273,9 @@ namespace Rendering {
return false;
}
// ----------------------------------------------------------------
// 3b. Create scaled texture (render target for upscale pass, only with SS)
// ----------------------------------------------------------------
if (oversample_ > 1) {
SDL_GPUTextureCreateInfo scaled_info = {};
scaled_info.type = SDL_GPU_TEXTURETYPE_2D;
scaled_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
scaled_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
scaled_info.width = static_cast<Uint32>(game_width_ * oversample_);
scaled_info.height = static_cast<Uint32>(game_height_ * oversample_);
scaled_info.layer_count_or_depth = 1;
scaled_info.num_levels = 1;
scaled_texture_ = SDL_CreateGPUTexture(device_, &scaled_info);
if (scaled_texture_ == nullptr) {
SDL_Log("SDL3GPUShader: failed to create scaled texture: %s", SDL_GetError());
cleanup();
return false;
}
}
// scaled_texture_ se creará en el primer render() una vez conocido el tamaño de ventana
scaled_w_ = 0;
scaled_h_ = 0;
// ----------------------------------------------------------------
// 4. Create upload transfer buffer (CPU → GPU, always game resolution)
@@ -467,6 +451,19 @@ namespace Rendering {
void SDL3GPUShader::render() {
if (!is_initialized_) { return; }
// Paso 0: si SS activo, verificar si el tamaño de ventana cambió y recrear scaled_texture_
if (oversample_ > 1) {
int win_w = 0;
int win_h = 0;
SDL_GetWindowSizeInPixels(window_, &win_w, &win_h);
const int NEED_W = win_w * oversample_;
const int NEED_H = win_h * oversample_;
if (NEED_W != scaled_w_ || NEED_H != scaled_h_) {
SDL_WaitForGPUIdle(device_);
recreateScaledTexture(NEED_W, NEED_H);
}
}
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_);
if (cmd == nullptr) {
SDL_Log("SDL3GPUShader: SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError());
@@ -561,11 +558,11 @@ namespace Rendering {
SDL_SetGPUViewport(pass, &vp);
// pixel_scale: subpíxeles de textura por pixel lógico de juego.
// Sin SS: vh/game_height (zoom de ventana = subpíxeles por fila).
// Con SS: la textura entrada al PostFX tiene OS subfilas por fila lógica,
// así que pixel_scale = OS (independiente del zoom de ventana).
uniforms_.pixel_scale = (oversample_ > 1)
? static_cast<float>(oversample_)
// Sin SS: vh/game_height (zoom de ventana).
// Con SS: scaled_h_/game_height (= win_h*oversample_/game_height), que indica
// cuántas subfilas de la textura intermedia corresponden a cada fila lógica.
uniforms_.pixel_scale = (oversample_ > 1 && game_height_ > 0)
? (static_cast<float>(scaled_h_) / static_cast<float>(game_height_))
: ((game_height_ > 0) ? (vh / static_cast<float>(game_height_)) : 1.0F);
uniforms_.time = static_cast<float>(SDL_GetTicks()) / 1000.0F;
uniforms_.oversample = static_cast<float>(oversample_);
@@ -619,6 +616,8 @@ namespace Rendering {
SDL_ReleaseGPUTexture(device_, scaled_texture_);
scaled_texture_ = nullptr;
}
scaled_w_ = 0;
scaled_h_ = 0;
if (upload_buffer_ != nullptr) {
SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_);
upload_buffer_ = nullptr;
@@ -746,10 +745,14 @@ namespace Rendering {
SDL_ReleaseGPUTexture(device_, scene_texture_);
scene_texture_ = nullptr;
}
// scaled_texture_ se libera aquí; se recreará en el primer render() con las dims de ventana
if (scaled_texture_ != nullptr) {
SDL_ReleaseGPUTexture(device_, scaled_texture_);
scaled_texture_ = nullptr;
}
scaled_w_ = 0;
scaled_h_ = 0;
if (upload_buffer_ != nullptr) {
SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_);
upload_buffer_ = nullptr;
@@ -773,25 +776,6 @@ namespace Rendering {
return false;
}
// scaled_texture_: solo con SS
if (oversample_ > 1) {
SDL_GPUTextureCreateInfo scaled_info = {};
scaled_info.type = SDL_GPU_TEXTURETYPE_2D;
scaled_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
scaled_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
scaled_info.width = static_cast<Uint32>(game_width_ * oversample_);
scaled_info.height = static_cast<Uint32>(game_height_ * oversample_);
scaled_info.layer_count_or_depth = 1;
scaled_info.num_levels = 1;
scaled_texture_ = SDL_CreateGPUTexture(device_, &scaled_info);
if (scaled_texture_ == nullptr) {
SDL_Log("SDL3GPUShader: reinit — failed to create scaled texture: %s", SDL_GetError());
SDL_ReleaseGPUTexture(device_, scene_texture_);
scene_texture_ = nullptr;
return false;
}
}
// upload_buffer_: siempre a resolución del juego
SDL_GPUTransferBufferCreateInfo tb_info = {};
tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
@@ -799,15 +783,44 @@ namespace Rendering {
upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info);
if (upload_buffer_ == nullptr) {
SDL_Log("SDL3GPUShader: reinit — failed to create upload buffer: %s", SDL_GetError());
if (scaled_texture_ != nullptr) { SDL_ReleaseGPUTexture(device_, scaled_texture_); scaled_texture_ = nullptr; }
SDL_ReleaseGPUTexture(device_, scene_texture_);
scene_texture_ = nullptr;
return false;
}
SDL_Log("SDL3GPUShader: oversample %d — scene %dx%d, scaled %dx%d",
oversample_, game_width_, game_height_,
game_width_ * oversample_, game_height_ * oversample_);
SDL_Log("SDL3GPUShader: reinit — scene %dx%d, oversample %d (scaled se creará en render)",
game_width_, game_height_, oversample_);
return true;
}
// ---------------------------------------------------------------------------
// recreateScaledTexture — libera y recrea scaled_texture_ con nuevas dimensiones.
// Llamar solo cuando device_ no esté ejecutando comandos (SDL_WaitForGPUIdle previo).
// ---------------------------------------------------------------------------
auto SDL3GPUShader::recreateScaledTexture(int w, int h) -> bool {
if (scaled_texture_ != nullptr) {
SDL_ReleaseGPUTexture(device_, scaled_texture_);
scaled_texture_ = nullptr;
}
scaled_w_ = 0;
scaled_h_ = 0;
SDL_GPUTextureCreateInfo info = {};
info.type = SDL_GPU_TEXTURETYPE_2D;
info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
info.width = static_cast<Uint32>(w);
info.height = static_cast<Uint32>(h);
info.layer_count_or_depth = 1;
info.num_levels = 1;
scaled_texture_ = SDL_CreateGPUTexture(device_, &info);
if (scaled_texture_ == nullptr) {
SDL_Log("SDL3GPUShader: failed to create scaled texture %dx%d: %s", w, h, SDL_GetError());
return false;
}
scaled_w_ = w;
scaled_h_ = h;
SDL_Log("SDL3GPUShader: scaled texture %dx%d (oversample %d)", w, h, oversample_);
return true;
}

View File

@@ -80,14 +80,15 @@ namespace Rendering {
Uint32 num_uniform_buffers) -> SDL_GPUShader*;
auto createPipeline() -> bool;
auto reinitTexturesAndBuffer() -> bool; // Recrea textura y buffer con oversample actual
auto reinitTexturesAndBuffer() -> bool; // Recrea scene_texture_ y upload_buffer_
auto recreateScaledTexture(int w, int h) -> bool; // Recrea scaled_texture_ con nuevas dims
SDL_Window* window_ = nullptr;
SDL_GPUDevice* device_ = nullptr;
SDL_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass
SDL_GPUGraphicsPipeline* upscale_pipeline_ = nullptr; // Upscale nearest pass (solo con SS)
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_)
SDL_GPUTexture* scaled_texture_ = nullptr; // Render target intermedio (game × OS), solo con SS
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_)
SDL_GPUTexture* scaled_texture_ = nullptr; // Render target intermedio (win*SS × win*SS), solo con SS
SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
SDL_GPUSampler* sampler_ = nullptr; // NEAREST
SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR
@@ -96,6 +97,8 @@ namespace Rendering {
int game_width_ = 0; // Dimensiones originales del canvas
int game_height_ = 0;
int scaled_w_ = 0; // Dimensiones actuales de scaled_texture_ (win*SS)
int scaled_h_ = 0;
int oversample_ = 1; // Factor SS actual (1 o 3)
bool is_initialized_ = false;
bool vsync_ = true;