mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
update
This commit is contained in:
parent
dc2e45bc89
commit
8e070e8b1c
27 changed files with 263 additions and 146 deletions
|
@ -172,6 +172,7 @@ target_link_libraries(rpcs3_emu
|
|||
|
||||
# Cell
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Cell/ErrorCodes.cpp
|
||||
Cell/MFC.cpp
|
||||
Cell/PPUAnalyser.cpp
|
||||
Cell/PPUDisAsm.cpp
|
||||
|
|
|
@ -498,6 +498,9 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector<std::string>& argv, std::vector<
|
|||
};
|
||||
|
||||
signal_system_cache_can_stay();
|
||||
|
||||
// Make sure we keep the game window opened
|
||||
Emu.SetContinuousMode(true);
|
||||
Emu.Kill(false);
|
||||
});
|
||||
|
||||
|
|
|
@ -52,6 +52,14 @@ GLGSRender::GLGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||
backend_config.supports_normalized_barycentrics = true;
|
||||
}
|
||||
|
||||
GLGSRender::~GLGSRender()
|
||||
{
|
||||
if (m_frame)
|
||||
{
|
||||
m_frame->reset();
|
||||
}
|
||||
}
|
||||
|
||||
extern CellGcmContextData current_context;
|
||||
|
||||
void GLGSRender::set_viewport()
|
||||
|
|
|
@ -159,6 +159,7 @@ public:
|
|||
|
||||
GLGSRender(utils::serial* ar) noexcept;
|
||||
GLGSRender() noexcept : GLGSRender(nullptr) {}
|
||||
virtual ~GLGSRender();
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
virtual ~GSFrameBase() = default;
|
||||
|
||||
virtual void close() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual bool shown() = 0;
|
||||
virtual void hide() = 0;
|
||||
virtual void show() = 0;
|
||||
|
|
|
@ -18,7 +18,7 @@ GSRender::~GSRender()
|
|||
{
|
||||
m_context = nullptr;
|
||||
|
||||
if (m_frame)
|
||||
if (m_frame && !m_continuous_mode)
|
||||
{
|
||||
m_frame->close();
|
||||
}
|
||||
|
@ -39,7 +39,10 @@ void GSRender::on_exit()
|
|||
|
||||
if (m_frame)
|
||||
{
|
||||
m_frame->hide();
|
||||
if (!m_continuous_mode)
|
||||
{
|
||||
m_frame->hide();
|
||||
}
|
||||
m_frame->delete_context(m_context);
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
|
|
@ -21,12 +21,15 @@ class GSRender : public rsx::thread
|
|||
protected:
|
||||
GSFrameBase* m_frame;
|
||||
draw_context_t m_context = nullptr;
|
||||
bool m_continuous_mode = false;
|
||||
|
||||
public:
|
||||
~GSRender() override;
|
||||
|
||||
GSRender(utils::serial* ar) noexcept;
|
||||
|
||||
void set_continuous_mode(bool continuous_mode) { m_continuous_mode = continuous_mode; }
|
||||
|
||||
void on_init_thread() override;
|
||||
void on_exit() override;
|
||||
|
||||
|
|
|
@ -114,6 +114,8 @@ namespace rsx
|
|||
|
||||
Emu.CallFromMainThread([]()
|
||||
{
|
||||
// Make sure we keep the game window opened
|
||||
Emu.SetContinuousMode(true);
|
||||
Emu.Restart(false);
|
||||
});
|
||||
return page_navigation::exit;
|
||||
|
|
|
@ -26,6 +26,9 @@ namespace rsx
|
|||
if (!suspend_mode)
|
||||
{
|
||||
Emu.after_kill_callback = []() { Emu.Restart(); };
|
||||
|
||||
// Make sure we keep the game window opened
|
||||
Emu.SetContinuousMode(true);
|
||||
}
|
||||
Emu.Kill(false, true);
|
||||
});
|
||||
|
|
|
@ -60,13 +60,13 @@
|
|||
#include "Emu/RSX/VK/VulkanAPI.h"
|
||||
#endif
|
||||
|
||||
#include "Emu/RSX/GSRender.h"
|
||||
|
||||
LOG_CHANNEL(sys_log, "SYS");
|
||||
|
||||
// Preallocate 32 MiB
|
||||
stx::manual_typemap<void, 0x20'00000, 128> g_fixed_typemap;
|
||||
|
||||
bool g_log_all_errors = false;
|
||||
|
||||
bool g_use_rtm = false;
|
||||
u64 g_rtm_tx_limit1 = 0;
|
||||
u64 g_rtm_tx_limit2 = 0;
|
||||
|
@ -964,6 +964,11 @@ game_boot_result Emulator::BootGame(const std::string& path, const std::string&
|
|||
std::tie(m_path, m_path_original, argv, envp, data, disc, klic, hdd1, m_config_mode, m_config_path) = std::move(save_args);
|
||||
};
|
||||
}
|
||||
|
||||
if (result != game_boot_result::no_errors)
|
||||
{
|
||||
GetCallbacks().close_gs_frame();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1005,6 +1010,16 @@ void Emulator::SetForceBoot(bool force_boot)
|
|||
m_force_boot = force_boot;
|
||||
}
|
||||
|
||||
void Emulator::SetContinuousMode(bool continuous_mode)
|
||||
{
|
||||
m_continuous_mode = continuous_mode;
|
||||
|
||||
if (GSRender* render = static_cast<GSRender*>(g_fxo->try_get<rsx::thread>()))
|
||||
{
|
||||
render->set_continuous_mode(continuous_mode);
|
||||
}
|
||||
}
|
||||
|
||||
game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, usz recursion_count)
|
||||
{
|
||||
if (recursion_count == 0 && m_restrict_emu_state_change)
|
||||
|
@ -1132,7 +1147,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch,
|
|||
|
||||
bool resolve_path_as_vfs_path = false;
|
||||
|
||||
const bool from_dev_flash = IsPathInsideDir(m_path, g_cfg_vfs.get_dev_flash());
|
||||
const bool from_dev_flash = IsPathInsideDir(m_path, g_cfg_vfs.get_dev_flash());
|
||||
|
||||
std::string savestate_build_version;
|
||||
std::string savestate_creation_date;
|
||||
|
@ -2895,8 +2910,14 @@ u64 get_sysutil_cb_manager_read_count();
|
|||
|
||||
void qt_events_aware_op(int repeat_duration_ms, std::function<bool()> wrapped_op);
|
||||
|
||||
void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op, bool savestate)
|
||||
void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op, bool savestate, bool continuous_mode)
|
||||
{
|
||||
// Make sure we close the game window
|
||||
if (!continuous_mode)
|
||||
{
|
||||
Emu.SetContinuousMode(false);
|
||||
}
|
||||
|
||||
// Ensure no game has booted inbetween
|
||||
const auto guard = Emu.MakeEmulationStateGuard();
|
||||
|
||||
|
@ -3040,6 +3061,22 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||
|
||||
*pause_thread = make_ptr(new named_thread("Savestate Prepare Thread"sv, [pause_thread, allow_autoexit, this]() mutable
|
||||
{
|
||||
struct scoped_success_guard
|
||||
{
|
||||
bool save_state_success = false;
|
||||
~scoped_success_guard()
|
||||
{
|
||||
if (!save_state_success)
|
||||
{
|
||||
// Reset continuous mode on savestate error
|
||||
Emu.SetContinuousMode(false);
|
||||
|
||||
// Reset after_kill_callback (which is usually used for Emu.Restart in combination with savestates)
|
||||
Emu.after_kill_callback = nullptr;
|
||||
}
|
||||
}
|
||||
} success_guard {};
|
||||
|
||||
std::vector<std::pair<shared_ptr<named_thread<spu_thread>>, u32>> paused_spus;
|
||||
|
||||
if (!try_lock_spu_threads_in_a_state_compatible_with_savestates(false, &paused_spus))
|
||||
|
@ -3110,6 +3147,8 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||
return;
|
||||
}
|
||||
|
||||
success_guard.save_state_success = true;
|
||||
|
||||
CallFromMainThread([allow_autoexit, this, paused_spus]()
|
||||
{
|
||||
savestate_stage stage{};
|
||||
|
@ -3185,15 +3224,15 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||
|
||||
sys_log.notice("Stopping emulator...");
|
||||
|
||||
const bool continuous_savestate_mode = savestate && !g_cfg.savestate.suspend_emu;
|
||||
|
||||
// Show visual feedback to the user in case that stopping takes a while.
|
||||
// This needs to be done before actually stopping, because otherwise the necessary threads will be terminated before we can show an image.
|
||||
if (g_fxo->try_get<named_thread<progress_dialog_server>>() && (continuous_savestate_mode || g_progr_text.operator bool()))
|
||||
{
|
||||
// Show visual feedback to the user in case that stopping takes a while.
|
||||
// This needs to be done before actually stopping, because otherwise the necessary threads will be terminated before we can show an image.
|
||||
if (auto progress_dialog = g_fxo->try_get<named_thread<progress_dialog_server>>(); progress_dialog && g_progr_text.operator bool())
|
||||
{
|
||||
// We are currently showing a progress dialog. Notify it that we are going to stop emulation.
|
||||
g_system_progress_stopping = true;
|
||||
std::this_thread::sleep_for(20ms); // Enough for one frame to be rendered
|
||||
}
|
||||
// Notify progress dialog that we are going to stop emulation
|
||||
g_system_progress_stopping = continuous_savestate_mode ? system_progress_stop_state::stop_state_continuous_savestate : system_progress_stop_state::stop_state_stopping;
|
||||
std::this_thread::sleep_for(30ms); // Enough for one frame to be rendered
|
||||
}
|
||||
|
||||
// Signal threads
|
||||
|
@ -3265,7 +3304,10 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||
if (auto ar_ptr = to_ar->load())
|
||||
{
|
||||
// Total amount of waiting: about 10s
|
||||
GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr, verbose_message.get(), init_mtx);
|
||||
if (g_cfg.savestate.suspend_emu)
|
||||
{
|
||||
GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr, verbose_message.get(), init_mtx);
|
||||
}
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
|
@ -3278,7 +3320,6 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||
thread_ctrl::wait_for(5'000);
|
||||
}
|
||||
|
||||
|
||||
*closed_sucessfully = true;
|
||||
}));
|
||||
|
||||
|
@ -3849,89 +3890,6 @@ std::string Emulator::GetFormattedTitle(double fps) const
|
|||
return rpcs3::get_formatted_title(title_data);
|
||||
}
|
||||
|
||||
s32 error_code::error_report(s32 result, const logs::message* channel, const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||
{
|
||||
static thread_local std::string g_tls_error_str;
|
||||
static thread_local std::unordered_map<std::string, usz> g_tls_error_stats;
|
||||
|
||||
if (!channel)
|
||||
{
|
||||
channel = &sys_log.error;
|
||||
}
|
||||
|
||||
if (!sup && !args)
|
||||
{
|
||||
if (!fmt)
|
||||
{
|
||||
// Report and clean error state
|
||||
for (auto&& pair : g_tls_error_stats)
|
||||
{
|
||||
if (pair.second > 3)
|
||||
{
|
||||
channel->operator()("Stat: %s [x%u]", pair.first, pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
g_tls_error_stats.clear();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ensure(fmt);
|
||||
|
||||
const char* func = "Unknown function";
|
||||
|
||||
if (auto ppu = get_current_cpu_thread<ppu_thread>())
|
||||
{
|
||||
if (auto current = ppu->current_function)
|
||||
{
|
||||
func = current;
|
||||
}
|
||||
}
|
||||
else if (auto spu = get_current_cpu_thread<spu_thread>())
|
||||
{
|
||||
if (auto current = spu->current_func; current && spu->start_time)
|
||||
{
|
||||
func = current;
|
||||
}
|
||||
}
|
||||
|
||||
// Format log message (use preallocated buffer)
|
||||
g_tls_error_str.clear();
|
||||
|
||||
fmt::append(g_tls_error_str, "'%s' failed with 0x%08x", func, result);
|
||||
|
||||
// Add spacer between error and fmt if necessary
|
||||
if (fmt[0] != ' ')
|
||||
g_tls_error_str += " : ";
|
||||
|
||||
fmt::raw_append(g_tls_error_str, fmt, sup, args);
|
||||
|
||||
// Update stats and check log threshold
|
||||
|
||||
if (g_log_all_errors) [[unlikely]]
|
||||
{
|
||||
if (!g_tls_error_stats.empty())
|
||||
{
|
||||
// Report and clean error state
|
||||
error_report(0, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
channel->operator()("%s", g_tls_error_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto stat = ++g_tls_error_stats[g_tls_error_str];
|
||||
|
||||
if (stat <= 3)
|
||||
{
|
||||
channel->operator()("%s [%u]", g_tls_error_str, stat);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Emulator::ConfigurePPUCache() const
|
||||
{
|
||||
auto& _main = g_fxo->get<main_ppu_module<lv2_obj>>();
|
||||
|
|
|
@ -86,6 +86,7 @@ struct EmuCallbacks
|
|||
std::function<void(std::string_view title_id)> init_pad_handler;
|
||||
std::function<void()> update_emu_settings;
|
||||
std::function<void()> save_emu_settings;
|
||||
std::function<void()> close_gs_frame;
|
||||
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
|
||||
std::function<std::shared_ptr<class camera_handler_base>()> get_camera_handler;
|
||||
std::function<std::shared_ptr<class music_handler_base>()> get_music_handler;
|
||||
|
@ -154,6 +155,7 @@ class Emulator final
|
|||
// 2. It signifies that we don't want to exit on Kill(), for example if we want to transition to another application.
|
||||
bool m_force_boot = false;
|
||||
|
||||
bool m_continuous_mode = false;
|
||||
bool m_has_gui = true;
|
||||
|
||||
bool m_state_inspection_savestate = false;
|
||||
|
@ -346,6 +348,15 @@ public:
|
|||
return m_config_mode == cfg_mode::continuous;
|
||||
}
|
||||
|
||||
bool ContinuousModeEnabled(bool reset)
|
||||
{
|
||||
if (reset)
|
||||
{
|
||||
return std::exchange(m_continuous_mode, false);
|
||||
}
|
||||
return m_continuous_mode;
|
||||
}
|
||||
|
||||
class emulation_state_guard_t
|
||||
{
|
||||
class Emulator* _this = nullptr;
|
||||
|
@ -385,6 +396,7 @@ public:
|
|||
bool BootRsxCapture(const std::string& path);
|
||||
|
||||
void SetForceBoot(bool force_boot);
|
||||
void SetContinuousMode(bool continuous_mode);
|
||||
|
||||
game_boot_result Load(const std::string& title_id = "", bool is_disc_patch = false, usz recursion_count = 0);
|
||||
void Run(bool start_playtime);
|
||||
|
@ -407,7 +419,7 @@ public:
|
|||
|
||||
bool Pause(bool freeze_emulation = false, bool show_resume_message = true);
|
||||
void Resume();
|
||||
void GracefulShutdown(bool allow_autoexit = true, bool async_op = false, bool savestate = false);
|
||||
void GracefulShutdown(bool allow_autoexit = true, bool async_op = false, bool savestate = false, bool continuous_mode = false);
|
||||
void Kill(bool allow_autoexit = true, bool savestate = false, savestate_stage* stage = nullptr);
|
||||
game_boot_result Restart(bool graceful = true);
|
||||
bool Quit(bool force_quit);
|
||||
|
@ -456,8 +468,6 @@ public:
|
|||
|
||||
extern Emulator Emu;
|
||||
|
||||
extern bool g_log_all_errors;
|
||||
|
||||
extern bool g_use_rtm;
|
||||
extern u64 g_rtm_tx_limit1;
|
||||
extern u64 g_rtm_tx_limit2;
|
||||
|
|
|
@ -295,6 +295,7 @@ enum class localized_string_id
|
|||
PROGRESS_DIALOG_OF,
|
||||
PROGRESS_DIALOG_PLEASE_WAIT,
|
||||
PROGRESS_DIALOG_STOPPING_PLEASE_WAIT,
|
||||
PROGRESS_DIALOG_SAVESTATE_PLEASE_WAIT,
|
||||
PROGRESS_DIALOG_SCANNING_PPU_EXECUTABLE,
|
||||
PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE,
|
||||
PROGRESS_DIALOG_SCANNING_PPU_MODULES,
|
||||
|
|
|
@ -322,7 +322,10 @@ bool boot_last_savestate(bool testing)
|
|||
if (result)
|
||||
{
|
||||
sys_log.success("Booting the most recent savestate \'%s\' using the Reload shortcut.", savestate_path);
|
||||
Emu.GracefulShutdown(false);
|
||||
|
||||
// Make sure we keep the game window opened
|
||||
Emu.SetContinuousMode(true);
|
||||
Emu.GracefulShutdown(false, false, false, true);
|
||||
|
||||
if (game_boot_result error = Emu.BootGame(savestate_path, "", true); error != game_boot_result::no_errors)
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@ atomic_t<u32> g_progr_pdone{0};
|
|||
atomic_t<bool> g_system_progress_canceled{false};
|
||||
|
||||
// For showing feedback while stopping emulation
|
||||
atomic_t<bool> g_system_progress_stopping{false};
|
||||
atomic_t<system_progress_stop_state> g_system_progress_stopping{system_progress_stop_state::stop_state_disabled};
|
||||
|
||||
namespace rsx::overlays
|
||||
{
|
||||
|
@ -40,7 +40,7 @@ namespace rsx::overlays
|
|||
void progress_dialog_server::operator()()
|
||||
{
|
||||
std::shared_ptr<rsx::overlays::progress_dialog> native_dlg;
|
||||
g_system_progress_stopping = false;
|
||||
g_system_progress_stopping = system_progress_stop_state::stop_state_disabled;
|
||||
g_system_progress_canceled = false;
|
||||
|
||||
const auto get_state = []()
|
||||
|
@ -63,6 +63,41 @@ void progress_dialog_server::operator()()
|
|||
return whole_state;
|
||||
};
|
||||
|
||||
const auto create_native_dialog = [&native_dlg](const std::string& text, bool* show_overlay_message)
|
||||
{
|
||||
if (const auto renderer = rsx::get_current_renderer())
|
||||
{
|
||||
// Some backends like OpenGL actually initialize a lot of driver objects in the "on_init" method.
|
||||
// Wait for init to complete within reasonable time. Abort just in case we have hardware/driver issues.
|
||||
renderer->is_initialized.wait(0, atomic_wait_timeout(5 * 1000000000ull));
|
||||
|
||||
auto manager = g_fxo->try_get<rsx::overlays::display_manager>();
|
||||
|
||||
if (show_overlay_message)
|
||||
{
|
||||
*show_overlay_message = g_fxo->get<progress_dialog_workaround>().show_overlay_message_only;
|
||||
if (*show_overlay_message)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (manager)
|
||||
{
|
||||
MsgDialogType type{};
|
||||
type.se_mute_on = true;
|
||||
type.se_normal = true;
|
||||
type.bg_invisible = true;
|
||||
type.disable_cancel = true;
|
||||
type.progress_bar_count = 1;
|
||||
|
||||
native_dlg = manager->create<rsx::overlays::progress_dialog>(true);
|
||||
native_dlg->show(false, text, type, msg_dialog_source::sys_progress, nullptr);
|
||||
native_dlg->progress_bar_set_message(0, get_localized_string(localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
// Wait for the start condition
|
||||
|
@ -113,29 +148,7 @@ void progress_dialog_server::operator()()
|
|||
bool show_overlay_message = false; // Only show an overlay message after initial loading is done.
|
||||
std::shared_ptr<MsgDialogBase> dlg;
|
||||
|
||||
if (const auto renderer = rsx::get_current_renderer())
|
||||
{
|
||||
// Some backends like OpenGL actually initialize a lot of driver objects in the "on_init" method.
|
||||
// Wait for init to complete within reasonable time. Abort just in case we have hardware/driver issues.
|
||||
renderer->is_initialized.wait(0, atomic_wait_timeout(5 * 1000000000ull));
|
||||
|
||||
auto manager = g_fxo->try_get<rsx::overlays::display_manager>();
|
||||
show_overlay_message = g_fxo->get<progress_dialog_workaround>().show_overlay_message_only;
|
||||
|
||||
if (manager && !show_overlay_message)
|
||||
{
|
||||
MsgDialogType type{};
|
||||
type.se_mute_on = true;
|
||||
type.se_normal = true;
|
||||
type.bg_invisible = true;
|
||||
type.disable_cancel = true;
|
||||
type.progress_bar_count = 1;
|
||||
|
||||
native_dlg = manager->create<rsx::overlays::progress_dialog>(true);
|
||||
native_dlg->show(false, text0, type, msg_dialog_source::sys_progress, nullptr);
|
||||
native_dlg->progress_bar_set_message(0, get_localized_string(localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT));
|
||||
}
|
||||
}
|
||||
create_native_dialog(text0, &show_overlay_message);
|
||||
|
||||
if (!show_overlay_message && !native_dlg && (dlg = Emu.GetCallbacks().get_msg_dialog()))
|
||||
{
|
||||
|
@ -392,6 +405,7 @@ void progress_dialog_server::operator()()
|
|||
else if (native_dlg)
|
||||
{
|
||||
native_dlg->close(false, false);
|
||||
native_dlg.reset();
|
||||
}
|
||||
else if (dlg)
|
||||
{
|
||||
|
@ -411,10 +425,25 @@ void progress_dialog_server::operator()()
|
|||
g_progr_ptotal.notify_all();
|
||||
}
|
||||
|
||||
if (native_dlg && g_system_progress_stopping)
|
||||
if (g_system_progress_stopping)
|
||||
{
|
||||
native_dlg->set_text(get_localized_string(localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT));
|
||||
native_dlg->refresh();
|
||||
const std::string text = get_localized_string(
|
||||
g_system_progress_stopping == system_progress_stop_state::stop_state_continuous_savestate
|
||||
? localized_string_id::PROGRESS_DIALOG_SAVESTATE_PLEASE_WAIT
|
||||
: localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT
|
||||
);
|
||||
if (native_dlg)
|
||||
{
|
||||
native_dlg->set_text(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
create_native_dialog(text, nullptr);
|
||||
}
|
||||
if (native_dlg)
|
||||
{
|
||||
native_dlg->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
if (g_progr_ptotal.exchange(0))
|
||||
|
|
|
@ -36,6 +36,13 @@ struct alignas(16) progress_dialog_string_t
|
|||
}
|
||||
};
|
||||
|
||||
enum system_progress_stop_state : u32
|
||||
{
|
||||
stop_state_disabled = 0,
|
||||
stop_state_stopping,
|
||||
stop_state_continuous_savestate
|
||||
};
|
||||
|
||||
extern progress_dialog_string_t g_progr_text;
|
||||
extern atomic_t<u32> g_progr_ftotal;
|
||||
extern atomic_t<u32> g_progr_fdone;
|
||||
|
@ -44,7 +51,7 @@ extern atomic_t<u64> g_progr_fknown_bits;
|
|||
extern atomic_t<u32> g_progr_ptotal;
|
||||
extern atomic_t<u32> g_progr_pdone;
|
||||
extern atomic_t<bool> g_system_progress_canceled;
|
||||
extern atomic_t<bool> g_system_progress_stopping;
|
||||
extern atomic_t<system_progress_stop_state> g_system_progress_stopping;
|
||||
|
||||
// Initialize progress dialog (can be recursive)
|
||||
class scoped_progress_dialog final
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\cache_utils.cpp" />
|
||||
<ClCompile Include="Emu\Cell\ErrorCodes.cpp" />
|
||||
<ClCompile Include="Emu\Cell\lv2\sys_game.cpp" />
|
||||
<ClCompile Include="Emu\Cell\Modules\cellMusicSelectionContext.cpp" />
|
||||
<ClCompile Include="Emu\Cell\Modules\libfs_utility_init.cpp" />
|
||||
|
|
|
@ -1327,6 +1327,9 @@
|
|||
<ClCompile Include="Emu\Audio\audio_utils.cpp">
|
||||
<Filter>Emu\Audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\ErrorCodes.cpp">
|
||||
<Filter>Emu\Cell</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
|
|
|
@ -120,6 +120,7 @@ void headless_application::InitializeCallbacks()
|
|||
return nullptr;
|
||||
};
|
||||
|
||||
callbacks.close_gs_frame = [](){};
|
||||
callbacks.get_gs_frame = []() -> std::unique_ptr<GSFrameBase>
|
||||
{
|
||||
if (g_cfg.video.renderer != video_renderer::null)
|
||||
|
|
|
@ -133,7 +133,7 @@ EmuCallbacks main_application::CreateCallbacks()
|
|||
basic_keyboard_handler* ret = g_fxo->init<KeyboardHandlerBase, basic_keyboard_handler>(Emu.DeserialManager());
|
||||
ensure(ret);
|
||||
ret->moveToThread(get_thread());
|
||||
ret->SetTargetWindow(m_game_window);
|
||||
ret->SetTargetWindow(reinterpret_cast<QWindow*>(m_game_window));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ EmuCallbacks main_application::CreateCallbacks()
|
|||
basic_mouse_handler* ret = g_fxo->init<MouseHandlerBase, basic_mouse_handler>(Emu.DeserialManager());
|
||||
ensure(ret);
|
||||
ret->moveToThread(get_thread());
|
||||
ret->SetTargetWindow(m_game_window);
|
||||
ret->SetTargetWindow(reinterpret_cast<QWindow*>(m_game_window));
|
||||
break;
|
||||
}
|
||||
case mouse_handler::raw:
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <QWindow>
|
||||
#include <QThread>
|
||||
|
||||
struct EmuCallbacks;
|
||||
class gs_frame;
|
||||
|
||||
class main_application
|
||||
{
|
||||
|
@ -25,5 +26,5 @@ protected:
|
|||
EmuCallbacks CreateCallbacks();
|
||||
|
||||
std::string m_active_user;
|
||||
QWindow* m_game_window = nullptr; // (Currently) only needed so that pad handlers have a valid target for event filtering.
|
||||
gs_frame* m_game_window = nullptr;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,11 @@ gl_gs_frame::gl_gs_frame(QScreen* screen, const QRect& geometry, const QIcon& ap
|
|||
show();
|
||||
}
|
||||
|
||||
void gl_gs_frame::reset()
|
||||
{
|
||||
m_primary_context = nullptr;
|
||||
}
|
||||
|
||||
draw_context_t gl_gs_frame::make_context()
|
||||
{
|
||||
auto context = new GLContext();
|
||||
|
|
|
@ -20,6 +20,7 @@ private:
|
|||
public:
|
||||
explicit gl_gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon, std::shared_ptr<gui_settings> gui_settings, bool force_fullscreen);
|
||||
|
||||
void reset() override;
|
||||
draw_context_t make_context() override;
|
||||
void set_current(draw_context_t ctx) override;
|
||||
void delete_context(draw_context_t ctx) override;
|
||||
|
|
|
@ -73,6 +73,7 @@ gs_frame::gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon,
|
|||
, m_initial_geometry(geometry)
|
||||
, m_gui_settings(std::move(gui_settings))
|
||||
, m_start_games_fullscreen(force_fullscreen)
|
||||
, m_renderer(g_cfg.video.renderer)
|
||||
{
|
||||
load_gui_settings();
|
||||
|
||||
|
@ -328,6 +329,9 @@ void gs_frame::handle_shortcut(gui::shortcuts::shortcut shortcut_key, const QKey
|
|||
{
|
||||
Emu.Restart();
|
||||
};
|
||||
|
||||
// Make sure we keep the game window opened
|
||||
Emu.SetContinuousMode(true);
|
||||
}
|
||||
|
||||
Emu.Kill(false, true);
|
||||
|
@ -602,6 +606,11 @@ void gs_frame::close()
|
|||
|
||||
gui_log.notice("Closing game window");
|
||||
|
||||
if (m_ignore_stop_events)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Emu.CallFromMainThread([this]()
|
||||
{
|
||||
// Hide window if necessary
|
||||
|
@ -623,6 +632,10 @@ void gs_frame::close()
|
|||
});
|
||||
}
|
||||
|
||||
void gs_frame::reset()
|
||||
{
|
||||
}
|
||||
|
||||
bool gs_frame::shown()
|
||||
{
|
||||
return QWindow::isVisible();
|
||||
|
@ -1134,6 +1147,11 @@ bool gs_frame::event(QEvent* ev)
|
|||
|
||||
gui_log.notice("Game window close event issued");
|
||||
|
||||
if (m_ignore_stop_events)
|
||||
{
|
||||
return QWindow::event(ev);
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
// This should be unreachable, but never say never. Properly close the window anyway.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <vector>
|
||||
|
||||
class gui_settings;
|
||||
enum class video_renderer;
|
||||
|
||||
class gs_frame : public QWindow, public GSFrameBase
|
||||
{
|
||||
|
@ -45,6 +46,7 @@ private:
|
|||
u32 m_hide_mouse_idletime = 2000; // ms
|
||||
bool m_flip_showed_frame = false;
|
||||
bool m_start_games_fullscreen = false;
|
||||
bool m_ignore_stop_events = false;
|
||||
|
||||
std::shared_ptr<utils::video_encoder> m_video_encoder{};
|
||||
|
||||
|
@ -52,6 +54,10 @@ public:
|
|||
explicit gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon, std::shared_ptr<gui_settings> gui_settings, bool force_fullscreen);
|
||||
~gs_frame();
|
||||
|
||||
video_renderer renderer() const { return m_renderer; };
|
||||
|
||||
void ignore_stop_events() { m_ignore_stop_events = true; }
|
||||
|
||||
draw_context_t make_context() override;
|
||||
void set_current(draw_context_t context) override;
|
||||
void delete_context(draw_context_t context) override;
|
||||
|
@ -76,10 +82,13 @@ public:
|
|||
void take_screenshot(std::vector<u8> data, u32 sshot_width, u32 sshot_height, bool is_bgra) override;
|
||||
|
||||
protected:
|
||||
video_renderer m_renderer;
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
void close() override;
|
||||
void reset() override;
|
||||
|
||||
bool shown() override;
|
||||
void hide() override;
|
||||
|
|
|
@ -348,6 +348,34 @@ void gui_application::InitializeConnects()
|
|||
|
||||
std::unique_ptr<gs_frame> gui_application::get_gs_frame()
|
||||
{
|
||||
// Load AppIcon
|
||||
const QIcon app_icon = m_main_window ? m_main_window->GetAppIcon() : gui::utils::get_app_icon_from_path(Emu.GetBoot(), Emu.GetTitleID());
|
||||
|
||||
if (m_game_window)
|
||||
{
|
||||
// Check if the continuous mode is enabled. We reset the mode after each use in order to ensure that it is only used when explicitly needed.
|
||||
const bool continuous_mode_enabled = Emu.ContinuousModeEnabled(true);
|
||||
|
||||
// Make sure we run the same config
|
||||
const bool is_same_renderer = m_game_window->renderer() == g_cfg.video.renderer;
|
||||
|
||||
if (is_same_renderer && (Emu.IsChildProcess() || continuous_mode_enabled))
|
||||
{
|
||||
gui_log.notice("gui_application: Re-using old game window (IsChildProcess=%d, ContinuousModeEnabled=%d)", Emu.IsChildProcess(), continuous_mode_enabled);
|
||||
|
||||
if (!app_icon.isNull())
|
||||
{
|
||||
m_game_window->setIcon(app_icon);
|
||||
}
|
||||
return std::unique_ptr<gs_frame>(m_game_window);
|
||||
}
|
||||
|
||||
// Clean-up old game window. This should only happen if the renderer changed or there was an unexpected error during boot.
|
||||
Emu.GetCallbacks().close_gs_frame();
|
||||
}
|
||||
|
||||
gui_log.notice("gui_application: Creating new game window");
|
||||
|
||||
extern const std::unordered_map<video_resolution, std::pair<int, int>, value_hash<video_resolution>> g_video_out_resolution_map;
|
||||
|
||||
auto [w, h] = ::at32(g_video_out_resolution_map, g_cfg.video.resolution);
|
||||
|
@ -424,9 +452,6 @@ std::unique_ptr<gs_frame> gui_application::get_gs_frame()
|
|||
frame_geometry.setSize(QSize(w, h));
|
||||
}
|
||||
|
||||
// Load AppIcon
|
||||
const QIcon app_icon = m_main_window ? m_main_window->GetAppIcon() : gui::utils::get_app_icon_from_path(Emu.GetBoot(), Emu.GetTitleID());
|
||||
|
||||
gs_frame* frame = nullptr;
|
||||
|
||||
switch (g_cfg.video.renderer.get())
|
||||
|
@ -446,6 +471,12 @@ std::unique_ptr<gs_frame> gui_application::get_gs_frame()
|
|||
|
||||
m_game_window = frame;
|
||||
|
||||
connect(m_game_window, &gs_frame::destroyed, this, [this]()
|
||||
{
|
||||
gui_log.notice("gui_application: Deleting old game window");
|
||||
m_game_window = nullptr;
|
||||
});
|
||||
|
||||
return std::unique_ptr<gs_frame>(frame);
|
||||
}
|
||||
|
||||
|
@ -539,6 +570,16 @@ void gui_application::InitializeCallbacks()
|
|||
return nullptr;
|
||||
};
|
||||
|
||||
callbacks.close_gs_frame = [this]()
|
||||
{
|
||||
if (m_game_window)
|
||||
{
|
||||
gui_log.warning("gui_application: Closing old game window");
|
||||
m_game_window->ignore_stop_events();
|
||||
delete m_game_window;
|
||||
m_game_window = nullptr;
|
||||
}
|
||||
};
|
||||
callbacks.get_gs_frame = [this]() -> std::unique_ptr<GSFrameBase> { return get_gs_frame(); };
|
||||
callbacks.get_msg_dialog = [this]() -> std::shared_ptr<MsgDialogBase> { return m_show_gui ? std::make_shared<msg_dialog_frame>() : nullptr; };
|
||||
callbacks.get_osk_dialog = [this]() -> std::shared_ptr<OskDialogBase> { return m_show_gui ? std::make_shared<osk_dialog_frame>() : nullptr; };
|
||||
|
@ -582,10 +623,10 @@ void gui_application::InitializeCallbacks()
|
|||
{
|
||||
switch (type)
|
||||
{
|
||||
case 0: static_cast<gs_frame*>(m_game_window)->progress_reset(value); break;
|
||||
case 1: static_cast<gs_frame*>(m_game_window)->progress_increment(value); break;
|
||||
case 2: static_cast<gs_frame*>(m_game_window)->progress_set_limit(value); break;
|
||||
case 3: static_cast<gs_frame*>(m_game_window)->progress_set_value(value); break;
|
||||
case 0: m_game_window->progress_reset(value); break;
|
||||
case 1: m_game_window->progress_increment(value); break;
|
||||
case 2: m_game_window->progress_set_limit(value); break;
|
||||
case 3: m_game_window->progress_set_value(value); break;
|
||||
default: gui_log.fatal("Unknown type in handle_taskbar_progress(type=%d, value=%d)", type, value); break;
|
||||
}
|
||||
}
|
||||
|
@ -770,7 +811,7 @@ void gui_application::InitializeCallbacks()
|
|||
verbose_message += ". ";
|
||||
}
|
||||
|
||||
verbose_message += "If Stuck, Report To Developers";
|
||||
verbose_message += tr("If Stuck, Report To Developers").toStdString();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1045,7 +1086,7 @@ void gui_application::OnShortcutChange()
|
|||
{
|
||||
if (m_game_window)
|
||||
{
|
||||
static_cast<gs_frame*>(m_game_window)->update_shortcuts();
|
||||
m_game_window->update_shortcuts();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1115,7 @@ void gui_application::OnAppStateChanged(Qt::ApplicationState state)
|
|||
}
|
||||
|
||||
const auto emu_state = Emu.GetStatus();
|
||||
const bool is_active = state == Qt::ApplicationActive;
|
||||
const bool is_active = state & Qt::ApplicationActive;
|
||||
|
||||
if (emu_state != system_state::paused && emu_state != system_state::running)
|
||||
{
|
||||
|
|
|
@ -314,6 +314,7 @@ private:
|
|||
case localized_string_id::PROGRESS_DIALOG_OF: return tr("of");
|
||||
case localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT: return tr("Please wait");
|
||||
case localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT: return tr("Stopping. Please wait...");
|
||||
case localized_string_id::PROGRESS_DIALOG_SAVESTATE_PLEASE_WAIT: return tr("Creating savestate. Please wait...");
|
||||
case localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_EXECUTABLE: return tr("Scanning PPU Executable...");
|
||||
case localized_string_id::PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE: return tr("Analyzing PPU Executable...");
|
||||
case localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_MODULES: return tr("Scanning PPU Modules...");
|
||||
|
|
|
@ -2590,6 +2590,9 @@ void main_window::CreateConnects()
|
|||
{
|
||||
Emu.Restart();
|
||||
};
|
||||
|
||||
// Make sure we keep the game window opened
|
||||
Emu.SetContinuousMode(true);
|
||||
}
|
||||
|
||||
Emu.Kill(false, true);
|
||||
|
|
Loading…
Add table
Reference in a new issue