Skip to content

Commit f39c4c3

Browse files
committed
overlays: parse big picture game entries multithreaded
1 parent 33af6e9 commit f39c4c3

6 files changed

Lines changed: 164 additions & 67 deletions

File tree

rpcs3/Emu/RSX/Overlays/BigPicture/overlay_big_picture_game_grid.cpp

Lines changed: 145 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
#include "overlay_big_picture_game_details.h"
44
#include "Emu/System.h"
55
#include "Emu/system_config.h"
6-
#include "Emu/system_utils.hpp"
7-
#include "Loader/PSF.h"
6+
#include "Utilities/Thread.h"
87

98
#include <algorithm>
109

@@ -51,12 +50,12 @@ namespace rsx
5150
: home_menu_page(x, y, width, height, false, parent, get_localized_string(localized_string_id::BIG_PICTURE_MENU_GAMES))
5251
, m_on_game_selected(std::move(on_game_selected))
5352
{
54-
m_no_games_text = std::make_unique<label>(get_localized_string(localized_string_id::BIG_PICTURE_NO_GAMES_FOUND));
55-
m_no_games_text->set_font("Arial", 20);
56-
m_no_games_text->set_pos(x, y + (height / 2) - 20);
57-
m_no_games_text->set_size(width, 40);
58-
m_no_games_text->align_text(text_align::center);
59-
m_no_games_text->back_color.a = 0.f;
53+
m_placeholder_text = std::make_unique<label>(get_localized_string(localized_string_id::BIG_PICTURE_LOADING));
54+
m_placeholder_text->set_font("Arial", 20);
55+
m_placeholder_text->set_pos(x, y + (height / 2) - 20);
56+
m_placeholder_text->set_size(width, 40);
57+
m_placeholder_text->align_text(text_align::center);
58+
m_placeholder_text->back_color.a = 0.f;
6059

6160
// Bezel around game cover art.
6261
m_highlight = std::make_unique<rounded_rect>();
@@ -78,15 +77,24 @@ namespace rsx
7877

7978
m_details = std::make_unique<big_picture_game_details>(x, y, width, height);
8079

81-
reload();
80+
start_reload();
8281
}
8382

84-
big_picture_game_grid::~big_picture_game_grid() = default;
83+
big_picture_game_grid::~big_picture_game_grid()
84+
{
85+
if (m_game_enumeration_thread)
86+
{
87+
*m_game_enumeration_thread = thread_state::aborting; // abort
88+
(*m_game_enumeration_thread)(); // wait
89+
m_game_enumeration_thread.reset(); // join
90+
}
91+
}
8592

86-
void big_picture_game_grid::reload()
93+
void big_picture_game_grid::start_reload()
8794
{
8895
rsx_log.notice("Big Picture Mode: reload() start");
8996

97+
m_loading = true;
9098
m_games.clear();
9199
m_tiles.clear();
92100

@@ -97,43 +105,100 @@ namespace rsx
97105
m_game_enumeration.set_prefer_game_data_icons(true);
98106
m_game_enumeration.set_play_hover_movies(true);
99107
m_game_enumeration.set_play_hover_music(true);
100-
m_game_enumeration.set_canceled_callback([](){ return Emu.IsStopped(); });
101-
102-
// Parse directories
103-
m_game_enumeration.parse_directories();
108+
m_game_enumeration.set_canceled_callback([](){ return thread_ctrl::state() == thread_state::aborting; });
104109

105-
// Add VFS entry
106-
m_game_enumeration.add_vfs_entry();
110+
m_game_enumeration_thread = std::make_unique<named_thread<std::function<void()>>>("BPM Reload", [this]()
111+
{
112+
// Parse directories
113+
m_game_enumeration.parse_directories();
107114

108-
// Remove duplicate entries
109-
m_game_enumeration.remove_duplicates();
115+
// Add VFS entry
116+
m_game_enumeration.add_vfs_entry();
110117

111-
// Parse entries
112-
for (const game_enumeration<big_picture_game_entry>::path_entry& entry : m_game_enumeration.path_entries())
113-
{
114-
m_game_enumeration.parse_entry(entry);
115-
}
118+
// Remove duplicate entries
119+
m_game_enumeration.remove_duplicates();
116120

117-
// Try to update the app version for disc games if there is a patch
118-
// Also try to find updated game icons and movies
119-
m_game_enumeration.apply_patches();
121+
// Parse entries (multithreaded)
122+
const std::vector<game_enumeration<big_picture_game_entry>::path_entry>& entries = m_game_enumeration.path_entries();
123+
const usz thread_count = std::min<usz>(utils::get_thread_count(), entries.size());
124+
if (thread_count > 1)
125+
{
126+
atomic_t<usz> entry_indexer = 0;
127+
const auto parse_entries = [this, &entry_indexer, &entries]()
128+
{
129+
while (thread_ctrl::state() != thread_state::aborting)
130+
{
131+
// Make sure entry_indexer does not exceed m_install_entries
132+
const usz index = entry_indexer.fetch_op([&entries](usz& v)
133+
{
134+
if (v < entries.size())
135+
{
136+
v++;
137+
return true;
138+
}
139+
140+
return false;
141+
}).first;
142+
143+
if (index >= entries.size())
144+
{
145+
break;
146+
}
147+
148+
m_game_enumeration.parse_entry(entries[index]);
149+
}
150+
};
151+
named_thread_group workers("BPM Parser "sv, ::narrow<u32>(thread_count) - 1, [&parse_entries]()
152+
{
153+
parse_entries();
154+
});
120155

121-
// Get final enumerated games
122-
for (big_picture_game_entry& game : m_game_enumeration.take_games())
123-
{
124-
if (!game.bootable) continue; // Let's restrict this to bootable entries
156+
parse_entries();
125157

126-
m_games.push_back(std::move(game));
127-
}
158+
workers.join();
159+
}
160+
else
161+
{
162+
for (const game_enumeration<big_picture_game_entry>::path_entry& entry : entries)
163+
{
164+
m_game_enumeration.parse_entry(entry);
165+
}
166+
}
128167

129-
// Reset enumeration
130-
m_game_enumeration.clear(true);
168+
// Try to update the app version for disc games if there is a patch
169+
// Also try to find updated game icons and movies
170+
m_game_enumeration.apply_patches();
131171

132-
// Sort by name
133-
std::sort(m_games.begin(), m_games.end(), [](const big_picture_game_entry& a, const big_picture_game_entry& b)
134-
{
135-
return a.name < b.name;
172+
// Get final enumerated games
173+
for (big_picture_game_entry& game : m_game_enumeration.take_games())
174+
{
175+
if (!game.bootable) continue; // Let's restrict this to bootable entries
176+
177+
m_games.push_back(std::move(game));
178+
}
179+
180+
// Reset enumeration
181+
m_game_enumeration.clear(true);
182+
183+
// Sort by name
184+
std::sort(m_games.begin(), m_games.end(), [](const big_picture_game_entry& a, const big_picture_game_entry& b)
185+
{
186+
return a.name < b.name;
187+
});
188+
189+
finish_reload();
136190
});
191+
}
192+
193+
void big_picture_game_grid::finish_reload()
194+
{
195+
std::lock_guard lock(m_reload_mutex);
196+
197+
if (thread_ctrl::state() == thread_state::aborting)
198+
{
199+
m_loading = false;
200+
return;
201+
}
137202

138203
m_grid = std::make_unique<vertical_layout>();
139204
m_grid->set_pos(x, y);
@@ -173,12 +238,19 @@ namespace rsx
173238

174239
m_selected_index = m_tiles.empty() ? 0 : std::clamp(m_selected_index, 0, static_cast<s32>(m_tiles.size()) - 1);
175240

176-
if (!m_tiles.empty())
241+
if (m_tiles.empty())
242+
{
243+
m_placeholder_text->set_text(get_localized_string(localized_string_id::BIG_PICTURE_NO_GAMES_FOUND));
244+
}
245+
else
177246
{
178247
select_tile(m_selected_index);
179248
}
180249

181250
rsx_log.notice("Big Picture Mode: reload() finished, games=%u, tiles=%u", m_games.size(), m_tiles.size());
251+
252+
m_loading = false;
253+
refresh();
182254
}
183255

184256
void big_picture_game_grid::select_tile(s32 index)
@@ -212,7 +284,7 @@ namespace rsx
212284
}
213285

214286
m_grid->scroll_offset_value = static_cast<u16>(std::clamp(offset, 0, max_offset));
215-
m_grid->refresh();
287+
m_grid->refresh();
216288
}
217289

218290
const big_picture_game_tile* tile = m_tiles[m_selected_index];
@@ -224,10 +296,14 @@ namespace rsx
224296
m_highlight->set_size(icon->w + bezel_margin * 2, icon->h + bezel_margin * 2);
225297
m_highlight->set_sinus_offset(1.6f);
226298
m_highlight->refresh();
299+
300+
refresh();
227301
}
228302

229303
page_navigation big_picture_game_grid::handle_button_press(pad_button button_press, bool is_auto_repeat, u64 auto_repeat_interval_ms)
230304
{
305+
if (m_loading) return page_navigation::stay;
306+
231307
const bool do_play_sound = !is_auto_repeat || auto_repeat_interval_ms >= user_interface::m_auto_repeat_ms_interval_default;
232308

233309
if (m_details && m_details->is_visible())
@@ -239,6 +315,7 @@ namespace rsx
239315
{
240316
case big_picture_game_details::result::back:
241317
m_details->hide();
318+
refresh();
242319
break;
243320
case big_picture_game_details::result::start:
244321
{
@@ -252,6 +329,7 @@ namespace rsx
252329
m_on_game_selected(info.path, info.serial);
253330
rsx_log.notice("Big Picture Mode: on_game_selected callback returned");
254331
}
332+
refresh();
255333
break;
256334
}
257335
default:
@@ -312,6 +390,7 @@ namespace rsx
312390
rsx_log.notice("Big Picture Mode: opening details for index=%d", m_selected_index);
313391
m_details->show(m_games[m_selected_index], m_tiles[m_selected_index]->get_icon_data());
314392
rsx_log.notice("Big Picture Mode: details shown");
393+
refresh();
315394
return page_navigation::stay;
316395
case pad_button::circle:
317396
play_sound(sound_effect::cancel);
@@ -335,36 +414,46 @@ namespace rsx
335414

336415
compiled_resource& big_picture_game_grid::get_compiled()
337416
{
338-
m_compiled_grid.clear();
417+
if (is_compiled())
418+
{
419+
return compiled_resources;
420+
}
421+
422+
m_is_compiled = true;
423+
compiled_resources.clear();
424+
425+
if (!visible)
426+
{
427+
return compiled_resources;
428+
}
429+
430+
std::lock_guard lock(m_reload_mutex);
339431

340432
if (m_tiles.empty())
341433
{
342-
m_compiled_grid.add(m_no_games_text->get_compiled());
434+
compiled_resources.add(m_placeholder_text->get_compiled());
343435
}
344436
else if (m_grid)
345437
{
346-
m_compiled_grid.add(m_grid->get_compiled());
347-
m_compiled_grid.add(m_highlight->get_compiled());
438+
compiled_resources.add(m_grid->get_compiled());
439+
compiled_resources.add(m_highlight->get_compiled());
348440
}
349441

350-
const bool details_visible = m_details && m_details->is_visible();
351-
352-
if (!details_visible)
442+
if (m_details && m_details->is_visible())
353443
{
354-
m_compiled_grid.add(m_back_hint.get_compiled());
444+
compiled_resources.add(m_details->get_compiled());
445+
}
446+
else
447+
{
448+
compiled_resources.add(m_back_hint.get_compiled());
355449

356450
if (!m_tiles.empty())
357451
{
358-
m_compiled_grid.add(m_select_hint.get_compiled());
452+
compiled_resources.add(m_select_hint.get_compiled());
359453
}
360454
}
361455

362-
if (m_details)
363-
{
364-
m_compiled_grid.add(m_details->get_compiled());
365-
}
366-
367-
return m_compiled_grid;
456+
return compiled_resources;
368457
}
369458
}
370459
}

rpcs3/Emu/RSX/Overlays/BigPicture/overlay_big_picture_game_grid.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,21 @@ namespace rsx
4646
compiled_resource& get_compiled() override;
4747

4848
private:
49-
void reload();
49+
void start_reload();
50+
void finish_reload();
5051
void select_tile(s32 index);
5152

5253
static constexpr u16 m_columns = 5;
5354
static constexpr u16 m_tile_size = 200;
5455

56+
std::mutex m_reload_mutex;
57+
std::unique_ptr<named_thread<std::function<void()>>> m_game_enumeration_thread;
58+
5559
game_enumeration<big_picture_game_entry> m_game_enumeration;
5660
std::vector<big_picture_game_entry> m_games;
5761
std::vector<big_picture_game_tile*> m_tiles; // non-owning, owned by m_grid
5862
std::unique_ptr<vertical_layout> m_grid;
59-
std::unique_ptr<label> m_no_games_text;
63+
std::unique_ptr<label> m_placeholder_text;
6064
std::unique_ptr<rounded_rect> m_highlight;
6165
std::unique_ptr<big_picture_game_details> m_details;
6266
std::function<void(std::string, std::string)> m_on_game_selected;
@@ -66,8 +70,9 @@ namespace rsx
6670

6771
s32 m_selected_index = 0;
6872
u16 m_row_stride = 0;
69-
u16 m_content_height = 0;
70-
compiled_resource m_compiled_grid;
73+
u16 m_content_height = 0;
74+
75+
atomic_t<bool> m_loading = true;
7176
};
7277
}
7378
}

rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_page.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ namespace rsx
6363
is_current_page = false;
6464
page->is_current_page = true;
6565
rsx_log.notice("Home menu: changing current page from '%s' to '%s'", title, page->title);
66+
refresh();
6667
}
6768
}
6869

rpcs3/Emu/RSX/Overlays/overlay_controls.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ namespace rsx
107107
{
108108
sdf_function func = sdf_function::none;
109109

110-
f32 cx; // Center x
111-
f32 cy; // Center y
112-
f32 hx; // Half-size in X
113-
f32 hy; // Half-size in Y
114-
f32 br; // Border radius
115-
f32 bw; // Border width
110+
f32 cx {}; // Center x
111+
f32 cy {}; // Center y
112+
f32 hx {}; // Half-size in X
113+
f32 hy {}; // Half-size in Y
114+
f32 br {}; // Border radius
115+
f32 bw {}; // Border width
116116

117117
color4f border_color;
118118

@@ -132,7 +132,7 @@ namespace rsx
132132
f32 pulse_sinus_offset = 0.0f; // The current pulse offset
133133
f32 pulse_speed_modifier = 0.005f;
134134

135-
sdf_config_t sdf_config;
135+
sdf_config_t sdf_config {};
136136

137137
areaf clip_rect = {};
138138
bool clip_region = false;

rpcs3/Emu/localized_string_id.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ enum class localized_string_id
353353
BIG_PICTURE_MENU_GAMES,
354354
BIG_PICTURE_MENU_EXIT,
355355
BIG_PICTURE_NO_GAMES_FOUND,
356+
BIG_PICTURE_LOADING,
356357
BIG_PICTURE_GAME_DETAILS_START,
357358
BIG_PICTURE_HINT_BACK,
358359
BIG_PICTURE_HINT_SELECT,

0 commit comments

Comments
 (0)