diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 4a7e6f0a81..f795073ae6 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -2868,8 +2868,9 @@ bool spu_thread::stop_and_signal(u32 code) spu_log.trace("sys_spu_thread_receive_event(spuq=0x%x)", spuq); - if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate + if (!group->has_scheduler_context /*|| group->type & 0xf00*/) { + spu_log.error("sys_spu_thread_receive_event(): Incompatible group type = 0x%x", group->type); return ch_in_mbox.set_values(1, CELL_EINVAL), true; } diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index daa72bb316..424b52c203 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -14,6 +14,7 @@ #include "Emu/Cell/RawSPUThread.h" #include "sys_interrupt.h" #include "sys_process.h" +#include "sys_memory.h" #include "sys_mmapper.h" #include "sys_event.h" @@ -414,23 +415,138 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num sys_spu.warning("sys_spu_thread_group_create(id=*0x%x, num=%d, prio=%d, attr=*0x%x)", id, num, prio, attr); - // TODO: max num value should be affected by sys_spu_initialize() settings - const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16; - if (attr->nsize > 0x80 || !num || num > 6 || ((prio < min_prio || prio > 255) && (attr->type != SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT && attr->type != SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM))) + + if (attr->nsize > 0x80 || !num) { return CELL_EINVAL; } - if (attr->type) + const s32 type = attr->type; + + bool use_scheduler = true; + bool use_memct = !!(type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER); + bool needs_root = false; + u32 max_threads = 6; // TODO: max num value should be affected by sys_spu_initialize() settings + u32 min_threads = 1; + u32 mem_size = 0; + lv2_memory_container* ct{}; + + if (type) { - sys_spu.warning("sys_spu_thread_group_create(): SPU Thread Group type (0x%x)", attr->type); + sys_spu.warning("sys_spu_thread_group_create(): SPU Thread Group type (0x%x)", type); } - const auto group = idm::make_ptr(std::string(attr->name.get_ptr(), std::max(attr->nsize, 1) - 1), num, prio, attr->type, attr->ct); + switch (type) + { + case 0x0: + case 0x4: + case 0x18: + { + break; + } + + case 0x20: + case 0x22: + case 0x24: + case 0x26: + { + if (type == 0x22 || type == 0x26) + { + needs_root = true; + } + + min_threads = 2; // That's what appears from reversing + break; + } + + case 0x2: + case 0x6: + case 0xA: + + case 0x102: + case 0x106: + case 0x10A: + + case 0x202: + case 0x206: + case 0x20A: + + case 0x902: + case 0x906: + + case 0xA02: + case 0xA06: + + case 0xC02: + case 0xC06: + { + if (type & 0x700) + { + max_threads = 1; + } + + needs_root = true; + break; + } + default: return CELL_EINVAL; + } + + if (type & SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM) + { + // Constant size, unknown what it means but it's definitely not for each spu thread alone + mem_size = 0x40000; + use_scheduler = false; + } + else if (type & SYS_SPU_THREAD_GROUP_TYPE_NON_CONTEXT) + { + // No memory consumed + mem_size = 0; + use_scheduler = false; + } + else + { + // 256kb for each spu thread, probably for saving and restoring SPU LS (used by scheduler?) + mem_size = 0x40000 * num; + } + + if (num < min_threads || num > max_threads || + (needs_root && min_prio == 0x10) || (use_scheduler && (prio > 255 || prio < min_prio))) + { + return CELL_EINVAL; + } + + if (use_memct && mem_size) + { + const auto sct = idm::get(attr->ct); + + if (!sct) + { + return CELL_ESRCH; + } + + if (sct->take(mem_size) != mem_size) + { + return CELL_ENOMEM; + } + + ct = sct.get(); + } + else + { + ct = g_fxo->get(); + + if (ct->take(mem_size) != mem_size) + { + return CELL_ENOMEM; + } + } + + const auto group = idm::make_ptr(std::string(attr->name.get_ptr(), std::max(attr->nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size); if (!group) { + ct->used -= mem_size; return CELL_EAGAIN; } @@ -454,6 +570,7 @@ error_code sys_spu_thread_group_destroy(ppu_thread& ppu, u32 id) return CELL_EBUSY; } + group.ct->used -= group.mem_size; return {}; }); @@ -564,7 +681,7 @@ error_code sys_spu_thread_group_suspend(ppu_thread& ppu, u32 id) return CELL_ESRCH; } - if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate + if (!group->has_scheduler_context || group->type & 0xf00) { return CELL_EINVAL; } @@ -619,7 +736,7 @@ error_code sys_spu_thread_group_resume(ppu_thread& ppu, u32 id) return CELL_ESRCH; } - if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate + if (!group->has_scheduler_context || group->type & 0xf00) { return CELL_EINVAL; } @@ -666,7 +783,8 @@ error_code sys_spu_thread_group_yield(ppu_thread& ppu, u32 id) return CELL_ESRCH; } - if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate + // No effect on these group types + if (!group->has_scheduler_context || group->type & 0xf00) { return CELL_OK; } @@ -830,12 +948,7 @@ error_code sys_spu_thread_group_set_priority(ppu_thread& ppu, u32 id, s32 priori return CELL_ESRCH; } - if (priority < (g_ps3_process_info.has_root_perm() ? 0 : 16) || priority > 255) - { - return CELL_EINVAL; - } - - if (group->type == SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) + if (!group->has_scheduler_context || priority < (g_ps3_process_info.has_root_perm() ? 0 : 16) || priority > 255) { return CELL_EINVAL; } @@ -858,7 +971,7 @@ error_code sys_spu_thread_group_get_priority(ppu_thread& ppu, u32 id, vm::ptrtype == SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) + if (!group->has_scheduler_context) { *priority = 0; } diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 0ea8506533..88c73a91b5 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -7,10 +7,12 @@ #include "Emu/Memory/vm_ptr.h" #include "Utilities/File.h" +struct lv2_memory_container; + enum : s32 { SYS_SPU_THREAD_GROUP_TYPE_NORMAL = 0x00, - SYS_SPU_THREAD_GROUP_TYPE_SEQUENTIAL = 0x01, + //SYS_SPU_THREAD_GROUP_TYPE_SEQUENTIAL = 0x01, doesn't exist SYS_SPU_THREAD_GROUP_TYPE_SYSTEM = 0x02, SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER = 0x04, SYS_SPU_THREAD_GROUP_TYPE_NON_CONTEXT = 0x08, @@ -239,8 +241,10 @@ struct lv2_spu_group const std::string name; const u32 id; const u32 max_num; + const u32 mem_size; const s32 type; // SPU Thread Group Type - const u32 ct; // Memory Container Id + lv2_memory_container* const ct; // Memory Container + const bool has_scheduler_context; u32 max_run; shared_mutex mutex; @@ -264,15 +268,17 @@ struct lv2_spu_group std::weak_ptr ep_exception; // TODO: SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION std::weak_ptr ep_sysmodule; // TODO: SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE - lv2_spu_group(std::string name, u32 num, s32 prio, s32 type, u32 ct) + lv2_spu_group(std::string name, u32 num, s32 prio, s32 type, lv2_memory_container* ct, bool uses_scheduler, u32 mem_size) : id(idm::last_id()) , name(name) , max_num(num) , max_run(num) + , mem_size(mem_size) , init(0) , prio(prio) , type(type) , ct(ct) + , has_scheduler_context(uses_scheduler) , run_state(SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) , exit_status(0) , join_state(0)