feat(shaders): sistema de shaders runtime amb presets externs
- Afegir GpuShaderPreset i ShaderManager per carregar shaders des de data/shaders/ - Implementar preset ntsc-md-rainbows (2 passos: encode + decode MAME NTSC) - Render loop multi-pass per shaders externs (targets intermedis R16G16B16A16_FLOAT) - cycleShader(): cicla OFF→PostFX natius→shaders externs amb tecla X - --shader <nom> per arrancar directament amb un preset extern - CMake auto-descubreix i compila data/shaders/**/*.vert/.frag → .spv - HUD F1 mostra 'Shader: <nom>' quan hi ha shader extern actiu Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
94
source/gpu/gpu_shader_preset.hpp
Normal file
94
source/gpu/gpu_shader_preset.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "gpu_texture.hpp"
|
||||
|
||||
// ============================================================================
|
||||
// NTSCParams — uniform buffer for NTSC shader passes (set=3, binding=0)
|
||||
// Matches the layout in pass0_encode.frag and pass1_decode.frag.
|
||||
// Pushed via SDL_PushGPUFragmentUniformData(cmd, 0, &ntsc, sizeof(NTSCParams)).
|
||||
// ============================================================================
|
||||
struct NTSCParams {
|
||||
float source_width;
|
||||
float source_height;
|
||||
float a_value;
|
||||
float b_value;
|
||||
float cc_value;
|
||||
float scan_time;
|
||||
float notch_width;
|
||||
float y_freq;
|
||||
float i_freq;
|
||||
float q_freq;
|
||||
float _pad[2];
|
||||
};
|
||||
static_assert(sizeof(NTSCParams) == 48, "NTSCParams must be 48 bytes");
|
||||
|
||||
// ============================================================================
|
||||
// ShaderPass — one render pass in a multi-pass shader preset
|
||||
// ============================================================================
|
||||
struct ShaderPass {
|
||||
SDL_GPUGraphicsPipeline* pipeline = nullptr;
|
||||
GpuTexture* target = nullptr; // null = swapchain (last pass)
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// GpuShaderPreset — loads and owns a multi-pass shader preset from disk.
|
||||
//
|
||||
// Directory layout:
|
||||
// <dir>/preset.ini — descriptor
|
||||
// <dir>/pass0_xxx.vert — GLSL 4.50 vertex shader source
|
||||
// <dir>/pass0_xxx.frag — GLSL 4.50 fragment shader source
|
||||
// <dir>/pass0_xxx.vert.spv — compiled SPIRV (by CMake/glslc at build time)
|
||||
// <dir>/pass0_xxx.frag.spv — compiled SPIRV
|
||||
// ...
|
||||
// ============================================================================
|
||||
class GpuShaderPreset {
|
||||
public:
|
||||
// Load preset from directory. swapchain_fmt is the target format for the
|
||||
// last pass; intermediate passes use R16G16B16A16_FLOAT.
|
||||
bool load(SDL_GPUDevice* device,
|
||||
const std::string& dir,
|
||||
SDL_GPUTextureFormat swapchain_fmt,
|
||||
int w, int h);
|
||||
|
||||
void destroy(SDL_GPUDevice* device);
|
||||
|
||||
// Recreate intermediate render targets on resolution change.
|
||||
void recreateTargets(SDL_GPUDevice* device, int w, int h);
|
||||
|
||||
int passCount() const { return static_cast<int>(passes_.size()); }
|
||||
ShaderPass& pass(int i) { return passes_[i]; }
|
||||
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
// Read a float parameter parsed from preset.ini (returns default_val if absent).
|
||||
float param(const std::string& key, float default_val) const;
|
||||
|
||||
private:
|
||||
std::vector<ShaderPass> passes_;
|
||||
std::vector<std::unique_ptr<GpuTexture>> targets_; // intermediate render targets
|
||||
std::string name_;
|
||||
std::string dir_;
|
||||
std::unordered_map<std::string, float> params_;
|
||||
SDL_GPUTextureFormat swapchain_fmt_ = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
// Entries read from preset.ini for each pass
|
||||
struct PassDesc {
|
||||
std::string vert_name; // e.g. "pass0_encode.vert"
|
||||
std::string frag_name; // e.g. "pass0_encode.frag"
|
||||
};
|
||||
std::vector<PassDesc> descs_;
|
||||
|
||||
bool parseIni(const std::string& ini_path);
|
||||
|
||||
// Build a full-screen-triangle pipeline from two on-disk SPV files.
|
||||
SDL_GPUGraphicsPipeline* buildPassPipeline(SDL_GPUDevice* device,
|
||||
const std::string& vert_spv_path,
|
||||
const std::string& frag_spv_path,
|
||||
SDL_GPUTextureFormat target_fmt);
|
||||
};
|
||||
Reference in New Issue
Block a user