Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PPU Compilation: Search for more game data directories. #9685

Merged
merged 1 commit into from Jan 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 16 additions & 9 deletions rpcs3/Emu/Cell/PPUThread.cpp
Expand Up @@ -5,6 +5,7 @@
#include "Crypto/unself.h"
#include "Loader/ELF.h"
#include "Loader/mself.hpp"
#include "Loader/PSF.h"
#include "Emu/perf_meter.hpp"
#include "Emu/Memory/vm_reservation.h"
#include "Emu/Memory/vm_locking.h"
Expand Down Expand Up @@ -2069,7 +2070,13 @@ extern void ppu_finalize(const ppu_module& info)

extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<lv2_prx*>* loaded_prx)
{
// Remove duplicates
// Make sure we only have one '/' at the end and remove duplicates.
for (std::string& dir : dir_queue)
{
while (dir.back() == '/' || dir.back() == '\\')
dir.pop_back();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe try dir.erase(dir.begin() + (dir.find_last_not_of(fs::delim) +1), dir.end());

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't make much sense since we already manually add /

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its about not calling pop_back potentially many times.

Copy link
Contributor Author

@Megamouse Megamouse Jan 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do it twice for / and \.
But what's the big difference for a couple of dirs

dir += '/';
}
std::sort(dir_queue.begin(), dir_queue.end());
dir_queue.erase(std::unique(dir_queue.begin(), dir_queue.end()), dir_queue.end());

Expand Down Expand Up @@ -2230,6 +2237,9 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<lv2_

named_thread_group workers("SPRX Worker ", std::min<u32>(utils::get_thread_count(), ::size32(file_queue)), [&]
{
// Set low priority
thread_ctrl::scoped_priority low_prio(-1);

for (usz func_i = fnext++; func_i < file_queue.size(); func_i = fnext++, g_progr_fdone++)
{
if (Emu.IsStopped())
Expand Down Expand Up @@ -2265,7 +2275,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<lv2_
if (!src)
{
ppu_log.error("Failed to decrypt '%s'", path);
continue;
continue;
}

elf_error prx_err{}, ovl_err{};
Expand All @@ -2289,7 +2299,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<lv2_
// Log error
prx_err = elf_error::header_type;
}

if (const ppu_exec_object obj = src; (ovl_err = obj, obj == elf_error::ok))
{
while (ovl_err == elf_error::ok)
Expand Down Expand Up @@ -2392,12 +2402,9 @@ extern void ppu_initialize()
// Avoid compilation if main's cache exists or it is a standalone SELF with no PARAM.SFO
if (compile_main && !Emu.GetTitleID().empty())
{
dir_queue.emplace_back(vfs::get(Emu.GetDir()) + '/');

if (const std::string dev_bdvd = vfs::get("/dev_bdvd/PS3_GAME"); !dev_bdvd.empty())
{
dir_queue.emplace_back(dev_bdvd + '/');
}
// Try to add all related directories
const std::set<std::string> dirs = Emu.GetGameDirs();
dir_queue.insert(std::end(dir_queue), std::begin(dirs), std::end(dirs));
}

ppu_precompile(dir_queue, &prx_list);
Expand Down
50 changes: 50 additions & 0 deletions rpcs3/Emu/System.cpp
Expand Up @@ -1116,6 +1116,10 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
}
}

// Try to add all related directories
const std::set<std::string> dirs = GetGameDirs();
dir_queue.insert(std::end(dir_queue), std::begin(dirs), std::end(dirs));

if (std::string path = m_path + "/USRDIR/EBOOT.BIN"; fs::is_file(path))
{
// Compile EBOOT.BIN first
Expand Down Expand Up @@ -2048,4 +2052,50 @@ void Emulator::ConfigurePPUCache()
}
}

std::set<std::string> Emulator::GetGameDirs() const
{
std::set<std::string> dirs;

// Add boot directory.
// For installed titles and disc titles with updates this is usually /dev_hdd0/game/<title_id>/
// For disc titles without updates this is /dev_bdvd/PS3_GAME/
if (const std::string dir = vfs::get(GetDir()); !dir.empty())
{
dirs.insert(dir + '/');
}

// Add more paths for disc titles.
if (const std::string dev_bdvd = vfs::get("/dev_bdvd/PS3_GAME");
!dev_bdvd.empty() && !GetTitleID().empty())
{
// Add the dev_bdvd dir if available. This is necessary for disc titles with installed updates.
dirs.insert(dev_bdvd + '/');

// Naive search for all matching game data dirs.
const std::string game_dir = vfs::get("/dev_hdd0/game/");
for (auto&& entry : fs::dir(game_dir))
{
if (entry.is_directory && entry.name.starts_with(GetTitleID()))
{
const std::string sfo_dir = game_dir + entry.name + '/';
const fs::file sfo_file(sfo_dir + "PARAM.SFO");
if (!sfo_file)
{
continue;
}

const psf::registry psf = psf::load_object(sfo_file);
const std::string title_id = std::string(psf::get_string(psf, "TITLE_ID", ""));

if (title_id == GetTitleID())
{
dirs.insert(sfo_dir);
}
}
}
}

return dirs;
}

Emulator Emu;
3 changes: 3 additions & 0 deletions rpcs3/Emu/System.h
Expand Up @@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include <vector>
#include <set>

u64 get_system_time();
u64 get_guest_system_time();
Expand Down Expand Up @@ -242,6 +243,8 @@ class Emulator final
void ConfigureLogs();
void ConfigurePPUCache();

std::set<std::string> GetGameDirs() const;

private:
void LimitCacheSize();
};
Expand Down