primera implementacio de postfx

This commit is contained in:
2026-03-23 13:18:36 +01:00
parent 99cc803f21
commit 2f3161d701
23 changed files with 13306 additions and 771 deletions

View File

@@ -0,0 +1,106 @@
#pragma once
#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
#include "rendering/shader_backend.hpp"
// PostFX uniforms pushed to fragment stage each frame.
// Must match the MSL struct and GLSL uniform block layout.
// 12 floats = 48 bytes — meets Metal/Vulkan 16-byte alignment requirement.
struct PostFXUniforms {
float vignette_strength; // 0 = none, ~0.8 = subtle
float chroma_strength; // 0 = off, ~0.2 = subtle chromatic aberration
float scanline_strength; // 0 = off, 1 = full
float screen_height; // logical height in pixels (used by bleeding effect)
float mask_strength; // 0 = off, 1 = full phosphor dot mask
float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction
float curvature; // 0 = flat, 1 = max barrel distortion
float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding
float pixel_scale; // physical pixels per logical pixel (vh / tex_height_)
float time; // seconds since SDL init (SDL_GetTicks() / 1000.0f)
float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS)
float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz — keep struct at 48 bytes (3 × 16)
};
namespace Rendering {
/**
* @brief Backend de shaders usando SDL3 GPU API (Metal en macOS, Vulkan/SPIR-V en Win/Linux)
*
* Reemplaza el backend OpenGL para que los shaders PostFX funcionen en macOS.
* Pipeline: Surface pixels (CPU) → SDL_GPUTransferBuffer → SDL_GPUTexture (scene)
* → PostFX render pass → swapchain → present
*/
class SDL3GPUShader : public ShaderBackend {
public:
SDL3GPUShader() = default;
~SDL3GPUShader() override;
auto init(SDL_Window* window,
SDL_Texture* texture,
const std::string& vertex_source,
const std::string& fragment_source) -> bool override;
void render() override;
void setTextureSize(float width, float height) override {}
void cleanup() final; // 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()
void uploadPixels(const Uint32* pixels, int width, int height) override;
// Actualiza los parámetros de intensidad de los efectos PostFX
void setPostFXParams(const PostFXParams& p) override;
// Activa/desactiva VSync en el swapchain
void setVSync(bool vsync) override;
// Activa/desactiva escalado entero (integer scale)
void setScaleMode(bool integer_scale) override;
// Establece factor de supersampling (1 = off, 3 = 3×SS)
void setOversample(int factor) override;
private:
static auto createShaderMSL(SDL_GPUDevice* device,
const char* msl_source,
const char* entrypoint,
SDL_GPUShaderStage stage,
Uint32 num_samplers,
Uint32 num_uniform_buffers) -> SDL_GPUShader*;
static auto createShaderSPIRV(SDL_GPUDevice* device,
const uint8_t* spv_code,
size_t spv_size,
const char* entrypoint,
SDL_GPUShaderStage stage,
Uint32 num_samplers,
Uint32 num_uniform_buffers) -> SDL_GPUShader*;
auto createPipeline() -> bool;
auto reinitTexturesAndBuffer() -> bool; // Recrea textura y buffer con oversample actual
SDL_Window* window_ = nullptr;
SDL_GPUDevice* device_ = nullptr;
SDL_GPUGraphicsPipeline* pipeline_ = nullptr;
SDL_GPUTexture* scene_texture_ = nullptr;
SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
SDL_GPUSampler* sampler_ = nullptr; // NEAREST — para path sin supersampling
SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR — para path con supersampling
PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .oversample = 1.0F};
int game_width_ = 0; // Dimensiones originales del canvas (sin SS)
int game_height_ = 0;
int tex_width_ = 0; // Dimensiones de la textura GPU (game × oversample_)
int tex_height_ = 0;
int oversample_ = 1; // Factor SS actual (1 o 3)
float baked_scanline_strength_ = 0.0F; // Guardado para hornear en CPU
bool is_initialized_ = false;
bool vsync_ = true;
bool integer_scale_ = false;
};
} // namespace Rendering