Merge branch 'master' into AVX10

This commit is contained in:
Elad 2025-03-22 10:44:44 +02:00 committed by GitHub
commit 55a918bdab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 163 additions and 128 deletions

View file

@ -62,7 +62,7 @@ namespace rsx
if (fs::exists(avatar_path))
{
icon_data = std::make_unique<image_info>(avatar_path.c_str());
icon_data = std::make_unique<image_info>(avatar_path);
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
}
else

View file

@ -31,7 +31,7 @@ namespace rsx
if (fs::exists(icon_path))
{
icon_data = std::make_unique<image_info>(icon_path.c_str(), details.hidden || locked);
icon_data = std::make_unique<image_info>(icon_path, details.hidden || locked);
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
}
else

View file

@ -12,7 +12,7 @@ namespace rsx
animated_icon::animated_icon(const char* icon_name)
{
const std::string image_path = fmt::format("%s/Icons/ui/%s", fs::get_config_dir(), icon_name);
m_icon = std::make_unique<image_info>(image_path.c_str());
m_icon = std::make_unique<image_info>(image_path);
set_raw_image(m_icon.get());
}

View file

@ -54,7 +54,7 @@ namespace rsx
return result;
}
image_info::image_info(const char* filename, bool grayscaled)
image_info::image_info(const std::string& filename, bool grayscaled)
{
fs::file f(filename, fs::read + fs::isfile);
@ -132,7 +132,7 @@ namespace rsx
{
// First check the global config dir
const std::string image_path = fs::get_config_dir() + "Icons/ui/" + res;
auto info = std::make_unique<image_info>(image_path.c_str());
auto info = std::make_unique<image_info>(image_path);
#if !defined(_WIN32) && !defined(__APPLE__) && defined(DATADIR)
// Check the DATADIR if defined
@ -140,7 +140,7 @@ namespace rsx
{
const std::string data_dir (DATADIR);
const std::string image_data = data_dir + "/Icons/ui/" + res;
info = std::make_unique<image_info>(image_data.c_str());
info = std::make_unique<image_info>(image_data);
}
#endif
@ -148,7 +148,7 @@ namespace rsx
{
// Resource was not found in the DATADIR or config dir, try and grab from relative path (linux)
std::string src = "Icons/ui/" + res;
info = std::make_unique<image_info>(src.c_str());
info = std::make_unique<image_info>(src);
#ifndef _WIN32
// Check for Icons in ../share/rpcs3 for AppImages,
// in rpcs3.app/Contents/Resources for App Bundles, and /usr/bin.
@ -188,12 +188,12 @@ namespace rsx
#else
src = executablePath + "/../share/rpcs3/Icons/ui/" + res;
#endif
info = std::make_unique<image_info>(src.c_str());
info = std::make_unique<image_info>(src);
// Check if the icons are in the same directory as the executable (local builds)
if (info->get_data() == nullptr)
{
src = executablePath + "/Icons/ui/" + res;
info = std::make_unique<image_info>(src.c_str());
info = std::make_unique<image_info>(src);
}
}
}

View file

@ -41,7 +41,7 @@ namespace rsx
int bpp = 0;
image_info(image_info&) = delete;
image_info(const char* filename, bool grayscaled = false);
image_info(const std::string& filename, bool grayscaled = false);
image_info(const std::vector<u8>& bytes, bool grayscaled = false);
~image_info();

View file

@ -58,7 +58,7 @@ namespace rsx
}
}
icon_data = std::make_unique<image_info>(entry.info.path.c_str());
icon_data = std::make_unique<image_info>(entry.info.path);
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
}
else

View file

@ -3,6 +3,7 @@
#include "overlay_message_dialog.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "Emu/system_utils.hpp"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/IdManager.h"
#include "Utilities/Thread.h"
@ -95,6 +96,11 @@ namespace rsx
if (background_image && background_image->get_data())
{
result.add(background_poster.get_compiled());
if (background_overlay_image && background_overlay_image->get_data())
{
result.add(background_overlay_poster.get_compiled());
}
}
result.add(background.get_compiled());
@ -356,10 +362,28 @@ namespace rsx
if (!background_image)
{
if (const auto picture_path = Emu.GetBackgroundPicturePath(); fs::exists(picture_path))
// Search for any useable background picture in the given order
game_content_type content_type = game_content_type::background_picture;
for (game_content_type type : { game_content_type::background_picture, game_content_type::overlay_picture, game_content_type::content_icon })
{
background_image = std::make_unique<image_info>(picture_path.c_str());
dirty |= !!background_image->get_data();
if (const std::string picture_path = rpcs3::utils::get_game_content_path(type); !picture_path.empty())
{
content_type = type;
background_image = std::make_unique<image_info>(picture_path);
dirty |= !!background_image->get_data();
break;
}
}
// Search for an overlay picture in the same dir in case we found a real background picture
if (background_image && !background_overlay_image && content_type == game_content_type::background_picture)
{
if (const std::string picture_path = rpcs3::utils::get_game_content_path(game_content_type::overlay_picture); !picture_path.empty())
{
background_overlay_image = std::make_unique<image_info>(picture_path);
dirty |= !!background_overlay_image->get_data();
}
}
}
@ -388,6 +412,23 @@ namespace rsx
const int padding = (background_poster.w - static_cast<int>(background_image->w * (background_poster.h / static_cast<double>(background_image->h)))) / 2;
background_poster.set_padding(padding, padding, 0, 0);
}
if (background_overlay_image && background_overlay_image->get_data())
{
constexpr f32 reference_factor = 2.0f / 3.0f;
const f32 image_aspect = background_overlay_image->w / static_cast<f32>(background_overlay_image->h);
const f32 overlay_width = background_overlay_image->w * reference_factor;
const f32 overlay_height = overlay_width / image_aspect;
const u16 overlay_x = static_cast<u16>(std::min(virtual_width - overlay_width, (virtual_width * reference_factor) - (overlay_width / 2.0f)));
const u16 overlay_y = static_cast<u16>(std::min(virtual_height - overlay_height, (virtual_height * reference_factor) - (overlay_height / 2.0f)));
const f32 color = (100 - background_darkening_strength) / 100.f;
background_overlay_poster.fore_color = color4f(color, color, color, 1.);
background_overlay_poster.set_size(static_cast<u16>(overlay_width), static_cast<u16>(overlay_height));
background_overlay_poster.set_pos(overlay_x, overlay_y);
background_overlay_poster.set_raw_image(background_overlay_image.get());
background_overlay_poster.set_blur_strength(static_cast<u8>(background_blur_strength));
}
}
}
else
@ -397,6 +438,13 @@ namespace rsx
background_poster.clear_image();
background_image.reset();
}
if (background_overlay_image)
{
background_overlay_poster.clear_image();
background_overlay_image.reset();
}
background.back_color.a = 0.85f;
}
}

View file

@ -16,8 +16,10 @@ namespace rsx
image_button btn_ok;
image_button btn_cancel;
overlay_element bottom_bar, background;
overlay_element bottom_bar;
overlay_element background;
image_view background_poster;
image_view background_overlay_poster;
std::array<progress_bar, 2> progress_bars{};
u8 num_progress_bars = 0;
s32 taskbar_index = 0;
@ -31,6 +33,7 @@ namespace rsx
u32 background_blur_strength = 0;
u32 background_darkening_strength = 0;
std::unique_ptr<image_info> background_image;
std::unique_ptr<image_info> background_overlay_image;
animation_color_interpolate fade_animation;

View file

@ -17,7 +17,7 @@ namespace rsx
if (fs::exists(avatar_path))
{
icon_data = std::make_unique<image_info>(avatar_path.c_str());
icon_data = std::make_unique<image_info>(avatar_path);
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
}
else

View file

@ -753,99 +753,6 @@ void Emulator::SetUsr(const std::string& user)
m_usr = user;
}
std::string Emulator::GetBackgroundPicturePath() const
{
// Try to find a custom icon first
std::string path = fs::get_config_dir() + "/Icons/game_icons/" + GetTitleID() + "/PIC1.PNG";
if (fs::is_file(path))
{
return path;
}
std::string disc_dir = vfs::get("/dev_bdvd/PS3_GAME");
if (m_sfo_dir == disc_dir)
{
disc_dir.clear();
}
constexpr auto search_barrier = "barrier";
const std::string locale_suffix = fmt::format("_%02d", static_cast<s32>(g_cfg.sys.language.get()));
std::initializer_list<std::string> testees =
{
m_sfo_dir + fmt::format("/PIC0%s.PNG", locale_suffix),
m_sfo_dir + fmt::format("/PIC1%s.PNG", locale_suffix),
m_sfo_dir + fmt::format("/PIC2%s.PNG", locale_suffix),
m_sfo_dir + fmt::format("/PIC3%s.PNG", locale_suffix),
search_barrier,
m_sfo_dir + "/PIC0.PNG",
m_sfo_dir + "/PIC1.PNG",
m_sfo_dir + "/PIC2.PNG",
m_sfo_dir + "/PIC3.PNG",
search_barrier,
!disc_dir.empty() ? (disc_dir + fmt::format("/PIC0%s.PNG", locale_suffix)) : disc_dir,
!disc_dir.empty() ? (disc_dir + fmt::format("/PIC1%s.PNG", locale_suffix)) : disc_dir,
!disc_dir.empty() ? (disc_dir + fmt::format("/PIC2%s.PNG", locale_suffix)) : disc_dir,
!disc_dir.empty() ? (disc_dir + fmt::format("/PIC3%s.PNG", locale_suffix)) : disc_dir,
search_barrier,
!disc_dir.empty() ? (disc_dir + "/PIC0.PNG") : disc_dir,
!disc_dir.empty() ? (disc_dir + "/PIC1.PNG") : disc_dir,
!disc_dir.empty() ? (disc_dir + "/PIC2.PNG") : disc_dir,
!disc_dir.empty() ? (disc_dir + "/PIC3.PNG") : disc_dir,
search_barrier,
m_sfo_dir + fmt::format("/ICON0%s.PNG", locale_suffix),
search_barrier,
m_sfo_dir + "/ICON0.PNG",
search_barrier,
!disc_dir.empty() ? (disc_dir + fmt::format("/ICON0%s.PNG", locale_suffix)) : disc_dir,
search_barrier,
!disc_dir.empty() ? (disc_dir + "/ICON0.PNG") : disc_dir,
};
// Try to return the picture with the highest resolution
// Be naive and assume that its the one that spans over the most bytes
usz max_file_size = 0;
usz index_of_largest_file = umax;
for (usz index = 0; index < testees.size(); index++)
{
const std::string& path = testees.begin()[index];
fs::stat_t file_stat{};
if (path == search_barrier)
{
if (index_of_largest_file != umax)
{
// Found a file in the preferred image group
break;
}
continue;
}
if (path.empty() || !fs::get_stat(path, file_stat) || file_stat.is_directory)
{
continue;
}
if (max_file_size < file_stat.size)
{
max_file_size = file_stat.size;
index_of_largest_file = index;
}
}
if (index_of_largest_file == umax)
{
return {};
}
return testees.begin()[index_of_largest_file];
}
bool Emulator::BootRsxCapture(const std::string& path)
{
if (m_state != system_state::stopped || m_restrict_emu_state_change)

View file

@ -338,8 +338,6 @@ public:
void SetUsr(const std::string& user);
std::string GetBackgroundPicturePath() const;
u64 GetPauseTime() const
{
return m_pause_amend_time;

View file

@ -4,6 +4,7 @@
#include "vfs_config.h"
#include "Emu/Io/pad_config.h"
#include "Emu/System.h"
#include "Emu/VFS.h"
#include "util/sysinfo.hpp"
#include "Utilities/File.h"
#include "Utilities/Thread.h"
@ -338,4 +339,83 @@ namespace rpcs3::utils
if (title_id.empty()) return "";
return get_input_config_dir(title_id) + g_cfg_input_configs.default_config + ".yml";
}
std::string get_game_content_path(game_content_type type)
{
const std::string locale_suffix = fmt::format("_%02d", static_cast<s32>(g_cfg.sys.language.get()));
const std::string disc_dir = vfs::get("/dev_bdvd/PS3_GAME");
std::string hdd0_dir = Emu.GetSfoDir(false);
if (hdd0_dir == disc_dir)
{
hdd0_dir.clear(); // No hdd0 dir
}
const bool check_disc = !disc_dir.empty();
const bool check_hdd0 = !hdd0_dir.empty() && !check_disc;
const auto find_content = [&](const std::string& name, const std::string& extension) -> std::string
{
// Check localized content first
for (bool localized : { true, false })
{
const std::string filename = fmt::format("/%s%s.%s", name, localized ? locale_suffix : std::string(), extension);
// Check content on hdd0 first
if (check_hdd0)
{
if (std::string path = hdd0_dir + filename; fs::is_file(path))
{
return path;
}
}
// Check content on disc
if (check_disc)
{
if (std::string path = disc_dir + filename; fs::is_file(path))
{
return path;
}
}
}
return {};
};
switch (type)
{
case game_content_type::content_icon:
{
return find_content("ICON0", "PNG");
}
case game_content_type::content_video:
{
return find_content("ICON1", "PAM");
}
case game_content_type::content_sound:
{
return find_content("SND0", "AT3");
}
case game_content_type::overlay_picture:
{
const bool high_res = g_cfg.video.aspect_ratio == video_aspect::_16_9;
return find_content(high_res ? "PIC0" : "PIC2", "PNG");
}
case game_content_type::background_picture:
case game_content_type::background_picture_2:
{
// Try to find a custom background first
if (std::string path = fs::get_config_dir() + "/Icons/game_icons/" + Emu.GetTitleID() + "/PIC1.PNG"; fs::is_file(path))
{
return path;
}
// Look for proper background
return find_content(type == game_content_type::background_picture ? "PIC1" : "PIC3", "PNG");
}
}
return {};
}
}

View file

@ -3,6 +3,16 @@
#include "util/types.hpp"
#include <string>
enum class game_content_type
{
content_icon, // ICON0.PNG
content_video, // ICON1.PAM
content_sound, // SND0.AT3
overlay_picture, // PIC0.PNG (16:9) or PIC2.PNG (4:3)
background_picture, // PIC1.PNG
background_picture_2, // PIC3.PNG (should only exist for install or extra content discs...)
};
namespace rpcs3::utils
{
u32 get_max_threads();
@ -30,4 +40,6 @@ namespace rpcs3::utils
std::string get_input_config_root();
std::string get_input_config_dir(const std::string& title_id = "");
std::string get_custom_input_config_path(const std::string& title_id);
std::string get_game_content_path(game_content_type type);
}

View file

@ -897,7 +897,8 @@ void game_list_frame::OnRefreshFinished()
}
}
if (!entry->has_custom_icon)
// Let's fetch the game data icon if the path was empty for some reason
if (entry->info.icon_path.empty())
{
if (std::string icon_path = other->info.path + "/" + localized_icon; fs::is_file(icon_path))
{
@ -908,20 +909,6 @@ void game_list_frame::OnRefreshFinished()
entry->info.icon_path = std::move(icon_path);
}
}
if (!entry->has_hover_gif)
{
if (std::string movie_path = other->info.path + "/" + localized_movie; fs::is_file(movie_path))
{
entry->info.movie_path = std::move(movie_path);
entry->has_hover_pam = true;
}
else if (std::string movie_path = other->info.path + "/ICON1.PAM"; fs::is_file(movie_path))
{
entry->info.movie_path = std::move(movie_path);
entry->has_hover_pam = true;
}
}
}
}

View file

@ -56,7 +56,7 @@ public:
const QString anti_cheat_savestates = tr("When this mode is on, emulation exits when saving and the savestate file is concealed after its load, preventing reuse by RPCS3.\nThis mode is like hibernation of emulation: if you don't want to be able to cheat using savestates when playing the game, consider using this mode.\nDo note that the savestate file is not gone completely, just ignored by RPCS3. You can manually relaunch it if needed.");
const QString compatible_savestates = tr("When this mode is on, SPU emulation prioritizes savestate compatibility, however, it may reduce performance slightly.\nWhen this mode is off, some games may not allow making a savestate and show an SPU pause error in the log.");
const QString paused_savestates = tr("When this mode is on, savestates are loaded and paused on the first frame.\nThis allows players to prepare for gameplay without being thrown into the action immediately.");
const QString spu_profiler = tr("When enabled, SPU performance is measured at runtime.\nEnable only at a developr's request because when enabled it reduces performance a bit by itself.");
const QString spu_profiler = tr("When enabled, SPU performance is measured at runtime.\nEnable only at a developer's request because when enabled it reduces performance a bit by itself.");
// audio
@ -166,7 +166,7 @@ public:
const QString perf_overlay_center_x = tr("Centers the performance overlay horizontally and overrides the horizontal margin.");
const QString perf_overlay_center_y = tr("Centers the performance overlay vertically and overrides the vertical margin.");
const QString shader_load_bg_enabled = tr("Shows a background image during the native shader loading dialog/loading screen.\nBy default the used image will be <gamedir>/PS3_GAME/PIC1.PNG or <gamedir>/PS3_GAME/PIC0.PNG.");
const QString shader_load_bg_enabled = tr("Shows a background image during the native shader loading dialog/loading screen.\nBy default the used image will be <gamedir>/PS3_GAME/PIC1.PNG.");
const QString shader_load_bg_darkening = tr("Changes the background image darkening effect strength of the native shader loading dialog.\nThis may be used to improve readability and/or aesthetics.");
const QString shader_load_bg_blur = tr("Changes the background image blur effect strength of the native shader loading dialog.\nThis may be used to improve readability and/or aesthetics.");