diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 490605c792..aff4537dea 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -166,6 +166,7 @@ static fs::error to_error(int e) case ENOTEMPTY: return fs::error::notempty; case EROFS: return fs::error::readonly; case EISDIR: return fs::error::isdir; + case ENOTDIR: return fs::error::notdir; case ENOSPC: return fs::error::nospace; case EXDEV: return fs::error::xdev; default: return fs::error::unknown; @@ -2833,6 +2834,7 @@ void fmt_class_string::format(std::string& out, u64 arg) case fs::error::notempty: return "Not empty"; case fs::error::readonly: return "Read only"; case fs::error::isdir: return "Is a directory"; + case fs::error::notdir: return "Not a directory"; case fs::error::toolong: return "Path too long"; case fs::error::nospace: return "Not enough space on the device"; case fs::error::xdev: return "Device mismatch"; diff --git a/Utilities/File.h b/Utilities/File.h index dd2db42a46..3d332dd0be 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -683,6 +683,7 @@ namespace fs notempty, readonly, isdir, + notdir, toolong, nospace, xdev, diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index b10845889b..4e8c044113 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -2957,7 +2957,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (g_cfg.core.spu_block_size == spu_block_size_type::safe) { // Stop on special instructions (TODO) - m_targets[pos]; + m_targets[pos].push_back(SPU_LS_SIZE); next_block(); break; } @@ -2978,7 +2978,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s spu_log.error("[0x%x] Invalid interrupt flags (DE)", pos); } - m_targets[pos]; + m_targets[pos].push_back(SPU_LS_SIZE); next_block(); break; } @@ -3011,7 +3011,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s bool is_no_return = false; - if (pos_next >= lsa && pos_next < limit) + if (sl && pos_next >= lsa && pos_next < limit) { const u32 data_next = ls[pos_next / 4]; const auto type_next = g_spu_itype.decode(data_next); @@ -3274,6 +3274,12 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s spu_log.notice("[0x%x] At 0x%x: ignoring indirect branch (SYNC)", entry_point, pos); } + if (!(af & vf::is_const)) + { + // Possible unknown target + m_targets[pos].emplace_back(SPU_LS_SIZE); + } + if (type == spu_itype::BI || sl || is_no_return) { if (type == spu_itype::BI || g_cfg.core.spu_block_size == spu_block_size_type::safe || is_no_return) @@ -3883,6 +3889,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s it->second.emplace_back(SPU_LS_SIZE); } + std::sort(it->second.begin(), it->second.end()); it++; } @@ -6087,17 +6094,17 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max; - if (m_use_ra.test(pos / 4)) + if (::at32(m_use_ra, pos / 4)) { ra = op.ra; } - if (m_use_rb.test(pos / 4)) + if (::at32(m_use_rb, pos / 4)) { rb = op.rb; } - if (m_use_rc.test(pos / 4)) + if (::at32(m_use_rc, pos / 4)) { rc = op.rc; } @@ -6312,10 +6319,6 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s case spu_itype::BI: case spu_itype::BISL: case spu_itype::BISLED: - case spu_itype::BIZ: - case spu_itype::BINZ: - case spu_itype::BIHZ: - case spu_itype::BIHNZ: { if (op.e || op.d) { @@ -6361,11 +6364,11 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s const auto& b = ::at32(m_bbs, reduced_loop->loop_pc); const auto& b2 = ::at32(m_bbs, bpc); - if (!reduced_loop->loop_dicts.test(i)) + if (!::at32(reduced_loop->loop_dicts, i)) { - if (b.reg_use[i] || (!b.reg_mod.test(i) && b2.reg_use[i])) + if (b.reg_use[i] || (!::at32(b.reg_mod, i) && b2.reg_use[i])) { - if ((b.reg_use[i] && b.reg_mod.test(i)) || b2.reg_mod.test(i)) + if ((b.reg_use[i] && ::at32(b.reg_mod, i)) || ::at32(b2.reg_mod, i)) { reduced_loop->is_constant_expression = false; reduced_loop->loop_writes.set(i); @@ -6416,12 +6419,23 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } case spu_itype::BRHZ: case spu_itype::BRHNZ: - { - const u32 next_pc = spu_branch_target(pos, 1); - const u32 target = spu_branch_target(pos, op.i16); - const bool is_u16_jump = type == spu_itype::BRHZ || type == spu_itype::BRHNZ; - const bool is_jump_zero = (type == spu_itype::BRZ || type == spu_itype::BRHZ) ^ reduced_loop->is_two_block_loop; + case spu_itype::BIZ: + case spu_itype::BINZ: + case spu_itype::BIHZ: + case spu_itype::BIHNZ: + { + if (type == spu_itype::spu_itype::BIZ || type == spu_itype::BINZ || type == spu_itype::BIHZ || type == spu_itype::BIHNZ) + { + if (op.e || op.d) + { + break_all_patterns(27); + break; + } + } + + const bool is_u16_jump = type == spu_itype::BRHZ || type == spu_itype::BRHNZ || type == spu_itype::BIHZ || type == spu_itype::BIHNZ; + const bool is_jump_zero = (type == spu_itype::BRZ || type == spu_itype::BRHZ || type == spu_itype::BIZ || type == spu_itype::BIHZ) ^ reduced_loop->is_two_block_loop; while (reduced_loop->active) { @@ -6598,7 +6612,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < reg->regs.size() && reduced_loop->active; i++) { - if (reg->regs.test(i)) + if (::at32(reg->regs, i)) { if (0) if (i == op_rt || reg->modified == 0) { @@ -6644,11 +6658,11 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s auto reg_org = reduced_loop->find_reg(i); u32 reg_index = i; - if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !reg_org->regs.test(i)) + if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !::at32(reg_org->regs, i)) { for (u32 j = 0; j <= s_reg_127; j++) { - if (reg_org->regs.test(j)) + if (::at32(reg_org->regs, j)) { if (const auto reg_found = reduced_loop->find_reg(j)) { @@ -6728,8 +6742,8 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s { reduced_loop->cond_val_incr_is_immediate = false; - const u32 op_ra = spu_opcode_t{reg->IMM}.ra; - const u32 op_rb = spu_opcode_t{reg->IMM}.rb; + const u32 op_ra = spu_opcode_t{reg_org->IMM}.ra; + const u32 op_rb = spu_opcode_t{reg_org->IMM}.rb; if (!(op_ra == reg_index || op_rb == reg_index)) { @@ -7040,11 +7054,11 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s const auto& b = ::at32(m_bbs, reduced_loop->loop_pc); const auto& b2 = ::at32(m_bbs, bpc); - if (!reduced_loop->loop_dicts.test(i)) + if (!::at32(reduced_loop->loop_dicts, i)) { - if (b.reg_use[i] || (!b.reg_mod.test(i) && b2.reg_use[i])) + if (b.reg_use[i] || (!::at32(b.reg_mod, i) && b2.reg_use[i])) { - if ((b.reg_use[i] && b.reg_mod.test(i)) || b2.reg_mod.test(i)) + if ((b.reg_use[i] && ::at32(b.reg_mod, i)) || ::at32(b2.reg_mod, i)) { reduced_loop->is_constant_expression = false; reduced_loop->loop_writes.set(i); @@ -8298,17 +8312,17 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max; - if (m_use_ra.test(pos / 4)) + if (::at32(m_use_ra, pos / 4)) { ra = op.ra; } - if (m_use_rb.test(pos / 4)) + if (::at32(m_use_rb, pos / 4)) { rb = op.rb; } - if (m_use_rc.test(pos / 4)) + if (::at32(m_use_rc, pos / 4)) { rc = op.rc; } @@ -8575,7 +8589,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s for (u32 i = 0; i < s_reg_max; i++) { - if (pattern.loop_writes.test(i)) + if (::at32(pattern.loop_writes, i)) { if (regs.size() != 1) { @@ -8585,7 +8599,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s fmt::append(regs, " r%u-w", i); } - if (pattern.loop_args.test(i)) + if (::at32(pattern.loop_args, i)) { if (regs.size() != 1) { diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 948c6e8b14..b13c27e376 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -180,7 +180,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator bool is_gpr_not_NaN_hint(u32 i) const noexcept { - return block_wide_reg_store_elimination && bb->reg_maybe_float[i] && bb->reg_use[i] >= 3 && !bb->reg_mod[i]; + return block_wide_reg_store_elimination && ::at32(bb->reg_maybe_float, i) && ::at32(bb->reg_use, i) >= 3 && !::at32(bb->reg_mod, i); } }; @@ -2536,6 +2536,11 @@ public: condition = m_ir->CreateAnd(cond_nans, condition); prev_i = umax; } + + if (is_last) + { + break; + } } } diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 1fd295f2f6..54ddcb2f1e 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -11,6 +11,17 @@ #include #include +// std::bitset +template + requires requires(std::remove_cvref_t& x, T&& y) { x.count(); x.test(y); x.flip(y); } +[[nodiscard]] constexpr bool at32(CT&& container, T&& index, std::source_location src_loc = std::source_location::current()) +{ + const usz csv = container.size(); + if (csv <= std::forward(index)) [[unlikely]] + fmt::raw_range_error(src_loc, format_object_simplified(index), csv); + return container[std::forward(index)]; +} + // Helper class class spu_cache { @@ -421,7 +432,7 @@ public: return true; } - return regs.count() == 1 && regs.test(reg_val); + return regs.count() == 1 && ::at32(regs, reg_val); } bool is_loop_dictator(u32 reg_val, bool test_predictable = false, bool should_predictable = true) const @@ -431,7 +442,7 @@ public: return false; } - if (regs.count() >= 1 && regs.test(reg_val)) + if (regs.count() >= 1 && ::at32(regs, reg_val)) { if (!test_predictable) { @@ -490,7 +501,7 @@ public: return false; } - if (regs.count() - (regs.test(reg_val) ? 1 : 0)) + if (regs.count() - (::at32(regs, reg_val) ? 1 : 0)) { return false; } diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index beec0fc4e4..2534f6a8c1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -140,6 +140,32 @@ bool verify_mself(const fs::file& mself_file) return true; } +// TODO: May not be thread-safe (or even, process-safe) +bool has_non_directory_components(std::string_view path) +{ + std::string path0{path}; + + while (true) + { + const std::string sub_path = fs::get_parent_dir(path0); + + if (sub_path.size() >= path0.size()) + { + break; + } + + fs::stat_t stat{}; + if (fs::get_stat(sub_path, stat)) + { + return !stat.is_directory; + } + + path0 = std::move(sub_path); + } + + return false; +} + lv2_fs_mount_info_map::lv2_fs_mount_info_map() { for (auto mp = &g_mp_sys_dev_root; mp; mp = mp->next) // Scan and keep track of pre-mounted devices @@ -899,8 +925,17 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3 switch (auto error = fs::g_tls_error) { + case fs::error::notdir: return {CELL_ENOTDIR}; case fs::error::noent: return {CELL_ENOENT}; - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return {CELL_ENOTDIR}; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1372,6 +1407,11 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr path, vm::ptr fd) } default: { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + fmt::throw_exception("unknown error %s", error); } } @@ -1555,6 +1595,10 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr path, vm::ptr { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { // Try to analyse split file (TODO) @@ -1594,6 +1638,11 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr path, vm::ptr } default: { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + fmt::throw_exception("unknown error %s", error); } } @@ -1720,6 +1769,10 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr path, s32 mode) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; @@ -1728,7 +1781,15 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr path, s32 mode) { return {sys_fs.warning, CELL_EEXIST, path}; } - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1789,9 +1850,18 @@ error_code sys_fs_rename(ppu_thread& ppu, vm::cptr from, vm::cptr to { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: return {CELL_ENOTDIR, from}; case fs::error::noent: return {CELL_ENOENT, from}; case fs::error::exist: return {CELL_EEXIST, to}; - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_from)) + { + return {CELL_ENOTDIR, from}; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1842,9 +1912,18 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr path) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: return {CELL_ENOTDIR, path}; case fs::error::noent: return {CELL_ENOENT, path}; case fs::error::notempty: return {CELL_ENOTEMPTY, path}; - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -1896,11 +1975,23 @@ error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr path) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path }; + } case fs::error::noent: { return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; } - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -2737,7 +2828,15 @@ error_code sys_fs_get_block_size(ppu_thread& ppu, vm::cptr path, vm::ptr path, u64 size) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { return {mp == &g_mp_sys_dev_hdd1 ? sys_fs.warning : sys_fs.error, CELL_ENOENT, path}; } - default: fmt::throw_exception("unknown error %s", error); + default: + { + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); + } } } @@ -2840,7 +2951,10 @@ error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size) switch (auto error = fs::g_tls_error) { case fs::error::ok: - default: fmt::throw_exception("unknown error %s", error); + default: + { + fmt::throw_exception("unknown error %s", error); + } } } @@ -2887,6 +3001,10 @@ error_code sys_fs_chmod(ppu_thread&, vm::cptr path, s32 mode) { switch (auto error = fs::g_tls_error) { + case fs::error::notdir: + { + return { CELL_ENOTDIR, path}; + } case fs::error::noent: { // Try to locate split files @@ -2900,8 +3018,12 @@ error_code sys_fs_chmod(ppu_thread&, vm::cptr path, s32 mode) } default: { - sys_fs.error("sys_fs_chmod(): unknown error %s", error); - return {CELL_EIO, path}; + if (has_non_directory_components(local_path)) + { + return { CELL_ENOTDIR, path }; + } + + fmt::throw_exception("unknown error %s", error); } } } @@ -3033,11 +3155,23 @@ error_code sys_fs_utime(ppu_thread& ppu, vm::cptr path, vm::cptr inputs; SRC_Common src { .HEX = instruction->bytecode[operand + 1] }; - if (src.reg_type != RSX_FP_REGISTER_TYPE_TEMP) + if (src.reg_type != RSX_FP_REGISTER_TYPE_TEMP && + src.reg_type != RSX_FP_REGISTER_TYPE_INPUT) { return 0; } diff --git a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp index 28cbaa61f0..febb5c93bd 100644 --- a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp +++ b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp @@ -418,6 +418,11 @@ namespace glsl enabled_options.push_back("_ENABLE_DEPTH_FORMAT_RECONSTRUCTION"); } + if (props.require_msaa_ops) + { + enabled_options.push_back("_ENABLE_TEXTURE_MULTISAMPLE"); + } + program_common::define_glsl_switches(OS, enabled_options); enabled_options.clear(); diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl index aaf4dc434a..19f3ff3f9c 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl @@ -46,7 +46,7 @@ R"( _texture_bx2_active = false; \ } while (false) #define TEX_FLAGS(index) ((TEX_PARAM(index).flags & ~(_texture_flag_erase)) | _texture_flag_override) -#elif defined(_ENABLE_TEXTURE_ALPHA_KILL) || defined(_ENABLE_FORMAT_CONVERSION) || defined(_ENABLE_DEPTH_FORMAT_RECONSTRUCTION) +#elif defined(_ENABLE_TEXTURE_ALPHA_KILL) || defined(_ENABLE_FORMAT_CONVERSION) || defined(_ENABLE_DEPTH_FORMAT_RECONSTRUCTION) || defined(_ENABLE_TEXTURE_MULTISAMPLE) #define TEX_FLAGS(index) (TEX_PARAM(index).flags) #else #define TEX_FLAGS(index) 0 diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 3392b9693b..a7338cbf56 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -712,9 +712,12 @@ namespace rsx { m_overlay_manager = g_fxo->init(0); - if (const std::string audio_path = Emu.GetSfoDir(true) + "/SND0.AT3"; fs::is_file(audio_path)) + if (g_cfg.misc.play_music_during_boot) { - m_overlay_manager->start_audio(audio_path); + if (const std::string audio_path = Emu.GetSfoDir(true) + "/SND0.AT3"; fs::is_file(audio_path)) + { + m_overlay_manager->start_audio(audio_path); + } } } diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index 0bcf1caf8b..c411f6e480 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -254,7 +254,9 @@ enum class localized_string_id HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT, HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT, HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT, + HOME_MENU_SETTINGS_OVERLAYS_SHOW_FATAL_ERROR_HINTS, HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS, + HOME_MENU_SETTINGS_OVERLAYS_PLAY_MUSIC_DURING_BOOT, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE, HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE_FRAMERATE_GRAPH, diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 099e0243a1..9dbaa0c723 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -357,12 +357,14 @@ struct cfg_root : cfg::node cfg::_bool show_pressure_intensity_toggle_hint{ this, "Show pressure intensity toggle hint", true, true }; cfg::_bool show_analog_limiter_toggle_hint{ this, "Show analog limiter toggle hint", true, true }; cfg::_bool show_mouse_and_keyboard_toggle_hint{ this, "Show mouse and keyboard toggle hint", true, true }; + cfg::_bool show_fatal_error_hints{ this, "Show fatal error hints", false, true }; cfg::_bool show_capture_hints{ this, "Show capture hints", true, true }; cfg::_bool use_native_interface{ this, "Use native user interface", true }; cfg::string gdb_server{ this, "GDB Server", "127.0.0.1:2345" }; cfg::_bool silence_all_logs{ this, "Silence All Logs", false, true }; cfg::string title_format{ this, "Window Title Format", "FPS: %F | %R | %V | %T [%t]", true }; cfg::_bool pause_during_home_menu{this, "Pause Emulation During Home Menu", false, false }; + cfg::_bool play_music_during_boot{this, "Play music during boot sequence", true, true }; cfg::_bool enable_gamemode{ this, "Enable GameMode", false, false }; } misc{ this }; diff --git a/rpcs3/Loader/ISO.cpp b/rpcs3/Loader/ISO.cpp index a80d664174..0ddc3e39d9 100644 --- a/rpcs3/Loader/ISO.cpp +++ b/rpcs3/Loader/ISO.cpp @@ -585,10 +585,8 @@ std::unique_ptr iso_device::open_dir(const std::string& path) if (!node->metadata.is_directory) { - // fs::dir::open -> ::readdir should return ENOTDIR when path is - // pointing to a file instead of a folder, which translates to error::unknown. - // doing the same here. - fs::g_tls_error = fs::error::unknown; + // fs::dir::open -> ::readdir should return ENOTDIR when path is pointing to a file instead of a folder. + fs::g_tls_error = fs::error::notdir; return nullptr; } diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 921394e311..011dfbe39f 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -68,6 +68,7 @@ DYNAMIC_IMPORT("ntdll.dll", NtSetTimerResolution, NTSTATUS(ULONG DesiredResoluti #include "util/media_utils.h" #include "rpcs3_version.h" #include "Emu/System.h" +#include "Emu/system_config.h" #include "Emu/system_utils.hpp" #include "Emu/RSX/Overlays/overlay_message.h" #include @@ -353,11 +354,14 @@ public: #endif if (msg == logs::level::fatal) { - std::string overlay_msg = "Fatal error: " + _msg.substr(rpcs3_prefix.size()); - fmt::trim_back(overlay_msg, " \t\n"); + if (g_cfg.misc.show_fatal_error_hints) + { + std::string overlay_msg = "Fatal error: " + _msg.substr(rpcs3_prefix.size()); + fmt::trim_back(overlay_msg, " \t\n"); + rsx::overlays::queue_message(overlay_msg, umax); + } // Pause emulation if fatal error encountered - rsx::overlays::queue_message(overlay_msg, umax); Emu.Pause(true); } } diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index b8ed1d642f..2184974d85 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -58,6 +58,7 @@ debugger_frame::debugger_frame(std::shared_ptr gui_settings, QWidg : custom_dock_widget(tr("Debugger [Press F1 for Help]"), parent) , m_gui_settings(std::move(gui_settings)) { + setObjectName("debugger"); setContentsMargins(0, 0, 0, 0); m_update = new QTimer(this); diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index 9b9f8a9279..db3e3556da 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -189,9 +189,11 @@ enum class emu_settings_type ShowPressureIntensityToggleHint, ShowAnalogLimiterToggleHint, ShowMouseAndKeyboardToggleHint, + ShowFatalErrorHints, ShowCaptureHints, WindowTitleFormat, PauseDuringHomeMenu, + PlayMusicDuringBoot, EnableGamemode, // Network @@ -405,10 +407,12 @@ inline static const std::map settings_location { emu_settings_type::ShowPressureIntensityToggleHint, { "Miscellaneous", "Show pressure intensity toggle hint"}}, { emu_settings_type::ShowAnalogLimiterToggleHint, { "Miscellaneous", "Show analog limiter toggle hint"}}, { emu_settings_type::ShowMouseAndKeyboardToggleHint, { "Miscellaneous", "Show mouse and keyboard toggle hint"}}, + { emu_settings_type::ShowFatalErrorHints, { "Miscellaneous", "Show fatal error hints"}}, { emu_settings_type::ShowCaptureHints, { "Miscellaneous", "Show capture hints" }}, { emu_settings_type::SilenceAllLogs, { "Miscellaneous", "Silence All Logs" }}, { emu_settings_type::WindowTitleFormat, { "Miscellaneous", "Window Title Format" }}, { emu_settings_type::PauseDuringHomeMenu, { "Miscellaneous", "Pause Emulation During Home Menu" }}, + { emu_settings_type::PlayMusicDuringBoot, { "Miscellaneous", "Play music during boot sequence" }}, { emu_settings_type::EnableGamemode, { "Miscellaneous", "Enable GameMode" }}, // Networking diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 7ef27ea0f9..36e26cf43d 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -40,6 +40,8 @@ game_list_frame::game_list_frame(std::shared_ptr gui_settings, std , m_emu_settings(std::move(emu_settings)) , m_persistent_settings(std::move(persistent_settings)) { + setObjectName("gamelist"); + m_game_list_actions = std::make_shared(this, m_gui_settings); m_icon_size = gui::gl_icon_size_min; // ensure a valid size diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index c15b4166bf..41be2732ab 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -173,7 +173,7 @@ namespace gui const gui_save fd_save_log = gui_save(main_window, "lastExplorePathSaveLog", ""); const gui_save mw_debugger = gui_save(main_window, "debuggerVisible", false); - const gui_save mw_logger = gui_save(main_window, "loggerVisible", true); + const gui_save mw_logger = gui_save(main_window, "loggerVisible", false); const gui_save mw_gamelist = gui_save(main_window, "gamelistVisible", true); const gui_save mw_toolBarVisible = gui_save(main_window, "toolBarVisible", true); const gui_save mw_titleBarsVisible = gui_save(main_window, "titleBarsVisible", true); diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index fe0451b44c..ba4960aa73 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -274,7 +274,9 @@ private: case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_PRESSURE_INTENSITY_TOGGLE_HINT: return tr("Show Pressure Intensity Toggle Hint", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_ANALOG_LIMITER_TOGGLE_HINT: return tr( "Show Analog Limiter Toggle Hint", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_MOUSE_AND_KB_TOGGLE_HINT: return tr("Show Mouse And Keyboard Toggle Hint", "Overlays"); + case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_SHOW_FATAL_ERROR_HINTS: return tr("Show Fatal Error Hints", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_RECORD_WITH_OVERLAYS: return tr("Record With Overlays", "Overlays"); + case localized_string_id::HOME_MENU_SETTINGS_OVERLAYS_PLAY_MUSIC_DURING_BOOT: return tr("Play music during boot sequence.", "Overlays"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY: return tr("Performance Overlay"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE: return tr("Enable Performance Overlay", "Performance Overlay"); case localized_string_id::HOME_MENU_SETTINGS_PERFORMANCE_OVERLAY_ENABLE_FRAMERATE_GRAPH: return tr("Enable Framerate Graph", "Performance Overlay"); diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index cf570eea7a..61ca66a909 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -113,6 +113,8 @@ static gui_listener s_gui_listener; log_frame::log_frame(std::shared_ptr _gui_settings, QWidget* parent) : custom_dock_widget(tr("Log"), parent), m_gui_settings(std::move(_gui_settings)) { + setObjectName("logger"); + const int max_block_count_log = m_gui_settings->GetValue(gui::l_limit).toInt(); const int max_block_count_tty = m_gui_settings->GetValue(gui::l_limit_tty).toInt(); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 130434f0c2..2a366705ab 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -3512,11 +3512,8 @@ void main_window::CreateDockWindows() m_mw->setContextMenuPolicy(Qt::PreventContextMenu); m_game_list_frame = new game_list_frame(m_gui_settings, m_emu_settings, m_persistent_settings, m_mw); - m_game_list_frame->setObjectName("gamelist"); m_debugger_frame = new debugger_frame(m_gui_settings, m_mw); - m_debugger_frame->setObjectName("debugger"); m_log_frame = new log_frame(m_gui_settings, m_mw); - m_log_frame->setObjectName("logger"); m_mw->addDockWidget(Qt::LeftDockWidgetArea, m_game_list_frame); m_mw->addDockWidget(Qt::LeftDockWidgetArea, m_log_frame); diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index f4fcee4985..7e7f115d22 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -1829,6 +1829,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std ui->enableGamemode->setVisible(false); #endif + m_emu_settings->EnhanceCheckBox(ui->playMusicDuringBoot, emu_settings_type::PlayMusicDuringBoot); + SubscribeTooltip(ui->playMusicDuringBoot, tooltips.settings.play_music_during_boot); + m_emu_settings->EnhanceCheckBox(ui->showShaderCompilationHint, emu_settings_type::ShowShaderCompilationHint); SubscribeTooltip(ui->showShaderCompilationHint, tooltips.settings.show_shader_compilation_hint); @@ -1847,6 +1850,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->showMouseAndKeyboardToggleHint, emu_settings_type::ShowMouseAndKeyboardToggleHint); SubscribeTooltip(ui->showMouseAndKeyboardToggleHint, tooltips.settings.show_mouse_and_keyboard_toggle_hint); + m_emu_settings->EnhanceCheckBox(ui->showFatalErrorHints, emu_settings_type::ShowFatalErrorHints); + SubscribeTooltip(ui->showFatalErrorHints, tooltips.settings.show_fatal_error_hints); + m_emu_settings->EnhanceCheckBox(ui->showCaptureHints, emu_settings_type::ShowCaptureHints); SubscribeTooltip(ui->showCaptureHints, tooltips.settings.show_capture_hints); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 282826fcd6..d3b98a2608 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -3009,6 +3009,13 @@ Overlay Settings + + + + Play music during boot sequence + + + @@ -3037,6 +3044,13 @@ + + + + Show fatal error hints + + + diff --git a/rpcs3/rpcs3qt/shortcut_utils.h b/rpcs3/rpcs3qt/shortcut_utils.h index d1ed3962e2..f41741ecdf 100644 --- a/rpcs3/rpcs3qt/shortcut_utils.h +++ b/rpcs3/rpcs3qt/shortcut_utils.h @@ -1,4 +1,5 @@ #pragma once +#include struct gui_game_info; class iso_archive; diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 0276ac0f82..caccc1c47b 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -154,10 +154,12 @@ public: const QString show_pressure_intensity_toggle_hint = tr("Shows pressure intensity toggle hint using the native overlay."); const QString show_analog_limiter_toggle_hint = tr("Shows analog limiter toggle hint using the native overlay."); const QString show_mouse_and_keyboard_toggle_hint = tr("Shows mouse and keyboard toggle hint using the native overlay."); + const QString show_fatal_error_hints = tr("Shows fatal error hints using the native overlay."); const QString show_capture_hints = tr("Shows screenshot and recording hints using the native overlay."); const QString use_native_interface = tr("Enables use of native HUD within the game window that can interact with game controllers.\nWhen disabled, regular Qt dialogs are used instead.\nCurrently, the on-screen keyboard only supports the English key layout."); const QString record_with_overlays = tr("Enables recording with overlays.\nThis also affects screenshots."); const QString pause_during_home_menu = tr("When enabled, opening the home menu will also pause emulation.\nWhile most games pause themselves while the home menu is shown, some do not.\nIn that case it can be helpful to pause the emulation whenever the home menu is open."); + const QString play_music_during_boot = tr("Play music during boot sequence if available."); const QString perf_overlay_enabled = tr("Enables or disables the performance overlay."); const QString perf_overlay_framerate_graph_enabled = tr("Enables or disables the framerate graph.");