Skip to content

Commit d476be4

Browse files
authored
Merge branch 'master' into build-llvm-8462cff
2 parents d2d8c4d + 3c747b3 commit d476be4

25 files changed

+614
-239
lines changed

BUILDING.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
88
### Windows 10 or later
99

1010
The following tools are required to build RPCS3 on Windows 10 or later:
11-
- [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
11+
- [Visual Studio 2022/2026](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
1212
- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
1313

1414
**NOTES:**
15-
- **Visual Studio 2022** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
15+
- **Visual Studio 2026** needs at least **CMake 4.2.0+**.
16+
- **Visual Studio 2022/2026** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
1617
See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution)
1718
on how to build the project with **Visual Studio**.
1819
- Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project

rpcs3/Emu/Cell/SPUCommonRecompiler.cpp

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -720,9 +720,19 @@ void spu_cache::initialize(bool build_existing_cache)
720720
}
721721

722722
// SPU cache file (version + block size type)
723-
const std::string loc = ppu_cache + "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat";
723+
const std::string filename = "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat";
724+
const std::string loc = ppu_cache + filename;
725+
const std::string loc_debug = fs::get_cache_dir() + "DEBUG/" + filename;
724726

725-
spu_cache cache(loc);
727+
bool is_debug = false;
728+
729+
if (fs::is_file(loc_debug))
730+
{
731+
spu_log.success("SPU Cache override applied!");
732+
is_debug = true;
733+
}
734+
735+
spu_cache cache(is_debug ? loc_debug : loc);
726736

727737
if (!cache)
728738
{
@@ -4963,6 +4973,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
49634973
u32 lsa_last_pc = SPU_LS_SIZE; // PC of first LSA write
49644974
u32 get_pc = SPU_LS_SIZE; // PC of GETLLAR
49654975
u32 put_pc = SPU_LS_SIZE; // PC of PUTLLC
4976+
u32 rdatomic_pc = SPU_LS_SIZE; // PC of last RdAtomcStat read
49664977
reg_state_t ls{}; // state of LS load/store address register
49674978
reg_state_t ls_offs = reg_state_t::from_value(0); // Added value to ls
49684979
reg_state_t lsa{}; // state of LSA register on GETLLAR
@@ -5008,7 +5019,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
50085019
ls_invalid = true;
50095020
ls_write |= write;
50105021

5011-
if (write)
5022+
if (ls_write)
50125023
{
50135024
return discard();
50145025
}
@@ -6323,6 +6334,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
63236334
break;
63246335
}
63256336

6337+
atomic16->rdatomic_pc = pos;
6338+
63266339
const auto it = atomic16_all.find(pos);
63276340

63286341
if (it == atomic16_all.end())
@@ -7263,7 +7276,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
72637276

72647277
for (const auto& [pc_commited, pattern] : atomic16_all)
72657278
{
7266-
if (!pattern.active)
7279+
if (!pattern.active || pattern.lsa_pc >= pattern.rdatomic_pc)
72677280
{
72687281
continue;
72697282
}
@@ -7273,6 +7286,17 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
72737286
continue;
72747287
}
72757288

7289+
std::string pattern_hash;
7290+
{
7291+
sha1_context ctx;
7292+
u8 output[20]{};
7293+
7294+
sha1_starts(&ctx);
7295+
sha1_update(&ctx, reinterpret_cast<const u8*>(result.data.data()) + (pattern.lsa_pc - result.lower_bound), pattern.rdatomic_pc - pattern.lsa_pc);
7296+
sha1_finish(&ctx, output);
7297+
fmt::append(pattern_hash, "%s", fmt::base57(output));
7298+
}
7299+
72767300
union putllc16_or_0_info
72777301
{
72787302
u64 data;
@@ -7295,8 +7319,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
72957319
value.required_pc = pattern.required_pc;
72967320
}
72977321

7298-
spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
7299-
add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa, value.data);
7322+
// spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
7323+
// add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa, value.data);
73007324
continue;
73017325
}
73027326

@@ -7363,16 +7387,35 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
73637387
value.reg2 = pattern.reg2;
73647388
}
73657389

7390+
bool allow_pattern = true;
7391+
73667392
if (g_cfg.core.spu_accurate_reservations)
73677393
{
7368-
// Because enabling it is a hack, as it turns out
7369-
// continue;
7394+
// The problem with PUTLLC16 optimization, that it is in theory correct at the bounds of the spu function.
7395+
// But if the SPU code reuses the cache line data observed, it is not truly atomic.
7396+
// So we may enable it only for known cases where SPU atomic data is not used after the function leaves.
7397+
7398+
// So the two options are:
7399+
7400+
// 1. Atomic compare exchange 16 bytes operation. (rest of data is not read) -> good for RPCS3 to optimize.
7401+
// 2. Fetch 128 bytes (read them later), modify only 16 bytes. -> Bad for RPCS3 to optimize.
7402+
7403+
// This difference cannot be known at analyzer time but from observing callers.
7404+
static constexpr std::initializer_list<std::string_view> allowed_patterns =
7405+
{
7406+
"620oYSe8uQqq9eTkhWfMqoEXX0us"sv, // CellSpurs JobChain acquire pattern
7407+
};
7408+
7409+
allow_pattern = std::any_of(allowed_patterns.begin(), allowed_patterns.end(), FN(pattern_hash == x));
73707410
}
73717411

7372-
add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
7412+
if (allow_pattern)
7413+
{
7414+
add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
7415+
}
73737416

7374-
spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s) (putllc0=%d, putllc16+0=%d, all=%d)"
7375-
, pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, +stats.nowrite, ++stats.single, +stats.all);
7417+
spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s, pattern-hash=%s) (putllc0=%d, putllc16+0=%d, all=%d)"
7418+
, pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, pattern_hash, +stats.nowrite, ++stats.single, +stats.all);
73767419
}
73777420

73787421
for (const auto& [read_pc, pattern] : rchcnt_loop_all)

rpcs3/Emu/RSX/RSXThread.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3073,7 +3073,7 @@ namespace rsx
30733073
{
30743074
capture_current_frame = false;
30753075

3076-
std::string file_path = fs::get_config_dir() + "captures/" + Emu.GetTitleID() + "_" + date_time::current_time_narrow() + "_capture.rrc.gz";
3076+
const std::string file_path = fs::get_config_dir() + "captures/" + (Emu.GetTitleID().empty() ? Emu.GetTitle() : Emu.GetTitleID()) + "_" + date_time::current_time_narrow() + "_capture.rrc.gz";
30773077

30783078
fs::pending_file temp(file_path);
30793079

rpcs3/Emu/System.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,19 @@ bool Emulator::BootRsxCapture(const std::string& path)
840840
return false;
841841
}
842842

843+
m_path.clear();
844+
m_path_old.clear();
845+
m_path_original.clear();
846+
m_title_id.clear();
847+
m_title.clear();
848+
m_localized_title.clear();
849+
m_app_version.clear();
850+
m_hash.clear();
851+
m_cat.clear();
852+
m_dir.clear();
853+
m_sfo_dir.clear();
854+
m_ar.reset();
855+
843856
Init();
844857
g_cfg.video.disable_on_disk_shader_cache.set(true);
845858

rpcs3/rpcs3qt/emu_settings.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -668,10 +668,9 @@ void emu_settings::EnhanceSpinBox(QSpinBox* spinbox, emu_settings_type type, con
668668
spinbox->setRange(min, max);
669669
spinbox->setValue(val);
670670

671-
connect(spinbox, &QSpinBox::textChanged, this, [type, spinbox, this](const QString& /* text*/)
671+
connect(spinbox, &QSpinBox::valueChanged, this, [type, this](int value)
672672
{
673-
if (!spinbox) return;
674-
SetSetting(type, spinbox->cleanText().toStdString());
673+
SetSetting(type, fmt::format("%d", value));
675674
});
676675

677676
connect(this, &emu_settings::RestoreDefaultsSignal, spinbox, [def, spinbox]()
@@ -724,10 +723,9 @@ void emu_settings::EnhanceDoubleSpinBox(QDoubleSpinBox* spinbox, emu_settings_ty
724723
spinbox->setRange(min, max);
725724
spinbox->setValue(val);
726725

727-
connect(spinbox, &QDoubleSpinBox::textChanged, this, [type, spinbox, this](const QString& /* text*/)
726+
connect(spinbox, &QDoubleSpinBox::valueChanged, this, [type, this](double value)
728727
{
729-
if (!spinbox) return;
730-
SetSetting(type, spinbox->cleanText().toStdString());
728+
SetSetting(type, fmt::format("%f", value));
731729
});
732730

733731
connect(this, &emu_settings::RestoreDefaultsSignal, spinbox, [def, spinbox]()

rpcs3/rpcs3qt/game_list.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ game_list::game_list() : QTableWidget(), game_list_base()
1414
};
1515
}
1616

17-
void game_list::sync_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility)
17+
void game_list::sync_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility)
1818
{
1919
ensure(get_visibility);
2020

2121
bool is_dirty = false;
2222

23-
for (int col = 0; col < actions.count(); ++col)
23+
for (auto& [col, action] : actions)
2424
{
2525
const bool is_hidden = !get_visibility(col);
26-
actions[col]->setChecked(!is_hidden);
26+
action->setChecked(!is_hidden);
2727

2828
if (isColumnHidden(col) != is_hidden)
2929
{
@@ -38,7 +38,7 @@ void game_list::sync_header_actions(QList<QAction*>& actions, std::function<bool
3838
}
3939
}
4040

41-
void game_list::create_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility)
41+
void game_list::create_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility)
4242
{
4343
ensure(get_visibility);
4444
ensure(set_visibility);
@@ -48,27 +48,30 @@ void game_list::create_header_actions(QList<QAction*>& actions, std::function<bo
4848
connect(horizontalHeader(), &QHeaderView::customContextMenuRequested, this, [this, &actions](const QPoint& pos)
4949
{
5050
QMenu* configure = new QMenu(this);
51-
configure->addActions(actions);
51+
for (auto& [col, action] : actions)
52+
{
53+
configure->addAction(action);
54+
}
5255
configure->exec(horizontalHeader()->viewport()->mapToGlobal(pos));
5356
});
5457

55-
for (int col = 0; col < actions.count(); ++col)
58+
for (auto& [col, action] : actions)
5659
{
57-
actions[col]->setCheckable(true);
60+
action->setCheckable(true);
5861

59-
connect(actions[col], &QAction::triggered, this, [this, &actions, get_visibility, set_visibility, col](bool checked)
62+
connect(action, &QAction::triggered, this, [this, &actions, get_visibility, set_visibility, col](bool checked)
6063
{
6164
if (!checked) // be sure to have at least one column left so you can call the context menu at all time
6265
{
6366
int c = 0;
64-
for (int i = 0; i < actions.count(); ++i)
67+
for (auto& [col, action] : actions)
6568
{
66-
if (get_visibility(i) && ++c > 1)
69+
if (get_visibility(col) && ++c > 1)
6770
break;
6871
}
6972
if (c < 2)
7073
{
71-
actions[col]->setChecked(true); // re-enable the checkbox if we don't change the actual state
74+
::at32(actions, col)->setChecked(true); // re-enable the checkbox if we don't change the actual state
7275
return;
7376
}
7477
}

rpcs3/rpcs3qt/game_list.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class game_list : public QTableWidget, public game_list_base
2323
public:
2424
game_list();
2525

26-
void sync_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility);
27-
void create_header_actions(QList<QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility);
26+
void sync_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility);
27+
void create_header_actions(std::map<int, QAction*>& actions, std::function<bool(int)> get_visibility, std::function<void(int, bool)> set_visibility);
2828

2929
void clear_list() override; // Use this instead of clearContents
3030

0 commit comments

Comments
 (0)