diff --git a/.ci/build-mac-arm64.sh b/.ci/build-mac-arm64.sh index ce81caae6e..a1aefd2b4f 100644 --- a/.ci/build-mac-arm64.sh +++ b/.ci/build-mac-arm64.sh @@ -3,18 +3,18 @@ # shellcheck disable=SC2086 brew_arm64_install_packages() { for pkg in "$@"; do - echo "Fetching bottle for $pkg..." - bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_sonoma "$pkg")" + echo "Fetching bottle for $pkg (arm64)..." + bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")" if [ ! -f "$bottle_path" ]; then - if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --bottle-tag=arm64_sonoma "$pkg"; then + if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --verbose --debug --bottle-tag=arm64_ventura "$pkg"; then echo "Failed to fetch bottle for $pkg" return 1 fi - bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_sonoma "$pkg")" + bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")" fi - echo "Installing $pkg..." - "$BREW_ARM64_PATH/bin/brew" install --ignore-dependencies "$bottle_path" || true + echo "Installing $pkg (arm64)..." + "$BREW_ARM64_PATH/bin/brew" install --force --force-bottle --ignore-dependencies "$bottle_path" || true done } @@ -23,9 +23,14 @@ export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 export HOMEBREW_NO_INSTALL_CLEANUP=1 /usr/local/bin/brew update +sudo rm -rf /usr/local/Cellar/curl /usr/local/opt/curl +/usr/local/bin/brew install -f --overwrite curl /usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg /usr/local/bin/brew install -f --build-from-source ffmpeg@5 || true +/usr/local/bin/brew install -f --overwrite python || true +/usr/local/bin/brew link --overwrite python || true /usr/local/bin/brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg +/usr/local/bin/brew link -f curl || true /usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils /usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5 || true @@ -34,8 +39,13 @@ sudo mkdir -p "$BREW_ARM64_PATH" sudo chmod 777 "$BREW_ARM64_PATH" curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$BREW_ARM64_PATH" -"$BREW_ARM64_PATH/bin/brew" update -brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson curl dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl2 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd +#"$BREW_ARM64_PATH/bin/brew" update +# libvorbis requires Homebrew-installed curl, but we can't run it on x64, and we also need the aarch64 libs, so we swap the binary +brew_arm64_install_packages curl +mv /opt/homebrew1/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl.bak +ln -s /usr/local/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl + +brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl2 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd "$BREW_ARM64_PATH/bin/brew" link -f ffmpeg@5 # moltenvk based on commit for 1.2.11 release @@ -125,6 +135,7 @@ export MACOSX_DEPLOYMENT_TARGET=13.0 -DLLVM_TARGET_ARCH=arm64 \ -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DCMAKE_IGNORE_PATH="$BREW_X64_PATH/lib" \ + -DCMAKE_IGNORE_PREFIX_PATH=/usr/local/opt \ -DCMAKE_SYSTEM_PROCESSOR=arm64 \ -DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \ -DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \ diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index c1cef57964..0f712c6d93 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1673,6 +1673,12 @@ void spu_thread::cpu_init() status_npc.raw() = {get_type() == spu_type::isolated ? SPU_STATUS_IS_ISOLATED : 0, 0}; run_ctrl.raw() = 0; + spurs_last_task_timestamp = 0; + spurs_wait_duration_last = 0; + spurs_average_task_duration = 0; + spurs_waited = false; + spurs_entered_wait = false; + int_ctrl[0].clear(); int_ctrl[1].clear(); int_ctrl[2].clear(); @@ -4890,53 +4896,71 @@ bool spu_thread::process_mfc_cmd() // Avoid logging useless commands if there is no reservation const bool dump = g_cfg.core.mfc_debug && raddr; - const bool is_spurs_task_wait = pc == 0x11e4 && spurs_addr == raddr && g_cfg.core.max_spurs_threads != g_cfg.core.max_spurs_threads.def && !spurs_waited; + const bool is_spurs_task_wait = pc == 0x11e4 && spurs_addr; - if (is_spurs_task_wait) + if (!is_spurs_task_wait || spurs_addr != raddr || spurs_waited) + { + // + } + else if ((_ref(0x100 + 0x73) & (1u << index)) == 0 && (static_cast(rdata[0x73]) & (1u << index)) != 0) { // Wait for other threads to complete their tasks (temporarily) u32 max_run = group->max_run; - u32 prev_running = group->spurs_running.fetch_op([max_run](u32& x) + auto [prev_running, ok] = spurs_entered_wait ? std::make_pair(+group->spurs_running, false) : + group->spurs_running.fetch_op([max_run, num = group->max_num](u32& x) { - if (x >= max_run) + if (x >= max_run && max_run < num) { x--; return true; } return false; - }).first; + }); - if (prev_running == max_run && prev_running != group->max_num) + if (ok || spurs_entered_wait) { - group->spurs_running.notify_one(); + lv2_obj::prepare_for_sleep(*this); - if (group->spurs_running == max_run - 1) + if (ok) { - // Try to let another thread slip in and take over execution - thread_ctrl::wait_for(300); - - // Try to quit waiting - prev_running = group->spurs_running.fetch_op([max_run](u32& x) + if (prev_running == max_run) { - if (x < max_run) + group->spurs_running.notify_one(); + + if (group->spurs_running == max_run - 1) { - x++; - return true; + // Try to let another thread slip in and take over execution + thread_ctrl::wait_for(300); + + // Update value + prev_running = group->spurs_running + 1; } + } - return false; - }).first; + // Restore state + prev_running--; } - } - if (prev_running >= max_run) - { const u64 before = get_system_time(); u64 current = before; - lv2_obj::prepare_for_sleep(*this); + spurs_waited = true; + spurs_entered_wait = true; + + // Wait the duration of 3 tasks + const u64 spurs_wait_time = std::clamp(spurs_average_task_duration / spurs_task_count_to_calculate * 3 + 2'000, 3'000, 100'000); + spurs_wait_duration_last = spurs_wait_time; + + if (spurs_last_task_timestamp) + { + const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate; + spurs_average_task_duration -= avg_entry; + spurs_average_task_duration += std::min(45'000, before - spurs_last_task_timestamp); + spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate); + spurs_last_task_timestamp = 0; + } while (true) { @@ -4945,7 +4969,10 @@ bool spu_thread::process_mfc_cmd() break; } - thread_ctrl::wait_on(group->spurs_running, prev_running, 10000 - (current - before)); + if (prev_running >= max_run) + { + thread_ctrl::wait_on(group->spurs_running, prev_running, spurs_wait_time - (current - before)); + } max_run = group->max_run; @@ -4967,9 +4994,10 @@ bool spu_thread::process_mfc_cmd() current = get_system_time(); - if (current - before >= 10000u) + if (current - before >= spurs_wait_time) { // Timed-out + group->spurs_running++; break; } } @@ -4979,11 +5007,27 @@ bool spu_thread::process_mfc_cmd() } } - if (do_putllc(ch_mfc_cmd)) { ch_atomic_stat.set_value(MFC_PUTLLC_SUCCESS); - spurs_waited = false; + + if (is_spurs_task_wait) + { + const u64 current = get_system_time(); + + if (spurs_last_task_timestamp) + { + const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate; + spurs_average_task_duration -= avg_entry; + spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate); + spurs_average_task_duration -= avg_entry; + spurs_average_task_duration += std::min(45'000, current - spurs_last_task_timestamp); + } + + spurs_last_task_timestamp = current; + spurs_waited = false; + spurs_entered_wait = false; + } } else { @@ -5588,101 +5632,37 @@ s64 spu_thread::get_ch_value(u32 ch) return events.events & mask1; } - const bool is_spurs_task_wait = pc == 0x11a8 && spurs_addr == raddr && g_cfg.core.max_spurs_threads != g_cfg.core.max_spurs_threads.def && !spurs_waited; - - const auto wait_spurs_task = [&] - { - if (is_spurs_task_wait) - { - // Wait for other threads to complete their tasks (temporarily) - if (!is_stopped()) - { - u32 max_run = group->max_run; - - u32 prev_running = group->spurs_running.fetch_op([max_run](u32& x) - { - if (x < max_run) - { - x++; - return true; - } - - return false; - }).first; - - if (prev_running >= max_run) - { - const u64 before = get_system_time(); - u64 current = before; - - lv2_obj::prepare_for_sleep(*this); - - spurs_waited = true; - - while (true) - { - if (is_stopped()) - { - break; - } - - thread_ctrl::wait_on(group->spurs_running, prev_running, 10000u - (current - before)); - - max_run = group->max_run; - - prev_running = group->spurs_running.fetch_op([max_run](u32& x) - { - if (x < max_run) - { - x++; - return true; - } - - return false; - }).first; - - if (prev_running < max_run) - { - break; - } - - current = get_system_time(); - - if (current - before >= 10000u) - { - // Timed-out - group->spurs_running++; - break; - } - } - } - } - } - }; + const bool is_spurs_task_wait = pc == 0x11a8 && spurs_addr == raddr; if (is_spurs_task_wait) { - const u32 prev_running = group->spurs_running.fetch_op([](u32& x) + if (g_cfg.core.max_spurs_threads != g_cfg.core.max_spurs_threads.def && !spurs_entered_wait && (static_cast(rdata[0x73]) & (1u << index))) { - if (x) + const u32 prev_running = group->spurs_running.fetch_op([](u32& x) { - x--; - return true; + if (x) + { + x--; + return true; + } + + return false; + }).first; + + if (prev_running) + { + spurs_entered_wait = true; } - return false; - }).first; - - if (prev_running == group->max_run && prev_running < group->max_num) - { - group->spurs_running.notify_one(); - - spurs_waited = true; - - if (group->spurs_running == prev_running - 1) + if (prev_running == group->max_run && prev_running < group->max_num) { - // Try to let another thread slip in and take over execution - thread_ctrl::wait_for(300); + group->spurs_running.notify_one(); + + if (group->spurs_running == prev_running - 1) + { + // Try to let another thread slip in and take over execution + thread_ctrl::wait_for(300); + } } } } @@ -5918,7 +5898,6 @@ s64 spu_thread::get_ch_value(u32 ch) thread_ctrl::wait_on(state, old, 100); } - wait_spurs_task(); wakeup_delay(); if (is_paused(state - cpu_flag::suspend)) diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index a44af2c1df..2d91563a14 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -188,10 +188,10 @@ struct spu_channel_op_state struct alignas(16) spu_channel { // Low 32 bits contain value - atomic_t data; + atomic_t data{}; // Pending value to be inserted when it is possible in pop() or pop_wait() - atomic_t jostling_value; + atomic_t jostling_value{}; public: static constexpr u32 off_wait = 32; @@ -667,11 +667,11 @@ public: u8* reserv_base_addr = vm::g_reservations; // General-Purpose Registers - std::array gpr; - SPU_FPSCR fpscr; + std::array gpr{}; + SPU_FPSCR fpscr{}; // MFC command data - spu_mfc_cmd ch_mfc_cmd; + spu_mfc_cmd ch_mfc_cmd{}; // MFC command queue spu_mfc_cmd mfc_queue[16]{}; @@ -683,9 +683,9 @@ public: u64 mfc_last_timestamp = 0; // MFC proxy command data - spu_mfc_cmd mfc_prxy_cmd; + spu_mfc_cmd mfc_prxy_cmd{}; shared_mutex mfc_prxy_mtx; - atomic_t mfc_prxy_mask; + atomic_t mfc_prxy_mask = 0; // Tracks writes to MFC proxy command data union @@ -707,11 +707,11 @@ public: // Range Lock pointer atomic_t* range_lock{}; - u32 srr0; - u32 ch_tag_upd; - u32 ch_tag_mask; + u32 srr0 = 0; + u32 ch_tag_upd = 0; + u32 ch_tag_mask = 0; spu_channel ch_tag_stat; - u32 ch_stall_mask; + u32 ch_stall_mask = 0; spu_channel ch_stall_stat; spu_channel ch_atomic_stat; @@ -736,14 +736,14 @@ public: }; atomic_t ch_events; - bool interrupts_enabled; + bool interrupts_enabled = false; - u64 ch_dec_start_timestamp; // timestamp of writing decrementer value - u32 ch_dec_value; // written decrementer value + u64 ch_dec_start_timestamp = 0; // timestamp of writing decrementer value + u32 ch_dec_value = 0; // written decrementer value bool is_dec_frozen = false; std::pair read_dec() const; // Read decrementer - atomic_t run_ctrl; // SPU Run Control register (only provided to get latest data written) + atomic_t run_ctrl = 0; // SPU Run Control register (only provided to get latest data written) shared_mutex run_ctrl_mtx; struct alignas(8) status_npc_sync_var @@ -752,10 +752,10 @@ public: u32 npc; // SPU Next Program Counter register }; - atomic_t status_npc; - std::array int_ctrl; // SPU Class 0, 1, 2 Interrupt Management + atomic_t status_npc{}; + std::array int_ctrl{}; // SPU Class 0, 1, 2 Interrupt Management - std::array>, 32> spuq; // Event Queue Keys for SPU Thread + std::array>, 32> spuq{}; // Event Queue Keys for SPU Thread std::shared_ptr spup[64]; // SPU Ports spu_channel exit_status{}; // Threaded SPU exit status (not a channel, but the interface fits) atomic_t last_exit_status; // Value to be written in exit_status after checking group termination @@ -768,6 +768,11 @@ public: const u32 lv2_id; // The actual id that is used by syscalls u32 spurs_addr = 0; bool spurs_waited = false; + bool spurs_entered_wait = false; + u64 spurs_wait_duration_last = 0; + u64 spurs_average_task_duration = 0; + u64 spurs_last_task_timestamp = 0; + static constexpr u64 spurs_task_count_to_calculate = 10; spu_thread* next_cpu{}; // LV2 thread queues' node link diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index 6f519c0f69..41b24d79f8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -93,7 +93,7 @@ std::shared_ptr reserve_map(u32 alloc_size, u32 align) // Todo: fix order of error checks -error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr alloc_addr) +error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr alloc_addr) { cpu.state += cpu_flag::wait; @@ -129,9 +129,9 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr(size), align)) { - if (const u32 addr = area->alloc(size, nullptr, align)) + if (const u32 addr = area->alloc(static_cast(size), nullptr, align)) { ensure(!g_fxo->get().addrs[addr >> 16].exchange(&dct)); @@ -139,7 +139,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr(size)); cpu.check_state(); *alloc_addr = addr; return CELL_OK; @@ -155,7 +155,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr alloc_addr) +error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr alloc_addr) { cpu.state += cpu_flag::wait; @@ -203,15 +203,15 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid return {ct.ret, ct->size - ct->used}; } - if (const auto area = reserve_map(size, align)) + if (const auto area = reserve_map(static_cast(size), align)) { - if (const u32 addr = area->alloc(size)) + if (const u32 addr = area->alloc(static_cast(size))) { ensure(!g_fxo->get().addrs[addr >> 16].exchange(ct.ptr.get())); if (alloc_addr) { - vm::lock_sudo(addr, size); + vm::lock_sudo(addr, static_cast(size)); cpu.check_state(); *alloc_addr = addr; return CELL_OK; @@ -320,7 +320,7 @@ error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr cid, u32 size) +error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u64 size) { cpu.state += cpu_flag::wait; @@ -345,7 +345,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u32 si } // Create the memory container - if (const u32 id = idm::make(size, true)) + if (const u32 id = idm::make(static_cast(size), true)) { cpu.check_state(); *cid = id; diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h index 6143edc6df..5184aeed43 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -128,13 +128,13 @@ struct sys_memory_user_memory_stat_t }; // SysCalls -error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr alloc_addr); -error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid, u64 flags, vm::ptr alloc_addr); +error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr alloc_addr); +error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr alloc_addr); error_code sys_memory_free(cpu_thread& cpu, u32 start_addr); error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr attr); error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr mem_info); error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr mem_stat); -error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u32 size); +error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u64 size); error_code sys_memory_container_destroy(cpu_thread& cpu, u32 cid); error_code sys_memory_container_get_size(cpu_thread& cpu, vm::ptr mem_info, u32 cid); error_code sys_memory_container_destroy_parent_with_childs(cpu_thread& cpu, u32 cid, u32 must_0, vm::ptr mc_child); diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 86f82c8d01..3f8ae570d7 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -562,16 +562,39 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg); - const u32 option = attr->option; + if (!attr) + { + return CELL_EFAULT; + } - if (attr->name_len > 0x80 || option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE)) + const sys_spu_thread_attribute attr_data = *attr; + + if (attr_data.name_len > 0x80) { return CELL_EINVAL; } - sys_spu_image image; + if (!arg) + { + return CELL_EFAULT; + } - switch (img->type) + const sys_spu_thread_argument args = *arg; + const u32 option = attr_data.option; + + if (option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE)) + { + return CELL_EINVAL; + } + + if (!img) + { + return CELL_EFAULT; + } + + sys_spu_image image = *img; + + switch (image.type) { case SYS_SPU_IMAGE_TYPE_KERNEL: { @@ -591,12 +614,11 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g } case SYS_SPU_IMAGE_TYPE_USER: { - if (img->entry_point > 0x3fffc || img->nsegs <= 0 || img->nsegs > 0x20) + if (image.entry_point > 0x3fffc || image.nsegs <= 0 || image.nsegs > 0x20) { return CELL_EINVAL; } - image = *img; break; } default: return CELL_EINVAL; @@ -672,7 +694,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g } // Read thread name - const std::string thread_name(attr->name.get_ptr(), std::max(attr->name_len, 1) - 1); + const std::string thread_name(attr_data.name.get_ptr(), std::max(attr_data.name_len, 1) - 1); const auto group = idm::get(group_id); @@ -725,7 +747,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g ensure(vm::get(vm::spu)->falloc(spu->vm_offset(), SPU_LS_SIZE, &spu->shm, static_cast(vm::page_size_64k) | static_cast(vm::alloc_hidden))); spu->map_ls(*spu->shm, spu->ls); - group->args[inited] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4}; + group->args[inited] = {args.arg1, args.arg2, args.arg3, args.arg4}; group->imgs[inited].first = image.entry_point; group->imgs[inited].second = std::move(spu_segs); @@ -800,12 +822,14 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16; - if (attr->nsize > 0x80 || !num) + const sys_spu_thread_group_attribute attr_data = *attr; + + if (attr_data.nsize > 0x80 || !num) { return CELL_EINVAL; } - const s32 type = attr->type; + const s32 type = attr_data.type; bool use_scheduler = true; bool use_memct = !!(type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER); @@ -902,7 +926,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num if (use_memct && mem_size) { - const auto sct = idm::get(attr->ct); + const auto sct = idm::get(attr_data.ct); if (!sct) { @@ -936,7 +960,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num return CELL_EBUSY; } - 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); + const auto group = idm::make_ptr(std::string(attr_data.name.get_ptr(), std::max(attr_data.nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size); if (!group) { @@ -1909,7 +1933,7 @@ error_code sys_spu_thread_group_disconnect_event(ppu_thread& ppu, u32 id, u32 et return CELL_OK; } -error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u8 spup) +error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u32 spup) { ppu.state += cpu_flag::wait; @@ -1943,7 +1967,7 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, return CELL_OK; } -error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u8 spup) +error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u32 spup) { ppu.state += cpu_flag::wait; @@ -2144,7 +2168,7 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i return CELL_OK; } -error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u8 spup) +error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u32 spup) { ppu.state += cpu_flag::wait; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 8b0b890b39..7ce2c8b2ef 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -372,7 +372,7 @@ error_code sys_spu_thread_group_get_priority(ppu_thread&, u32 id, vm::ptr p error_code sys_spu_thread_group_connect_event(ppu_thread&, u32 id, u32 eq, u32 et); error_code sys_spu_thread_group_disconnect_event(ppu_thread&, u32 id, u32 et); error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread&, u32 id, u32 eq_id, u64 req, vm::ptr spup); -error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u8 spup); +error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u32 spup); error_code sys_spu_thread_group_set_cooperative_victims(ppu_thread&, u32 id, u32 threads_mask); error_code sys_spu_thread_group_syscall_253(ppu_thread& ppu, u32 id, vm::ptr info); error_code sys_spu_thread_group_log(ppu_thread&, s32 command, vm::ptr stat); @@ -382,8 +382,8 @@ error_code sys_spu_thread_write_spu_mb(ppu_thread&, u32 id, u32 value); error_code sys_spu_thread_set_spu_cfg(ppu_thread&, u32 id, u64 value); error_code sys_spu_thread_get_spu_cfg(ppu_thread&, u32 id, vm::ptr value); error_code sys_spu_thread_write_snr(ppu_thread&, u32 id, u32 number, u32 value); -error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u8 spup); -error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u8 spup); +error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u32 spup); +error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u32 spup); error_code sys_spu_thread_bind_queue(ppu_thread&, u32 id, u32 spuq, u32 spuq_num); error_code sys_spu_thread_unbind_queue(ppu_thread&, u32 id, u32 spuq_num); error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr status); diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index c520882341..d9993c389a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -48,13 +48,18 @@ sys_vm_t::sys_vm_t(utils::serial& ar) g_fxo->get().total_vsize += size; } -error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) +error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) { ppu.state += cpu_flag::wait; sys_vm.warning("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%x, policy=0x%x, addr=*0x%x)", vsize, psize, cid, flag, policy, addr); - if (!vsize || !psize || vsize % 0x2000000 || vsize > 0x10000000 || psize > 0x10000000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED) + if (!vsize || !psize || vsize % 0x200'0000 || vsize > 0x1000'0000 || psize > 0x1000'0000 || psize % 0x1'0000 || psize % policy != SYS_VM_POLICY_AUTO_RECOMMENDED) + { + return CELL_EINVAL; + } + + if (ppu.gpr[11] == 300 && psize < 0x10'0000) { return CELL_EINVAL; } @@ -68,16 +73,16 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 return CELL_ESRCH; } - if (!g_fxo->get().total_vsize.fetch_op([vsize](u32& size) + if (!g_fxo->get().total_vsize.fetch_op([vsize, has_root = g_ps3_process_info.has_root_perm()](u32& size) { // A single process can hold up to 256MB of virtual memory, even on DECR // VSH can hold more - if ((g_ps3_process_info.has_root_perm() ? 0x1E000000 : 0x10000000) - size < vsize) + if ((has_root ? 0x1E000000 : 0x10000000) - size < vsize) { return false; } - size += vsize; + size += static_cast(vsize); return true; }).second) { @@ -86,7 +91,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 if (!ct->take(psize)) { - g_fxo->get().total_vsize -= vsize; + g_fxo->get().total_vsize -= static_cast(vsize); return CELL_ENOMEM; } @@ -96,10 +101,10 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 sys_vm.warning("sys_vm_memory_map(): Found VM 0x%x area (vsize=0x%x)", addr, vsize); // Alloc all memory (shall not fail) - ensure(area->alloc(vsize)); - vm::lock_sudo(area->addr, vsize); + ensure(area->alloc(static_cast(vsize))); + vm::lock_sudo(area->addr, static_cast(vsize)); - idm::make(area->addr, vsize, ct, psize); + idm::make(area->addr, static_cast(vsize), ct, static_cast(psize)); // Write a pointer for the allocated memory ppu.check_state(); @@ -108,11 +113,11 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 } ct->free(psize); - g_fxo->get().total_vsize -= vsize; + g_fxo->get().total_vsize -= static_cast(vsize); return CELL_ENOMEM; } -error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) +error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) { ppu.state += cpu_flag::wait; @@ -153,7 +158,7 @@ error_code sys_vm_unmap(ppu_thread& ppu, u32 addr) return CELL_OK; } -error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size) +error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size) { ppu.state += cpu_flag::wait; @@ -176,7 +181,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size) return CELL_ENOMEM; } - vmo.psize += size; + vmo.psize += static_cast(size); return {}; }); @@ -193,7 +198,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size) return CELL_OK; } -error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size) +error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size) { ppu.state += cpu_flag::wait; @@ -213,12 +218,12 @@ error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size) auto [_, ok] = vmo.psize.fetch_op([&](u32& value) { - if (value < 0x100000ull + size) + if (value <= size || value - size < 0x100000ull) { return false; } - value -= size; + value -= static_cast(size); return true; }); diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.h b/rpcs3/Emu/Cell/lv2/sys_vm.h index f92c44564c..4d588b9200 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.h +++ b/rpcs3/Emu/Cell/lv2/sys_vm.h @@ -58,11 +58,11 @@ struct sys_vm_t class ppu_thread; // SysCalls -error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); -error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); +error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); +error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); error_code sys_vm_unmap(ppu_thread& ppu, u32 addr); -error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size); -error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size); +error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size); +error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size); error_code sys_vm_lock(ppu_thread& ppu, u32 addr, u32 size); error_code sys_vm_unlock(ppu_thread& ppu, u32 addr, u32 size); error_code sys_vm_touch(ppu_thread& ppu, u32 addr, u32 size); diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 1a6c2eec0c..5cae66d7fc 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -39,7 +39,7 @@ struct cfg_root : cfg::node cfg::_int<0, 6> preferred_spu_threads{ this, "Preferred SPU Threads", 0, true }; // Number 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", false }; // Try to detect wait loops and trigger thread yield - cfg::_int<0, 6> max_spurs_threads{ this, "Max SPURS Threads", 6, true }; // HACK. If less then 6, max number of running SPURS threads in each thread group. + cfg::_int<1, 6> max_spurs_threads{ this, "Max SPURS Threads", 6, true }; // 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_dma{ this, "Accurate SPU DMA", false }; cfg::_bool spu_accurate_reservations{ this, "Accurate SPU Reservations", true }; diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index 65df4c6cdc..5bf39052eb 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -494,6 +494,7 @@ int main(int argc, char** argv) } const std::string lock_name = fs::get_cache_dir() + "RPCS3.buf"; + const std::string log_name = fs::get_cache_dir() + "RPCS3.log"; static fs::file instance_lock; @@ -512,19 +513,19 @@ int main(int argc, char** argv) { if (fs::exists(lock_name)) { - report_fatal_error("Another instance of RPCS3 is running.\nClose it or kill its process, if necessary."); + report_fatal_error(fmt::format("Another instance of RPCS3 is running.\nClose it or kill its process, if necessary.\n'%s' still exists.", lock_name)); } - report_fatal_error("Cannot create RPCS3.log (access denied)." + report_fatal_error(fmt::format("Cannot create '%s' or '%s' (access denied).\n" #ifdef _WIN32 - "\nNote that RPCS3 cannot be installed in Program Files or similar directories with limited permissions." + "Note that RPCS3 cannot be installed in Program Files or similar directories with limited permissions." #else - "\nPlease, check RPCS3 permissions in '~/.config/rpcs3'." + "Please, check RPCS3 permissions." #endif - ); + , log_name, lock_name)); } - report_fatal_error(fmt::format("Cannot create RPCS3.log (error %s)", fs::g_tls_error)); + report_fatal_error(fmt::format("Cannot create'%s' or '%s' (error=%s)", log_name, lock_name, fs::g_tls_error)); } #ifdef _WIN32 @@ -568,7 +569,7 @@ int main(int argc, char** argv) } // Limit log size to ~25% of free space - log_file = logs::make_file_listener(fs::get_cache_dir() + "RPCS3.log", stats.avail_free / 4); + log_file = logs::make_file_listener(log_name, stats.avail_free / 4); } static std::unique_ptr fatal_listener = std::make_unique(); diff --git a/rpcs3/util/logs.cpp b/rpcs3/util/logs.cpp index 4e82126832..8ef9404e20 100644 --- a/rpcs3/util/logs.cpp +++ b/rpcs3/util/logs.cpp @@ -451,47 +451,47 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, ...) co logs::file_writer::file_writer(const std::string& name, u64 max_size) : m_max_size(max_size) { - if (!name.empty() && max_size) + if (name.empty() || !max_size) { - // Initialize ringbuffer - m_fptr = std::make_unique(s_log_size); + return; + } - // Actual log file (allowed to fail) - if (!m_fout.open(name, fs::rewrite)) - { - fprintf(stderr, "Log file open failed: %s (error %d)\n", name.c_str(), errno); - } + // Initialize ringbuffer + m_fptr = std::make_unique(s_log_size); - // Compressed log, make it inaccessible (foolproof) - if (m_fout2.open(name + ".gz", fs::rewrite + fs::unread)) - { + // Actual log file (allowed to fail) + if (!m_fout.open(name, fs::rewrite)) + { + fprintf(stderr, "Log file open failed: %s (error %d)\n", name.c_str(), errno); + } + + // Compressed log, make it inaccessible (foolproof) + if (m_fout2.open(name + ".gz", fs::rewrite + fs::unread)) + { #ifndef _MSC_VER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif - if (deflateInit2(&m_zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) != Z_OK) + if (deflateInit2(&m_zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) != Z_OK) #ifndef _MSC_VER #pragma GCC diagnostic pop #endif - m_fout2.close(); - } - - if (!m_fout2) { - fprintf(stderr, "Log file open failed: %s.gz (error %d)\n", name.c_str(), errno); + m_fout2.close(); } + } + + if (!m_fout2) + { + fprintf(stderr, "Log file open failed: %s.gz (error %d)\n", name.c_str(), errno); + } #ifdef _WIN32 - // Autodelete compressed log file - FILE_DISPOSITION_INFO disp; - disp.DeleteFileW = true; - SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp)); + // Autodelete compressed log file + FILE_DISPOSITION_INFO disp{}; + disp.DeleteFileW = true; + SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp)); #endif - } - else - { - return; - } m_writer = std::thread([this]() {