From d7f8e25cca86a0eae5f5f5d4338babee5936023c Mon Sep 17 00:00:00 2001 From: Ani Date: Tue, 7 Apr 2026 13:16:27 +0200 Subject: [PATCH 1/3] SPU: Remove RCHCNT loop handling of SPU_WrOutMbox Fixes freezing in Half-Life 2 Fixes #17958 --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 6837baaa97..87c61042a6 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -4357,11 +4357,6 @@ public: { switch (op.ra) { - case SPU_WrOutMbox: - { - res.value = wait_rchcnt(::offset32(&spu_thread::ch_out_mbox), true); - break; - } case SPU_WrOutIntrMbox: { res.value = wait_rchcnt(::offset32(&spu_thread::ch_out_intr_mbox), true); From beac01d5d1bb4ccc67d8f3ab3c86e9cd374c4acf Mon Sep 17 00:00:00 2001 From: Ani Date: Tue, 7 Apr 2026 13:35:20 +0200 Subject: [PATCH 2/3] SPU: Remove RCHCNT loop handling of SPU_WrOutIntrMbox --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 87c61042a6..f0a8c9f7db 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -4357,11 +4357,6 @@ public: { switch (op.ra) { - case SPU_WrOutIntrMbox: - { - res.value = wait_rchcnt(::offset32(&spu_thread::ch_out_intr_mbox), true); - break; - } case SPU_RdSigNotify1: { res.value = wait_rchcnt(::offset32(&spu_thread::ch_snr1)); From 8e80ddd99fe7a025177459306b2167633b0059ca Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 8 Apr 2026 10:52:03 +0200 Subject: [PATCH 3/3] ISO: optimize some file reads (#18511) - Batch some file reads in iso_read_directory_entry (speeds up indexing by ~41% on my test iso) - Fix some warnings --- rpcs3/Emu/RSX/NV47/FW/draw_call.hpp | 2 +- rpcs3/Emu/RSX/RSXThread.cpp | 4 +- rpcs3/Loader/ISO.cpp | 87 ++++++++++++++++++----------- 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/rpcs3/Emu/RSX/NV47/FW/draw_call.hpp b/rpcs3/Emu/RSX/NV47/FW/draw_call.hpp index 0fe726d417..7b2591f544 100644 --- a/rpcs3/Emu/RSX/NV47/FW/draw_call.hpp +++ b/rpcs3/Emu/RSX/NV47/FW/draw_call.hpp @@ -33,7 +33,7 @@ namespace rsx u32 draw_command_barrier_mask = 0; // Draw-time iterator to the draw_command_barriers struct - mutable rsx::simple_array::iterator current_barrier_it; + mutable rsx::simple_array::iterator current_barrier_it {}; // Subranges memory cache mutable rsx::simple_array subranges_store; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index a7338cbf56..33fd4a662b 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2970,7 +2970,7 @@ namespace rsx auto& cfg = g_fxo->get(); - std::unique_lock hle_lock; + std::optional> hle_lock; for (u32 i = 0; i < std::size(unmap_status); i++) { @@ -3011,7 +3011,7 @@ namespace rsx if (hle_lock) { - hle_lock.unlock(); + hle_lock->unlock(); } // Pause RSX thread momentarily to handle unmapping diff --git a/rpcs3/Loader/ISO.cpp b/rpcs3/Loader/ISO.cpp index 0ddc3e39d9..544b04d379 100644 --- a/rpcs3/Loader/ISO.cpp +++ b/rpcs3/Loader/ISO.cpp @@ -37,62 +37,82 @@ bool is_file_iso(const fs::file& file) const int ISO_BLOCK_SIZE = 2048; template -inline T read_both_endian_int(fs::file& file) +inline T retrieve_endian_int(const u8* buf) { - T out; + T out {}; - if (std::endian::little == std::endian::native) + if constexpr (std::endian::little == std::endian::native) { - out = file.read(); - file.seek(sizeof(T), fs::seek_cur); + // first half = little-endian copy + std::memcpy(&out, buf, sizeof(T)); } else { - file.seek(sizeof(T), fs::seek_cur); - out = file.read(); + // second half = big-endian copy + std::memcpy(&out, buf + sizeof(T), sizeof(T)); } return out; } // assumed that directory_entry is at file head -std::optional iso_read_directory_entry(fs::file& file, bool names_in_ucs2 = false) +static std::optional iso_read_directory_entry(fs::file& entry, bool names_in_ucs2 = false) { - const auto start_pos = file.pos(); - const u8 entry_length = file.read(); + const auto start_pos = entry.pos(); + const u8 entry_length = entry.read(); if (entry_length == 0) return std::nullopt; - file.seek(1, fs::seek_cur); - const u32 start_sector = read_both_endian_int(file); - const u32 file_size = read_both_endian_int(file); + // Batch this set of file reads. This reduces overall time spent in iso_read_directory_entry by ~41% +#pragma pack(push, 1) + struct iso_entry_header + { + //u8 entry_length; // Handled separately + u8 extended_attribute_length; + u8 start_sector[8]; + u8 file_size[8]; + u8 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 timezone_value; + u8 flags; + u8 file_unit_size; + u8 interleave; + u8 volume_sequence_number[4]; + u8 file_name_length; + //u8 file_name[file_name_length]; // Handled separately + }; +#pragma pack(pop) + static_assert(sizeof(iso_entry_header) == 32); + + const iso_entry_header header = entry.read(); + + const u32 start_sector = retrieve_endian_int(header.start_sector); + const u32 file_size = retrieve_endian_int(header.file_size); std::tm file_date = {}; - file_date.tm_year = file.read(); - file_date.tm_mon = file.read() - 1; - file_date.tm_mday = file.read(); - file_date.tm_hour = file.read(); - file_date.tm_min = file.read(); - file_date.tm_sec = file.read(); - const s16 timezone_value = file.read(); + file_date.tm_year = header.year; + file_date.tm_mon = header.month - 1; + file_date.tm_mday = header.day; + file_date.tm_hour = header.hour; + file_date.tm_min = header.minute; + file_date.tm_sec = header.second; + const s16 timezone_value = header.timezone_value; const s16 timezone_offset = (timezone_value - 50) * 15 * 60; const std::time_t date_time = std::mktime(&file_date) + timezone_offset; - const u8 flags = file.read(); - // 2nd flag bit indicates whether a given fs node is a directory - const bool is_directory = flags & 0b00000010; - const bool has_more_extents = flags & 0b10000000; - - file.seek(6, fs::seek_cur); - - const u8 file_name_length = file.read(); + const bool is_directory = header.flags & 0b00000010; + const bool has_more_extents = header.flags & 0b10000000; std::string file_name; - file.read(file_name, file_name_length); + entry.read(file_name, header.file_name_length); - if (file_name_length == 1 && file_name[0] == 0) + if (header.file_name_length == 1 && file_name[0] == 0) { file_name = "."; } @@ -104,7 +124,7 @@ std::optional iso_read_directory_entry(fs::file& file, bool nam { // characters are stored in big endian format. std::u16string utf16; - utf16.resize(file_name_length / 2); + utf16.resize(header.file_name_length / 2); const u16* raw = reinterpret_cast(file_name.data()); for (size_t i = 0; i < utf16.size(); ++i, raw++) @@ -120,13 +140,13 @@ std::optional iso_read_directory_entry(fs::file& file, bool nam file_name.erase(file_name.end() - 2, file_name.end()); } - if (file_name_length > 1 && file_name.ends_with(".")) + if (header.file_name_length > 1 && file_name.ends_with(".")) { file_name.pop_back(); } // skip the rest of the entry. - file.seek(entry_length + start_pos); + entry.seek(entry_length + start_pos); return iso_fs_metadata { @@ -180,6 +200,7 @@ void iso_form_hierarchy(fs::file& file, iso_fs_node& node, bool use_ucs2_decodin selected_node->metadata.extents.push_back(entry->extents[0]); extent_added = true; + break; } }