Merge branch 'master' into windows-clang

This commit is contained in:
qurious-pixel 2025-10-15 08:06:03 -07:00 committed by GitHub
commit 2b35b80041
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 69 additions and 57 deletions

View file

@ -106,6 +106,11 @@ thread_local u64 g_tls_wait_fail = 0;
thread_local bool g_tls_access_violation_recovered = false; thread_local bool g_tls_access_violation_recovered = false;
extern thread_local std::string(*g_tls_log_prefix)(); extern thread_local std::string(*g_tls_log_prefix)();
namespace stx
{
atomic_t<u32> g_launch_retainer{0};
}
// Report error and call std::abort(), defined in main.cpp // Report error and call std::abort(), defined in main.cpp
[[noreturn]] void report_fatal_error(std::string_view text, bool is_html = false, bool include_help_text = true); [[noreturn]] void report_fatal_error(std::string_view text, bool is_html = false, bool include_help_text = true);

View file

@ -465,6 +465,8 @@ public:
namespace stx namespace stx
{ {
struct launch_retainer; struct launch_retainer;
extern atomic_t<u32> g_launch_retainer;
} }
// Derived from the callable object Context, possibly a lambda // Derived from the callable object Context, possibly a lambda
@ -481,6 +483,11 @@ class named_thread final : public Context, result_storage<Context>, thread_base
u64 entry_point2() u64 entry_point2()
{ {
while (u32 value = stx::g_launch_retainer)
{
stx::g_launch_retainer.wait(value);
}
thread::initialize([]() thread::initialize([]()
{ {
if constexpr (!result::empty) if constexpr (!result::empty)

View file

@ -659,7 +659,7 @@ void cpu_thread::operator()()
} }
case thread_class::spu: case thread_class::spu:
{ {
if (g_cfg.core.spu_prof) if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
{ {
g_fxo->get<cpu_profiler>().registered.push(id); g_fxo->get<cpu_profiler>().registered.push(id);
} }
@ -1546,7 +1546,7 @@ void cpu_thread::flush_profilers() noexcept
return; return;
} }
if (g_cfg.core.spu_prof) if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
{ {
g_fxo->get<cpu_profiler>().registered.push(0); g_fxo->get<cpu_profiler>().registered.push(0);
} }
@ -1585,22 +1585,30 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu) idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu)
{ {
spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id))); if (give_up)
{
return;
}
if (spu.current_func && spu.unsavable) if (spu.current_func && spu.unsavable && !force_collect)
{ {
const u64 start = spu.start_time; const u64 start = spu.start_time;
// Automatically give up if it is asleep 15 seconds or more // Automatically give up if it is asleep 5 seconds or more
if (start && current > start && current - start >= 15'000'000) if (start && current > start && current - start >= 5'000'000)
{ {
give_up = true; give_up = true;
return;
} }
} }
spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id)));
}); });
if (!force_collect && give_up) if (give_up)
{ {
spu_list.clear();
old_counter = umax;
return decltype(&spu_list){}; return decltype(&spu_list){};
} }
@ -1625,6 +1633,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
} }
else if (get_system_time() - start >= 150'000) else if (get_system_time() - start >= 150'000)
{ {
std::this_thread::sleep_for(1ms);
passed_count++; passed_count++;
start = 0; start = 0;
continue; continue;
@ -1636,37 +1645,29 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
if (!spu_list) if (!spu_list)
{ {
// Give up for now // Give up for now
std::this_thread::sleep_for(10ms); std::this_thread::sleep_for(50ms);
passed_count++; passed_count++;
start = 0; start = 0;
continue; continue;
} }
// Avoid using suspend_all when more than 2 threads known to be unsavable // Avoid using suspend_all when more than 2 threads known to be unsavable
u32 unsavable_threads = 0; u32 savable_threads = 0;
for (auto& spu : *spu_list) for (auto& spu : *spu_list)
{ {
if (spu->unsavable) if (!spu->unsavable)
{ {
unsavable_threads++; savable_threads++;
if (unsavable_threads >= 3)
{
break;
}
} }
} }
if (unsavable_threads >= 3) if (!savable_threads)
{ {
std::this_thread::yield(); std::this_thread::yield();
continue; continue;
} }
// Flag for optimization
bool paused_anyone = false;
if (cpu_thread::suspend_all(nullptr, {}, [&]() if (cpu_thread::suspend_all(nullptr, {}, [&]()
{ {
if (!get_spus(false, true)) if (!get_spus(false, true))
@ -1695,19 +1696,13 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
break; break;
} }
} }
else
{
paused_anyone = true;
ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause));
}
} }
if (failed && paused_anyone) for (auto& spu : *spu_list)
{ {
// For faster signalling, first remove state flags then batch notifications if (!failed && !is_emu_paused)
for (auto& spu : *spu_list)
{ {
spu->state -= cpu_flag::dbg_global_pause; ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause));
} }
} }
@ -1719,13 +1714,6 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
return false; return false;
} }
if (!paused_anyone)
{
// Need not do anything
std::this_thread::yield();
continue;
}
for (auto& spu : *spu_list) for (auto& spu : *spu_list)
{ {
if (spu->state & cpu_flag::wait) if (spu->state & cpu_flag::wait)
@ -1755,7 +1743,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
{ {
spu->state.notify_one(); spu->state.notify_one();
} }
}; }
return false; return false;
} }

View file

@ -111,8 +111,6 @@ void AtracXdecDecoder::alloc_avcodec()
fmt::throw_exception("avcodec_find_decoder() failed"); fmt::throw_exception("avcodec_find_decoder() failed");
} }
//ensure(!(codec->capabilities & AV_CODEC_CAP_SUBFRAMES));
packet = av_packet_alloc(); packet = av_packet_alloc();
if (!packet) if (!packet)
{ {

View file

@ -361,7 +361,7 @@ public:
case move_handler::mouse: case move_handler::mouse:
case move_handler::raw_mouse: case move_handler::raw_mouse:
{ {
auto& handler = g_fxo->get<MouseHandlerBase>(); auto& handler = *ensure(g_fxo->try_get<MouseHandlerBase>());
std::lock_guard mouse_lock(handler.mutex); std::lock_guard mouse_lock(handler.mutex);
const MouseInfo& info = handler.GetInfo(); const MouseInfo& info = handler.GetInfo();
@ -374,7 +374,7 @@ public:
#ifdef HAVE_LIBEVDEV #ifdef HAVE_LIBEVDEV
case move_handler::gun: case move_handler::gun:
{ {
gun_thread& gun = g_fxo->get<gun_thread>(); gun_thread& gun = *ensure(g_fxo->try_get<gun_thread>());
std::scoped_lock lock(gun.handler.mutex); std::scoped_lock lock(gun.handler.mutex);
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0; gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
@ -505,7 +505,7 @@ public:
case move_handler::mouse: case move_handler::mouse:
case move_handler::raw_mouse: case move_handler::raw_mouse:
{ {
auto& handler = g_fxo->get<MouseHandlerBase>(); auto& handler = *ensure(g_fxo->try_get<MouseHandlerBase>());
std::lock_guard mouse_lock(handler.mutex); std::lock_guard mouse_lock(handler.mutex);
// Make sure that the mouse handler is initialized // Make sure that the mouse handler is initialized
@ -522,7 +522,7 @@ public:
#ifdef HAVE_LIBEVDEV #ifdef HAVE_LIBEVDEV
case move_handler::gun: case move_handler::gun:
{ {
gun_thread& gun = g_fxo->get<gun_thread>(); gun_thread& gun = *ensure(g_fxo->try_get<gun_thread>());
std::scoped_lock lock(gun.handler.mutex); std::scoped_lock lock(gun.handler.mutex);
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0; gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
connected_controllers = std::min<u32>(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices); connected_controllers = std::min<u32>(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices);

View file

@ -186,7 +186,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
c->cmp(SPU_OFF_32(state), 0); c->cmp(SPU_OFF_32(state), 0);
c->jnz(label_stop); c->jnz(label_stop);
if (g_cfg.core.spu_prof && g_cfg.core.spu_verification) if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification)
{ {
c->mov(x86::rax, m_hash_start & -0xffff); c->mov(x86::rax, m_hash_start & -0xffff);
c->mov(SPU_OFF_64(block_hash), x86::rax); c->mov(SPU_OFF_64(block_hash), x86::rax);
@ -755,7 +755,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
c->add(SPU_OFF_64(block_counter), ::size32(words) / (words_align / 4)); c->add(SPU_OFF_64(block_counter), ::size32(words) / (words_align / 4));
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if (g_cfg.core.spu_prof) if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
{ {
c->mov(x86::rax, m_hash_start | 0xffff); c->mov(x86::rax, m_hash_start | 0xffff);
c->mov(SPU_OFF_64(block_hash), x86::rax); c->mov(SPU_OFF_64(block_hash), x86::rax);
@ -1199,7 +1199,7 @@ void spu_recompiler::branch_set_link(u32 target)
c->movdqa(x86::dqword_ptr(*cpu, *qw1, 0, ::offset32(&spu_thread::stack_mirror)), x86::xmm0); c->movdqa(x86::dqword_ptr(*cpu, *qw1, 0, ::offset32(&spu_thread::stack_mirror)), x86::xmm0);
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if (g_cfg.core.spu_prof) if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
{ {
c->mov(x86::rax, m_hash_start | 0xffff); c->mov(x86::rax, m_hash_start | 0xffff);
c->mov(SPU_OFF_64(block_hash), x86::rax); c->mov(SPU_OFF_64(block_hash), x86::rax);

View file

@ -1636,7 +1636,7 @@ public:
m_ir->SetInsertPoint(label_test); m_ir->SetInsertPoint(label_test);
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if (g_cfg.core.spu_prof && g_cfg.core.spu_verification) if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification)
m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536)), spu_ptr(&spu_thread::block_hash)); m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536)), spu_ptr(&spu_thread::block_hash));
if (!g_cfg.core.spu_verification) if (!g_cfg.core.spu_verification)
@ -1993,7 +1993,7 @@ public:
set_function(m_functions[m_entry].chunk); set_function(m_functions[m_entry].chunk);
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if (g_cfg.core.spu_prof) if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536) | (m_entry >> 2)), spu_ptr(&spu_thread::block_hash)); m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536) | (m_entry >> 2)), spu_ptr(&spu_thread::block_hash));
m_finfo = &m_functions[m_entry]; m_finfo = &m_functions[m_entry];

View file

@ -1612,10 +1612,14 @@ std::string spu_thread::dump_misc() const
fmt::append(ret, "Block Weight: %u (Retreats: %u)", block_counter, block_failure); fmt::append(ret, "Block Weight: %u (Retreats: %u)", block_counter, block_failure);
if (g_cfg.core.spu_prof) if (u64 hash = atomic_storage<u64>::load(block_hash))
{ {
// Get short function hash and position in chunk // Get short function hash and position in chunk
fmt::append(ret, "\nCurrent block: %s", spu_block_hash{atomic_storage<u64>::load(block_hash)}); fmt::append(ret, "\nCurrent block: %s", spu_block_hash{hash});
}
else if (g_cfg.core.spu_prof || g_cfg.core.spu_debug)
{
fmt::append(ret, "\nCurrent block: N/A");
} }
const u32 offset = group ? SPU_FAKE_BASE_ADDR + (id & 0xffffff) * SPU_LS_SIZE : RAW_SPU_BASE_ADDR + index * RAW_SPU_OFFSET; const u32 offset = group ? SPU_FAKE_BASE_ADDR + (id & 0xffffff) * SPU_LS_SIZE : RAW_SPU_BASE_ADDR + index * RAW_SPU_OFFSET;

View file

@ -589,7 +589,7 @@ namespace rsx
{ {
if (REGS(m_ctx)->clip_planes_mask() == 0) [[ likely ]] if (REGS(m_ctx)->clip_planes_mask() == 0) [[ likely ]]
{ {
*reinterpret_cast<u32*>(buffer) = 0u; *reinterpret_cast<u32*>(buffer) = 0b0101010101010101;
return; return;
} }
@ -631,7 +631,7 @@ namespace rsx
break; break;
case rsx::user_clip_plane_op::less_than: case rsx::user_clip_plane_op::less_than:
clip_configuration_field |= CLIP_DISTANCE_FACTOR(2) << shift_offset; clip_configuration_field |= CLIP_DISTANCE_FACTOR(-1) << shift_offset;
break; break;
} }
} }

View file

@ -182,7 +182,7 @@ namespace glsl
OS << OS <<
"#define CLIP_PLANE_DISABLED 1\n" "#define CLIP_PLANE_DISABLED 1\n"
"#define is_user_clip_enabled(idx) (_get_bits(get_user_clip_config(), idx * 2, 2) != CLIP_PLANE_DISABLED)\n" "#define is_user_clip_enabled(idx) (_get_bits(get_user_clip_config(), idx * 2, 2) != CLIP_PLANE_DISABLED)\n"
"#define user_clip_factor(idx) float(_get_bits(get_user_clip_config(), idx * 2, 2) - 1)\n\n"; "#define user_clip_factor(idx) (float(_get_bits(get_user_clip_config(), idx * 2, 2)) - 1.f)\n\n";
} }
if (props.domain == glsl::program_domain::glsl_fragment_program) if (props.domain == glsl::program_domain::glsl_fragment_program)

View file

@ -837,7 +837,7 @@ namespace rsx
{ {
while (Emu.IsReady()) while (Emu.IsReady())
{ {
thread_ctrl::wait_for(1000); Emu.WaitReady();
} }
do do

View file

@ -221,13 +221,19 @@ void init_fxo_for_exec(utils::serial* ar, bool full = false)
Emu.ConfigurePPUCache(); Emu.ConfigurePPUCache();
stx::g_launch_retainer = 1;
g_fxo->init(false, ar, [](){ Emu.ExecPostponedInitCode(); }); g_fxo->init(false, ar, [](){ Emu.ExecPostponedInitCode(); });
Emu.GetCallbacks().init_gs_render(ar); Emu.GetCallbacks().init_gs_render(ar);
Emu.GetCallbacks().init_pad_handler(Emu.GetTitleID());
Emu.GetCallbacks().init_kb_handler(); Emu.GetCallbacks().init_kb_handler();
Emu.GetCallbacks().init_mouse_handler(); Emu.GetCallbacks().init_mouse_handler();
stx::g_launch_retainer = 0;
stx::g_launch_retainer.notify_all();
Emu.GetCallbacks().init_pad_handler(Emu.GetTitleID());
usz pos = 0; usz pos = 0;
if (ar) if (ar)
@ -859,6 +865,7 @@ bool Emulator::BootRsxCapture(const std::string& path)
GetCallbacks().on_run(false); GetCallbacks().on_run(false);
m_state = system_state::starting; m_state = system_state::starting;
m_state.notify_all();
ensure(g_fxo->init<named_thread<rsx::rsx_replay_thread>>("RSX Replay", std::move(frame))); ensure(g_fxo->init<named_thread<rsx::rsx_replay_thread>>("RSX Replay", std::move(frame)));
@ -2472,6 +2479,7 @@ void Emulator::Run(bool start_playtime)
rpcs3::utils::configure_logs(); rpcs3::utils::configure_logs();
m_state = system_state::starting; m_state = system_state::starting;
m_state.notify_all();
if (g_cfg.misc.prevent_display_sleep) if (g_cfg.misc.prevent_display_sleep)
{ {
@ -3254,6 +3262,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
} }
// Signal threads // Signal threads
m_state.notify_all();
if (auto rsx = g_fxo->try_get<rsx::thread>()) if (auto rsx = g_fxo->try_get<rsx::thread>())
{ {

View file

@ -439,6 +439,7 @@ public:
bool IsStopped(bool test_fully = false) const { return test_fully ? m_state == system_state::stopped : m_state <= system_state::stopping; } bool IsStopped(bool test_fully = false) const { return test_fully ? m_state == system_state::stopped : m_state <= system_state::stopping; }
bool IsReady() const { return m_state == system_state::ready; } bool IsReady() const { return m_state == system_state::ready; }
bool IsStarting() const { return m_state == system_state::starting; } bool IsStarting() const { return m_state == system_state::starting; }
void WaitReady() const { m_state.wait(system_state::ready); }
auto GetStatus(bool fixup = true) const { system_state state = m_state; return fixup && state == system_state::frozen ? system_state::paused : fixup && state == system_state::stopping ? system_state::stopped : state; } auto GetStatus(bool fixup = true) const { system_state state = m_state; return fixup && state == system_state::frozen ? system_state::paused : fixup && state == system_state::stopping ? system_state::stopped : state; }
bool HasGui() const { return m_has_gui; } bool HasGui() const { return m_has_gui; }

View file

@ -332,7 +332,7 @@ private:
case localized_string_id::EMULATION_RESUMING: return tr("Resuming...!"); case localized_string_id::EMULATION_RESUMING: return tr("Resuming...!");
case localized_string_id::EMULATION_FROZEN: return tr("The PS3 application has likely crashed, you can close it."); case localized_string_id::EMULATION_FROZEN: return tr("The PS3 application has likely crashed, you can close it.");
case localized_string_id::SAVESTATE_FAILED_DUE_TO_SAVEDATA: return tr("SaveState failed: Game saving is in progress, wait until finished."); case localized_string_id::SAVESTATE_FAILED_DUE_TO_SAVEDATA: return tr("SaveState failed: Game saving is in progress, wait until finished.");
case localized_string_id::SAVESTATE_FAILED_DUE_TO_VDEC: return tr("SaveState failed: VDEC-base video/cutscenes are in order, wait for them to end or enable libvdec.sprx."); case localized_string_id::SAVESTATE_FAILED_DUE_TO_VDEC: return tr("SaveState failed: VDEC-based video/cutscenes are in order, wait for them to end or enable libvdec.sprx.");
case localized_string_id::SAVESTATE_FAILED_DUE_TO_MISSING_SPU_SETTING: return tr("SaveState failed: Failed to lock SPU state, enabling SPU-Compatible mode may fix it."); case localized_string_id::SAVESTATE_FAILED_DUE_TO_MISSING_SPU_SETTING: return tr("SaveState failed: Failed to lock SPU state, enabling SPU-Compatible mode may fix it.");
case localized_string_id::SAVESTATE_FAILED_DUE_TO_SPU: return tr("SaveState failed: Failed to lock SPU state, using SPU ASMJIT will fix it."); case localized_string_id::SAVESTATE_FAILED_DUE_TO_SPU: return tr("SaveState failed: Failed to lock SPU state, using SPU ASMJIT will fix it.");
case localized_string_id::INVALID: return tr("Invalid"); case localized_string_id::INVALID: return tr("Invalid");