123 lines
4.5 KiB
C++
123 lines
4.5 KiB
C++
#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
|