166 lines
5.4 KiB
C++
166 lines
5.4 KiB
C++
#pragma once
|
||
|
||
#include <SDL3/SDL.h>
|
||
#include <SDL3/SDL_gpu.h>
|
||
|
||
#include <string>
|
||
|
||
#include "core/rendering/shader_backend.hpp"
|
||
|
||
// PostFX uniforms pushed to fragment stage each frame.
|
||
// 16 floats = 64 bytes (4 × vec4) — std140/scalar layout for Vulkan + Metal.
|
||
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;
|
||
};
|
||
|
||
// CrtPi uniforms pushed to fragment stage each frame.
|
||
// 16 fields = 64 bytes — 4 × 16-byte alignment.
|
||
struct CrtPiUniforms {
|
||
float scanline_weight;
|
||
float scanline_gap_brightness;
|
||
float bloom_factor;
|
||
float input_gamma;
|
||
float output_gamma;
|
||
float mask_brightness;
|
||
float curvature_x;
|
||
float curvature_y;
|
||
int mask_type;
|
||
int enable_scanlines;
|
||
int enable_multisample;
|
||
int enable_gamma;
|
||
int enable_curvature;
|
||
int enable_sharper;
|
||
float texture_width;
|
||
float texture_height;
|
||
};
|
||
|
||
namespace Rendering {
|
||
|
||
/**
|
||
* @brief Backend de shaders usando SDL3 GPU API (Metal en macOS, Vulkan/SPIR-V en Win/Linux)
|
||
*
|
||
* Pipeline: Surface pixels (CPU) → SDL_GPUTransferBuffer → SDL_GPUTexture (scene)
|
||
* → PostFX/CrtPi 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;
|
||
void destroy();
|
||
[[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; }
|
||
[[nodiscard]] auto getDriverName() const -> std::string override { return driver_name_; }
|
||
|
||
void setPreferredDriver(const std::string& driver) override { preferred_driver_ = driver; }
|
||
void uploadPixels(const Uint32* pixels, int width, int height) override;
|
||
void setPostFXParams(const PostFXParams& p) override;
|
||
void setVSync(bool vsync) override;
|
||
void setScaleMode(bool integer_scale) override;
|
||
|
||
void setActiveShader(ShaderType type) override;
|
||
void setCrtPiParams(const CrtPiParams& p) override;
|
||
[[nodiscard]] auto getActiveShader() const -> ShaderType override { return active_shader_; }
|
||
|
||
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 createCrtPiPipeline() -> bool;
|
||
auto reinitTexturesAndBuffer() -> bool;
|
||
[[nodiscard]] auto bestPresentMode(bool vsync) const -> SDL_GPUPresentMode;
|
||
|
||
SDL_Window* window_ = nullptr;
|
||
SDL_GPUDevice* device_ = nullptr;
|
||
SDL_GPUGraphicsPipeline* pipeline_ = nullptr;
|
||
SDL_GPUGraphicsPipeline* crtpi_pipeline_ = nullptr;
|
||
SDL_GPUTexture* scene_texture_ = nullptr;
|
||
SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
|
||
SDL_GPUSampler* sampler_ = nullptr;
|
||
|
||
PostFXUniforms uniforms_{
|
||
.vignette_strength = 0.6F,
|
||
.chroma_min = 0.15F,
|
||
.scanline_strength = 0.7F,
|
||
.screen_height = 192.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.15F,
|
||
.scan_dark_ratio = 0.333F,
|
||
.scan_dark_floor = 0.42F,
|
||
.scan_edge_soft = 1.0F,
|
||
.pad3 = 0.0F};
|
||
CrtPiUniforms crtpi_uniforms_{
|
||
.scanline_weight = 6.0F,
|
||
.scanline_gap_brightness = 0.12F,
|
||
.bloom_factor = 3.5F,
|
||
.input_gamma = 2.4F,
|
||
.output_gamma = 2.2F,
|
||
.mask_brightness = 0.80F,
|
||
.curvature_x = 0.05F,
|
||
.curvature_y = 0.10F,
|
||
.mask_type = 2,
|
||
.enable_scanlines = 1,
|
||
.enable_multisample = 1,
|
||
.enable_gamma = 1,
|
||
.enable_curvature = 0,
|
||
.enable_sharper = 0,
|
||
.texture_width = 0.0F,
|
||
.texture_height = 0.0F};
|
||
ShaderType active_shader_ = ShaderType::POSTFX;
|
||
|
||
int game_width_ = 0;
|
||
int game_height_ = 0;
|
||
std::string driver_name_;
|
||
std::string preferred_driver_;
|
||
bool is_initialized_ = false;
|
||
bool vsync_ = true;
|
||
bool integer_scale_ = false;
|
||
};
|
||
|
||
} // namespace Rendering
|