diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 3b855de455..12880caca4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -257,6 +257,17 @@ error_code sys_spu_thread_initialize(vm::ptr thread, u32 group_id, u32 spu_ if (++group->init == group->max_num) { + if (g_cfg.core.max_spurs_threads < 6 && group->max_num > g_cfg.core.max_spurs_threads) + { + if (group->name.size() >= 20 && group->name.compare(group->name.size() - 20, 20, "CellSpursKernelGroup", 20) == 0) + { + // Hack: don't run more SPURS threads than specified. + group->init = g_cfg.core.max_spurs_threads; + + LOG_SUCCESS(SPU, "HACK: '%s' (0x%x) limited to %u threads.", group->name, group_id, +g_cfg.core.max_spurs_threads); + } + } + group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; } @@ -386,12 +397,20 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id) std::lock_guard lock(group->mutex); + u32 max_threads = +group->init; + group->join_state = 0; - group->running = +group->init; + group->running = max_threads; + u32 run_threads = max_threads; for (auto& thread : group->threads) { - if (thread) + if (!run_threads) + { + break; + } + + if (thread && run_threads--) { auto& args = group->args[thread->index]; auto& img = group->imgs[thread->index]; @@ -413,9 +432,16 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id) // TODO: check data2 and data3 group->send_run_event(id, 0, 0); + u32 ran_threads = max_threads; + for (auto& thread : group->threads) { - if (thread) + if (!ran_threads) + { + break; + } + + if (thread && ran_threads--) { thread->state -= cpu_flag::stop; thread_ctrl::notify(*thread); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index fbe6e23c9a..99d1916014 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -372,6 +372,7 @@ struct cfg_root : cfg::node cfg::_int<0, 6> preferred_spu_threads{this, "Preferred SPU Threads", 0}; //Numnber of hardware threads dedicated to heavy simultaneous spu tasks cfg::_int<0, 16> spu_delay_penalty{this, "SPU delay penalty", 3}; //Number of milliseconds to block a thread if a virtual 'core' isn't free cfg::_bool spu_loop_detection{this, "SPU loop detection", true}; //Try to detect wait loops and trigger thread yield + cfg::_int<0, 6> max_spurs_threads{this, "Max SPURS Threads", 6}; // HACK. If less then 6, max number of running SPURS threads in each thread group. cfg::_enum spu_block_size{this, "SPU Block Size", spu_block_size_type::safe}; cfg::_bool spu_accurate_getllar{this, "Accurate GETLLAR", false}; cfg::_bool spu_accurate_putlluc{this, "Accurate PUTLLUC", false};