primera implementacio de sdl3gpu
This commit is contained in:
@@ -18,6 +18,7 @@ namespace GlobalInputs {
|
||||
static bool ss_prev = false;
|
||||
static bool next_shader_prev = false;
|
||||
static bool next_preset_prev = false;
|
||||
static bool stretch_filter_prev = false;
|
||||
|
||||
auto handle() -> bool {
|
||||
bool consumed = false;
|
||||
@@ -84,7 +85,9 @@ namespace GlobalInputs {
|
||||
bool next_shader = JI_KeyPressed(Options::keys_gui.next_shader);
|
||||
if (next_shader && !next_shader_prev) {
|
||||
Screen::get()->nextShaderPreset();
|
||||
Overlay::showNotification(Screen::get()->isHardwareAccelerated() ? "POSTFX / CRT-PI" : "SENSE GPU");
|
||||
char msg[32];
|
||||
snprintf(msg, sizeof(msg), "SHADER: %s", Screen::get()->getActiveShaderName());
|
||||
Overlay::showNotification(msg);
|
||||
}
|
||||
if (next_shader) consumed = true;
|
||||
next_shader_prev = next_shader;
|
||||
@@ -98,6 +101,15 @@ namespace GlobalInputs {
|
||||
if (next_preset) consumed = true;
|
||||
next_preset_prev = next_preset;
|
||||
|
||||
// F9 — Toggle filtre d'estirament 4:3 (NEAREST ↔ LINEAR)
|
||||
bool stretch_filter = JI_KeyPressed(Options::keys_gui.toggle_stretch_filter);
|
||||
if (stretch_filter && !stretch_filter_prev) {
|
||||
Screen::get()->toggleStretchFilter();
|
||||
Overlay::showNotification(Options::video.stretch_filter_linear ? "FILTRE: LINEAR" : "FILTRE: NEAREST");
|
||||
}
|
||||
if (stretch_filter) consumed = true;
|
||||
stretch_filter_prev = stretch_filter;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ static bool isGuiKey(SDL_Scancode sc) {
|
||||
sc == Options::keys_gui.toggle_aspect_ratio ||
|
||||
sc == Options::keys_gui.toggle_supersampling ||
|
||||
sc == Options::keys_gui.next_shader ||
|
||||
sc == Options::keys_gui.next_shader_preset;
|
||||
sc == Options::keys_gui.next_shader_preset ||
|
||||
sc == Options::keys_gui.toggle_stretch_filter;
|
||||
}
|
||||
|
||||
void JI_DisableKeyboard(Uint32 time) {
|
||||
|
||||
@@ -88,6 +88,7 @@ void Screen::initShaders() {
|
||||
|
||||
// Aplica opcions de vídeo
|
||||
shader_backend_->setScaleMode(Options::video.integer_scale);
|
||||
shader_backend_->setStretchFilter(Options::video.stretch_filter_linear);
|
||||
shader_backend_->setStretch4_3(Options::video.aspect_ratio_4_3);
|
||||
shader_backend_->setLinearUpscale(Options::video.linear_upscale);
|
||||
shader_backend_->setDownscaleAlgo(Options::video.downscale_algo);
|
||||
@@ -179,6 +180,13 @@ void Screen::toggleIntegerScale() {
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::toggleStretchFilter() {
|
||||
Options::video.stretch_filter_linear = !Options::video.stretch_filter_linear;
|
||||
if (shader_backend_) {
|
||||
shader_backend_->setStretchFilter(Options::video.stretch_filter_linear);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::nextShaderPreset() {
|
||||
if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) return;
|
||||
|
||||
@@ -224,6 +232,11 @@ auto Screen::isHardwareAccelerated() const -> bool {
|
||||
return shader_backend_ && shader_backend_->isHardwareAccelerated();
|
||||
}
|
||||
|
||||
auto Screen::getActiveShaderName() const -> const char* {
|
||||
if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) return "SENSE GPU";
|
||||
return shader_backend_->getActiveShader() == Rendering::ShaderType::POSTFX ? "POSTFX" : "CRT-PI";
|
||||
}
|
||||
|
||||
void Screen::adjustWindowSize() {
|
||||
int w = GAME_WIDTH * zoom_;
|
||||
// Si 4:3 actiu, l'alçada visual és 240 per zoom (200 * 1.2)
|
||||
|
||||
@@ -27,7 +27,8 @@ class Screen {
|
||||
void toggleSupersampling();
|
||||
void toggleAspectRatio();
|
||||
void toggleIntegerScale();
|
||||
void nextShaderPreset(); // Futur: ciclar presets
|
||||
void toggleStretchFilter();
|
||||
void nextShaderPreset();
|
||||
void setActiveShader(Rendering::ShaderType type);
|
||||
void applyCurrentPostFXPreset();
|
||||
void applyCurrentCrtPiPreset();
|
||||
@@ -36,6 +37,7 @@ class Screen {
|
||||
[[nodiscard]] auto isFullscreen() const -> bool { return fullscreen_; }
|
||||
[[nodiscard]] auto getZoom() const -> int { return zoom_; }
|
||||
[[nodiscard]] auto isHardwareAccelerated() const -> bool;
|
||||
[[nodiscard]] auto getActiveShaderName() const -> const char*;
|
||||
[[nodiscard]] auto getWindow() -> SDL_Window* { return window_; }
|
||||
[[nodiscard]] auto getRenderer() -> SDL_Renderer* { return renderer_; }
|
||||
|
||||
|
||||
@@ -812,23 +812,40 @@ namespace Rendering {
|
||||
SDL_EndGPUCopyPass(copy);
|
||||
}
|
||||
|
||||
// ---- Upscale pass: scene_texture_ → scaled_texture_ (NEAREST o LINEAR según linear_upscale_) ----
|
||||
// ---- Upscale pass: scene_texture_ → scaled_texture_ ----
|
||||
// Si 4:3 actiu, l'estirament s'aplica ací directament (320x200 → W*factor × H*factor*1.2)
|
||||
// El filtre per al 4:3 és configurable (stretch_filter_linear_).
|
||||
// L'effective_scene/height reflecteix la textura real que veuen els shaders.
|
||||
// Sense SS ni stretch: scene_texture_ a game_height_.
|
||||
// Amb SS o stretch: scaled_texture_ a l'alçada escalada (amb o sense 4:3).
|
||||
SDL_GPUTexture* effective_scene = scene_texture_;
|
||||
int effective_height = game_height_;
|
||||
|
||||
if (oversample_ > 1 && scaled_texture_ != nullptr && upscale_pipeline_ != nullptr) {
|
||||
SDL_GPUColorTargetInfo upscale_target = {};
|
||||
upscale_target.texture = scaled_texture_;
|
||||
upscale_target.load_op = SDL_GPU_LOADOP_DONT_CARE;
|
||||
upscale_target.store_op = SDL_GPU_STOREOP_STORE;
|
||||
|
||||
// Triar filtre: si 4:3 actiu, usar el filtre configurable per a l'estirament.
|
||||
// Si no, usar el filtre d'upscale normal (linear_upscale_).
|
||||
bool use_linear = stretch_4_3_ ? stretch_filter_linear_ : linear_upscale_;
|
||||
|
||||
SDL_GPURenderPass* upass = SDL_BeginGPURenderPass(cmd, &upscale_target, 1, nullptr);
|
||||
if (upass != nullptr) {
|
||||
SDL_BindGPUGraphicsPipeline(upass, upscale_pipeline_);
|
||||
SDL_GPUTextureSamplerBinding ubinding = {};
|
||||
ubinding.texture = scene_texture_;
|
||||
ubinding.sampler = (linear_upscale_ && linear_sampler_ != nullptr) ? linear_sampler_ : sampler_;
|
||||
ubinding.sampler = (use_linear && linear_sampler_ != nullptr) ? linear_sampler_ : sampler_;
|
||||
SDL_BindGPUFragmentSamplers(upass, 0, &ubinding, 1);
|
||||
SDL_DrawGPUPrimitives(upass, 3, 1, 0, 0);
|
||||
SDL_EndGPURenderPass(upass);
|
||||
}
|
||||
effective_scene = scaled_texture_;
|
||||
effective_height = stretch_4_3_ ? static_cast<int>(static_cast<float>(game_height_) * 1.2F) : game_height_;
|
||||
} else if (stretch_4_3_) {
|
||||
// Sense SS: el viewport s'encarrega de l'estirament geomètric
|
||||
effective_height = static_cast<int>(static_cast<float>(game_height_) * 1.2F);
|
||||
}
|
||||
|
||||
// ---- Acquire swapchain texture ----
|
||||
@@ -846,10 +863,10 @@ namespace Rendering {
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- Calcular viewport (dimensions lògiques del canvas, no de textura GPU) ----
|
||||
// Si stretch_4_3_ actiu, l'alçada lògica es multiplica per 1.2 (200→240) per simular 4:3 CRT
|
||||
// ---- Calcular viewport (dimensions lògiques del canvas) ----
|
||||
// Si 4:3 actiu, effective_height ja és 240 (la textura estirada)
|
||||
const float logical_w = static_cast<float>(game_width_);
|
||||
const float logical_h = stretch_4_3_ ? static_cast<float>(game_height_) * 1.2F : static_cast<float>(game_height_);
|
||||
const float logical_h = static_cast<float>(effective_height);
|
||||
|
||||
float vx = 0.0F;
|
||||
float vy = 0.0F;
|
||||
@@ -869,14 +886,15 @@ namespace Rendering {
|
||||
vx = std::floor((static_cast<float>(sw) - vw) * 0.5F);
|
||||
vy = std::floor((static_cast<float>(sh) - vh) * 0.5F);
|
||||
|
||||
// pixel_scale: subpíxeles por pixel lógico.
|
||||
// Sin SS: vh/game_height (zoom de ventana).
|
||||
// Con SS: ss_factor_ exacto (3, 6, 9...).
|
||||
// pixel_scale: subpíxels per píxel lògic.
|
||||
// Sense SS: vh/effective_height (zoom de finestra).
|
||||
// Amb SS: ss_factor_ exacte (3, 6, 9...).
|
||||
if (oversample_ > 1 && ss_factor_ > 0) {
|
||||
uniforms_.pixel_scale = static_cast<float>(ss_factor_);
|
||||
} else {
|
||||
uniforms_.pixel_scale = (game_height_ > 0) ? (vh / static_cast<float>(game_height_)) : 1.0F;
|
||||
uniforms_.pixel_scale = (effective_height > 0) ? (vh / static_cast<float>(effective_height)) : 1.0F;
|
||||
}
|
||||
uniforms_.screen_height = static_cast<float>(effective_height);
|
||||
uniforms_.time = static_cast<float>(SDL_GetTicks()) / 1000.0F;
|
||||
uniforms_.oversample = (oversample_ > 1 && ss_factor_ > 0)
|
||||
? static_cast<float>(ss_factor_)
|
||||
@@ -897,13 +915,13 @@ namespace Rendering {
|
||||
SDL_SetGPUViewport(pass, &vp);
|
||||
|
||||
SDL_GPUTextureSamplerBinding binding = {};
|
||||
binding.texture = scene_texture_;
|
||||
binding.sampler = sampler_; // NEAREST: el shader CrtPi hace su propio filtrado analítico
|
||||
binding.texture = effective_scene;
|
||||
binding.sampler = sampler_; // NEAREST: el shader CrtPi fa el seu propi filtrat analític
|
||||
SDL_BindGPUFragmentSamplers(pass, 0, &binding, 1);
|
||||
|
||||
// Inyectar texture_width/height antes del push
|
||||
// Injectar texture_width/height abans del push
|
||||
crtpi_uniforms_.texture_width = static_cast<float>(game_width_);
|
||||
crtpi_uniforms_.texture_height = static_cast<float>(game_height_);
|
||||
crtpi_uniforms_.texture_height = static_cast<float>(effective_height);
|
||||
SDL_PushGPUFragmentUniformData(cmd, 0, &crtpi_uniforms_, sizeof(CrtPiUniforms));
|
||||
|
||||
SDL_DrawGPUPrimitives(pass, 3, 1, 0, 0);
|
||||
@@ -973,10 +991,10 @@ namespace Rendering {
|
||||
SDL_GPUViewport vp = {.x = vx, .y = vy, .w = vw, .h = vh, .min_depth = 0.0F, .max_depth = 1.0F};
|
||||
SDL_SetGPUViewport(pass, &vp);
|
||||
|
||||
// Con SS: leer de scaled_texture_ con LINEAR; sin SS: scene_texture_ con NEAREST.
|
||||
// Amb SS: llegir de scaled_texture_ amb LINEAR; sense SS: effective_scene amb NEAREST.
|
||||
SDL_GPUTexture* input_texture = (oversample_ > 1 && scaled_texture_ != nullptr)
|
||||
? scaled_texture_
|
||||
: scene_texture_;
|
||||
: effective_scene;
|
||||
SDL_GPUSampler* active_sampler = (oversample_ > 1 && linear_sampler_ != nullptr)
|
||||
? linear_sampler_
|
||||
: sampler_;
|
||||
@@ -1179,6 +1197,17 @@ namespace Rendering {
|
||||
integer_scale_ = integer_scale;
|
||||
}
|
||||
|
||||
void SDL3GPUShader::setStretch4_3(bool enabled) {
|
||||
stretch_4_3_ = enabled;
|
||||
if (!is_initialized_ || device_ == nullptr) return;
|
||||
|
||||
// Recrear scaled_texture_ perquè tinga les dimensions correctes (amb o sense 4:3)
|
||||
if (oversample_ > 1 && ss_factor_ > 0) {
|
||||
SDL_WaitForGPUIdle(device_);
|
||||
recreateScaledTexture(ss_factor_);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// setOversample — cambia el factor SS; recrea texturas si ya está inicializado
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1292,7 +1321,10 @@ namespace Rendering {
|
||||
ss_factor_ = 0;
|
||||
|
||||
const int W = game_width_ * factor;
|
||||
const int H = game_height_ * factor;
|
||||
// Si 4:3 actiu, l'alçada inclou l'estirament (200 * factor * 1.2)
|
||||
const int H = stretch_4_3_
|
||||
? static_cast<int>(static_cast<float>(game_height_) * 1.2F * static_cast<float>(factor))
|
||||
: game_height_ * factor;
|
||||
|
||||
SDL_GPUTextureCreateInfo info = {};
|
||||
info.type = SDL_GPU_TEXTURETYPE_2D;
|
||||
|
||||
@@ -120,9 +120,10 @@ namespace Rendering {
|
||||
// Devuelve el shader activo
|
||||
[[nodiscard]] auto getActiveShader() const -> ShaderType override { return active_shader_; }
|
||||
|
||||
// Estirament vertical 4:3 (320x200 → 320x240 visual al viewport)
|
||||
void setStretch4_3(bool enabled) override { stretch_4_3_ = enabled; }
|
||||
// Estirament vertical 4:3 (fusionat amb l'upscale pass)
|
||||
void setStretch4_3(bool enabled) override;
|
||||
[[nodiscard]] auto isStretch4_3() const -> bool override { return stretch_4_3_; }
|
||||
void setStretchFilter(bool linear) override { stretch_filter_linear_ = linear; }
|
||||
|
||||
private:
|
||||
static auto createShaderMSL(SDL_GPUDevice* device,
|
||||
@@ -155,9 +156,9 @@ namespace Rendering {
|
||||
SDL_GPUGraphicsPipeline* postfx_offscreen_pipeline_ = nullptr; // PostFX → postfx_texture_ (B8G8R8A8, solo con Lanczos)
|
||||
SDL_GPUGraphicsPipeline* upscale_pipeline_ = nullptr; // Upscale pass (solo con SS)
|
||||
SDL_GPUGraphicsPipeline* downscale_pipeline_ = nullptr; // Lanczos downscale (solo con SS + algo > 0)
|
||||
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_)
|
||||
SDL_GPUTexture* scaled_texture_ = nullptr; // Upscale target (game×factor), solo con SS
|
||||
SDL_GPUTexture* postfx_texture_ = nullptr; // PostFX output a resolución escalada, solo con Lanczos
|
||||
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del joc (game_width_ × game_height_)
|
||||
SDL_GPUTexture* scaled_texture_ = nullptr; // Upscale target (game×factor, amb 4:3 si actiu)
|
||||
SDL_GPUTexture* postfx_texture_ = nullptr; // PostFX output a resolució escalada, sols amb Lanczos
|
||||
SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
|
||||
SDL_GPUSampler* sampler_ = nullptr; // NEAREST
|
||||
SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR
|
||||
@@ -166,7 +167,7 @@ namespace Rendering {
|
||||
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};
|
||||
ShaderType active_shader_ = ShaderType::POSTFX; // Shader de post-procesado activo
|
||||
|
||||
int game_width_ = 0; // Dimensiones originales del canvas
|
||||
int game_width_ = 0; // Dimensions originals del canvas
|
||||
int game_height_ = 0;
|
||||
int ss_factor_ = 0; // Factor SS activo (3, 6, 9...) o 0 si SS desactivado
|
||||
int oversample_ = 1; // SS on/off (1 = off, >1 = on)
|
||||
@@ -177,7 +178,8 @@ namespace Rendering {
|
||||
bool vsync_ = true;
|
||||
bool integer_scale_ = false;
|
||||
bool linear_upscale_ = false; // Upscale NEAREST (false) o LINEAR (true)
|
||||
bool stretch_4_3_ = false; // Estirament vertical 4:3 al viewport
|
||||
bool stretch_4_3_ = false; // Estirament vertical 4:3
|
||||
bool stretch_filter_linear_ = false; // Filtre per a l'estirament 4:3 (false=NEAREST, true=LINEAR)
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -177,6 +177,11 @@ namespace Rendering {
|
||||
*/
|
||||
virtual void setStretch4_3(bool /*enabled*/) {}
|
||||
[[nodiscard]] virtual auto isStretch4_3() const -> bool { return false; }
|
||||
|
||||
/**
|
||||
* @brief Filtre per a l'estirament 4:3 (false=NEAREST, true=LINEAR).
|
||||
*/
|
||||
virtual void setStretchFilter(bool /*linear*/) {}
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Defaults::KeysGUI {
|
||||
constexpr SDL_Scancode TOGGLE_SUPERSAMPLING = SDL_SCANCODE_F6;
|
||||
constexpr SDL_Scancode NEXT_SHADER = SDL_SCANCODE_F7;
|
||||
constexpr SDL_Scancode NEXT_SHADER_PRESET = SDL_SCANCODE_F8;
|
||||
constexpr SDL_Scancode TOGGLE_STRETCH_FILTER = SDL_SCANCODE_F9;
|
||||
} // namespace Defaults::KeysGUI
|
||||
|
||||
// Tecles de joc (moviment del personatge, accions)
|
||||
@@ -29,6 +30,7 @@ namespace Defaults::Video {
|
||||
constexpr bool SUPERSAMPLING = false;
|
||||
constexpr bool INTEGER_SCALE = true;
|
||||
constexpr bool ASPECT_RATIO_4_3 = true; // CRT original estira 200→240
|
||||
constexpr bool STRETCH_FILTER_LINEAR = false; // Filtre per a l'estirament 4:3 (false=NEAREST)
|
||||
constexpr int DOWNSCALE_ALGO = 1; // 0=bilinear, 1=Lanczos2, 2=Lanczos3
|
||||
constexpr bool LINEAR_UPSCALE = false;
|
||||
} // namespace Defaults::Video
|
||||
|
||||
@@ -55,6 +55,8 @@ namespace Options {
|
||||
video.integer_scale = node["integer_scale"].get_value<bool>();
|
||||
if (node.contains("aspect_ratio_4_3"))
|
||||
video.aspect_ratio_4_3 = node["aspect_ratio_4_3"].get_value<bool>();
|
||||
if (node.contains("stretch_filter_linear"))
|
||||
video.stretch_filter_linear = node["stretch_filter_linear"].get_value<bool>();
|
||||
if (node.contains("downscale_algo"))
|
||||
video.downscale_algo = node["downscale_algo"].get_value<int>();
|
||||
if (node.contains("linear_upscale"))
|
||||
@@ -158,6 +160,7 @@ namespace Options {
|
||||
file << " supersampling: " << (video.supersampling ? "true" : "false") << "\n";
|
||||
file << " integer_scale: " << (video.integer_scale ? "true" : "false") << "\n";
|
||||
file << " aspect_ratio_4_3: " << (video.aspect_ratio_4_3 ? "true" : "false") << "\n";
|
||||
file << " stretch_filter_linear: " << (video.stretch_filter_linear ? "true" : "false") << " # filtre 4:3: false=nearest, true=linear\n";
|
||||
file << " downscale_algo: " << video.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n";
|
||||
file << " linear_upscale: " << (video.linear_upscale ? "true" : "false") << "\n";
|
||||
file << "\n";
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Options {
|
||||
SDL_Scancode toggle_supersampling{Defaults::KeysGUI::TOGGLE_SUPERSAMPLING};
|
||||
SDL_Scancode next_shader{Defaults::KeysGUI::NEXT_SHADER};
|
||||
SDL_Scancode next_shader_preset{Defaults::KeysGUI::NEXT_SHADER_PRESET};
|
||||
SDL_Scancode toggle_stretch_filter{Defaults::KeysGUI::TOGGLE_STRETCH_FILTER};
|
||||
};
|
||||
|
||||
// Tecles de joc (moviment, accions)
|
||||
@@ -35,6 +36,7 @@ namespace Options {
|
||||
bool supersampling{Defaults::Video::SUPERSAMPLING};
|
||||
bool integer_scale{Defaults::Video::INTEGER_SCALE};
|
||||
bool aspect_ratio_4_3{Defaults::Video::ASPECT_RATIO_4_3};
|
||||
bool stretch_filter_linear{Defaults::Video::STRETCH_FILTER_LINEAR};
|
||||
int downscale_algo{Defaults::Video::DOWNSCALE_ALGO};
|
||||
bool linear_upscale{Defaults::Video::LINEAR_UPSCALE};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user