109 lines
3.9 KiB
C++
109 lines
3.9 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 (48 bytes, alineats a 16).
|
|
struct PostFXUniforms {
|
|
float vignette_strength;
|
|
float chroma_strength;
|
|
float scanline_strength;
|
|
float screen_height;
|
|
float mask_strength;
|
|
float gamma_strength;
|
|
float curvature;
|
|
float bleeding;
|
|
float pixel_scale;
|
|
float time;
|
|
float oversample;
|
|
float flicker;
|
|
};
|
|
|
|
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. Sense supersampling, sense
|
|
// CrtPi i sense Lanczos (reservats per a fases següents).
|
|
//
|
|
// 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 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();
|
|
|
|
[[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_strength = 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,
|
|
.oversample = 1.0F,
|
|
.flicker = 0.0F,
|
|
};
|
|
|
|
int game_width_{0};
|
|
int game_height_{0};
|
|
std::string preferred_driver_;
|
|
std::string driver_name_;
|
|
bool vsync_{true};
|
|
bool is_ready_{false};
|
|
};
|
|
|
|
} // namespace Rendering
|