diff --git a/source/core/input/global_inputs.cpp b/source/core/input/global_inputs.cpp index 9ba4ebf..9862dc8 100644 --- a/source/core/input/global_inputs.cpp +++ b/source/core/input/global_inputs.cpp @@ -160,14 +160,16 @@ namespace GlobalInputs { return InputAction::WINDOW_INC_ZOOM; } } - if (Input::get()->checkAction(InputAction::TOGGLE_SHADER, Input::DO_NOT_ALLOW_REPEAT)) { - if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) { - return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4 + if (Screen::get()->isHardwareAccelerated()) { + if (Input::get()->checkAction(InputAction::TOGGLE_SHADER, Input::DO_NOT_ALLOW_REPEAT)) { + if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) { + return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4 + } + if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) { + return InputAction::NEXT_SHADER_PRESET; // Shift+F4 + } + return InputAction::TOGGLE_SHADER; // F4 } - if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) { - return InputAction::NEXT_SHADER_PRESET; // Shift+F4 - } - return InputAction::TOGGLE_SHADER; // F4 } if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) { return InputAction::NEXT_PALETTE; diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index a5a47ec..d3ca9ca 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -602,7 +602,8 @@ void Screen::initShaders() { if (!shader_backend_) { shader_backend_ = std::make_unique(); - shader_backend_->setPreferredDriver(Options::video.gpu_preferred_driver); + const std::string fallback_driver = "none"; + shader_backend_->setPreferredDriver(Options::video.gpu_acceleration ? Options::video.gpu_preferred_driver : fallback_driver); } shader_backend_->init(window_, tex, "", ""); gpu_driver_ = shader_backend_->getDriverName(); diff --git a/source/core/rendering/screen.hpp b/source/core/rendering/screen.hpp index be6b27e..8c60079 100644 --- a/source/core/rendering/screen.hpp +++ b/source/core/rendering/screen.hpp @@ -58,7 +58,7 @@ class Screen { void previousPalette(); // Cambia a la paleta anterior auto setPaletteByName(const std::string& name) -> bool; // Cambia a paleta por nombre; false si no existe [[nodiscard]] auto getPaletteNames() const -> std::vector; // Nombres disponibles (minúsculas, sin .pal) - [[nodiscard]] auto getPalettePrettyName() const -> std::string; // Nombre actual con guiones sustituidos por espacios + [[nodiscard]] auto getPalettePrettyName() const -> std::string; // Nombre actual con guiones sustituidos por espacios void toggleShaders(); // Activa/desactiva todos los shaders respetando current_shader void toggleSupersampling(); // Activa/desactiva el supersampling global void reloadPostFX(); // Recarga el shader del preset actual sin toggle @@ -81,6 +81,7 @@ class Screen { [[nodiscard]] auto getText() const -> std::shared_ptr { return text_; } [[nodiscard]] auto getGameSurfaceDstRect() const -> SDL_FRect { return game_surface_dstrect_; } [[nodiscard]] auto getGPUDriver() const -> const std::string& { return gpu_driver_; } + [[nodiscard]] auto isHardwareAccelerated() const -> bool { return shader_backend_ && shader_backend_->isHardwareAccelerated(); } [[nodiscard]] auto getLastFPS() const -> int { return fps_.last_value; } [[nodiscard]] auto getZoomFactor() const -> float { return zoom_factor_; } [[nodiscard]] auto getMaxZoom() const -> int; diff --git a/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp b/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp index 3105459..4bed8c1 100644 --- a/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp +++ b/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp @@ -403,7 +403,7 @@ namespace Rendering { // ---------------------------------------------------------------- if (preferred_driver_ == "none") { SDL_Log("SDL3GPUShader: GPU disabled by config, using SDL_Renderer fallback"); - driver_name_ = "none"; + driver_name_ = ""; // vacío → RenderInfo mostrará "sdl" return false; } if (device_ == nullptr) { diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index a10afdb..b34f56c 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -32,6 +32,7 @@ namespace Defaults::Video { constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto constexpr bool LINEAR_UPSCALE = false; // Upscale NEAREST por defecto constexpr int DOWNSCALE_ALGO = 1; // Downscale Lanczos2 por defecto + constexpr bool GPU_ACCELERATION = true; // Aceleración GPU activada por defecto } // namespace Defaults::Video namespace Defaults::Border { diff --git a/source/game/options.cpp b/source/game/options.cpp index 49553ca..f01911c 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -399,6 +399,14 @@ namespace Options { } } + if (vid.contains("gpu_acceleration")) { + try { + video.gpu_acceleration = vid["gpu_acceleration"].get_value(); + } catch (...) { + video.gpu_acceleration = Defaults::Video::GPU_ACCELERATION; + } + } + if (vid.contains("gpu_preferred_driver")) { try { video.gpu_preferred_driver = vid["gpu_preferred_driver"].get_value(); @@ -715,7 +723,8 @@ namespace Options { file << " keep_aspect: " << (video.keep_aspect ? "true" : "false") << "\n"; file << " linear_upscale: " << (video.linear_upscale ? "true" : "false") << "\n"; file << " downscale_algo: " << video.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n"; - file << " gpu_preferred_driver: \"" << video.gpu_preferred_driver << "\" # GPU driver (empty = auto)\n"; + file << " gpu_acceleration: " << (video.gpu_acceleration ? "true" : "false") << " # Usar aceleración hardware GPU (false = SDL fallback)\n"; + file << " gpu_preferred_driver: \"" << video.gpu_preferred_driver << "\" # Driver GPU específico (empty = auto, aplica solo si gpu_acceleration: true)\n"; file << " palette: " << video.palette << "\n"; file << " border:\n"; file << " enabled: " << (video.border.enabled ? "true" : "false") << "\n"; diff --git a/source/game/options.hpp b/source/game/options.hpp index a07fd8a..b3d874b 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -77,19 +77,20 @@ namespace Options { // Estructura para las opciones de video struct Video { - bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa - Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen - bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no - bool postfx{Defaults::Video::POSTFX}; // Indica si se van a usar efectos PostFX o no - bool supersampling{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo - bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa - bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa - bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false) - int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3 - Border border{}; // Borde de la pantalla - std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego - std::string info; // Información sobre el modo de vídeo - std::string gpu_preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque. + bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa + Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen + bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no + bool postfx{Defaults::Video::POSTFX}; // Indica si se van a usar efectos PostFX o no + bool supersampling{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo + bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa + bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa + bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false) + int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3 + Border border{}; // Borde de la pantalla + std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego + std::string info; // Información sobre el modo de vídeo + bool gpu_acceleration{Defaults::Video::GPU_ACCELERATION}; // Usar aceleración GPU; false = path SDL fallback directo + std::string gpu_preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque. }; // Estructura para las opciones de musica diff --git a/source/game/ui/console.cpp b/source/game/ui/console.cpp index d32eced..0d46c0f 100644 --- a/source/game/ui/console.cpp +++ b/source/game/ui/console.cpp @@ -147,6 +147,7 @@ static constexpr bool CHEAT_HIDDEN = true; static const std::vector COMMANDS = { // SS [ON|OFF|SIZE|UPSCALE [NEAREST|LINEAR]|DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3]] — Supersampling {.keyword = "SS", .execute = [](const std::vector& args) -> std::string { + if (!Screen::get()->isHardwareAccelerated()) { return "No GPU acceleration"; } static const std::array DOWNSCALE_NAMES = {"Bilinear", "Lanczos2", "Lanczos3"}; if (!args.empty() && args[0] == "SIZE") { if (!Options::video.supersampling) { return "Supersampling is OFF: no texture"; } @@ -210,6 +211,7 @@ static const std::vector COMMANDS = { // SHADER [ON|OFF|NEXT [PRESET]|POSTFX|CRTPI] — Toggle/cicla/selecciona shader (F4 / Shift+F4) {.keyword = "SHADER", .execute = [](const std::vector& args) -> std::string { + if (!Screen::get()->isHardwareAccelerated()) { return "No GPU acceleration"; } if (args.empty()) { Screen::get()->toggleShaders(); return std::string("Shader ") + (Options::video.postfx ? "ON" : "OFF");