Files
aee-arcade/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp
T

123 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
#include <cstdint>
#include <memory>
#include <string>
#include "core/rendering/sdl3gpu/pipelines/crtpi_pipeline.hpp"
#include "core/rendering/shader_backend.hpp"
// Uniforms enviats al fragment stage cada frame.
// Han de coincidir amb l'estructura MSL/GLSL (64 bytes = 4 × vec4, alineats a 16).
struct PostFXUniforms {
// vec4 #0
float vignette_strength;
float chroma_min;
float scanline_strength;
float screen_height;
// vec4 #1
float mask_strength;
float gamma_strength;
float curvature;
float bleeding;
// vec4 #2
float pixel_scale;
float time;
float flicker;
float chroma_max;
// vec4 #3 — paràmetres de scanlines exposats al preset YAML
float scan_dark_ratio;
float scan_dark_floor;
float scan_edge_soft;
float pad3;
};
namespace Rendering {
// Backend GPU basat en SDL3 GPU API (Vulkan/SPIR-V a Linux i Windows,
// Metal/MSL a macOS). Pipeline únic: CPU framebuffer → transfer buffer →
// scene texture → PostFX pass → swapchain.
//
// Marcat `final` perquè el destructor crida cleanup() (que és virtual);
// sense final, clang-tidy avisa de dispatch virtual durant destrucció.
class SDL3GPUShader final : public ShaderBackend {
public:
SDL3GPUShader() = default;
~SDL3GPUShader() override;
SDL3GPUShader(const SDL3GPUShader&) = delete;
SDL3GPUShader(SDL3GPUShader&&) = delete;
auto operator=(const SDL3GPUShader&) -> SDL3GPUShader& = delete;
auto operator=(SDL3GPUShader&&) -> SDL3GPUShader& = delete;
auto init(SDL_Window* window, int game_width, int game_height) -> bool override;
void uploadPixels(const std::uint32_t* pixels, int width, int height) override;
void render() override;
void setPostFXParams(const PostFXParams& params) override;
void setActiveShader(ShaderType type) override { active_shader_ = type; }
void setCrtPiParams(const CrtPiParams& params) override;
void setVSync(bool vsync) override;
void setScalingMode(Defaults::ScalingMode mode) override { scaling_mode_ = mode; }
void setPreferredDriver(const std::string& driver) override { preferred_driver_ = driver; }
void cleanup() override;
// Allibera la finestra del device sense destruir el device. Cal cridar-ho
// abans de SDL_DestroyWindow perquè el VkSurface tancat no sobrevisca la
// finestra de Wayland (vkDestroyInstance cridaria Wayland amb surface invàlida).
void releaseWindow() override;
[[nodiscard]] auto isReady() const -> bool override { return is_ready_; }
[[nodiscard]] auto getDriverName() const -> std::string override { return driver_name_; }
private:
auto createDevice() -> bool;
auto createShaders() -> bool;
auto createPipeline() -> bool;
auto createResources() -> bool;
[[nodiscard]] auto bestPresentMode(bool vsync) const -> SDL_GPUPresentMode;
SDL_Window* window_{nullptr};
SDL_GPUDevice* device_{nullptr};
SDL_GPUShader* vertex_shader_{nullptr};
SDL_GPUShader* fragment_shader_{nullptr};
SDL_GPUGraphicsPipeline* pipeline_{nullptr};
SDL_GPUTexture* scene_texture_{nullptr};
SDL_GPUTransferBuffer* upload_buffer_{nullptr};
SDL_GPUSampler* sampler_{nullptr};
std::unique_ptr<CrtPiPipeline> crtpi_pipeline_;
ShaderType active_shader_{ShaderType::POSTFX};
PostFXUniforms uniforms_{
.vignette_strength = 0.0F,
.chroma_min = 0.0F,
.scanline_strength = 0.0F,
.screen_height = 0.0F,
.mask_strength = 0.0F,
.gamma_strength = 0.0F,
.curvature = 0.0F,
.bleeding = 0.0F,
.pixel_scale = 1.0F,
.time = 0.0F,
.flicker = 0.0F,
.chroma_max = 0.0F,
// Defaults canònics: 2/3 brillant + 1/3 fosca, brillantor 42%, suavitzat complet (1 px físic).
.scan_dark_ratio = 0.333F,
.scan_dark_floor = 0.42F,
.scan_edge_soft = 1.0F,
.pad3 = 0.0F,
};
int game_width_{0};
int game_height_{0};
Defaults::ScalingMode scaling_mode_{Defaults::Video::SCALING_MODE};
std::string preferred_driver_;
std::string driver_name_;
bool vsync_{true};
bool is_ready_{false};
};
} // namespace Rendering