diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index a86c393f..08353fb3 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -59,6 +59,7 @@ endif() # SDL3 if (NOT TARGET SDL3::SDL3) + set(SDL_PIPEWIRE OFF) add_subdirectory(sdl3) endif() diff --git a/src/common/io_file.h b/src/common/io_file.h index 7cb3246c..2c3df3f6 100644 --- a/src/common/io_file.h +++ b/src/common/io_file.h @@ -205,9 +205,9 @@ public: return WriteSpan(string); } - static void WriteBytes(const std::filesystem::path path, std::span vec) { + static void WriteBytes(const std::filesystem::path path, std::span data) { IOFile out(path, FileAccessMode::Write); - out.Write(vec); + out.Write(data); } private: diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index e06a4b6e..5f462937 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -11,18 +11,12 @@ constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder) { std::scoped_lock lock{m_mutex}; - - MntPair pair; - pair.host_path = host_folder.string(); - std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/'); - pair.guest_path = guest_folder; - - m_mnt_pairs.push_back(pair); + m_mnt_pairs.emplace_back(host_folder, guest_folder); } void MntPoints::Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder) { auto it = std::remove_if(m_mnt_pairs.begin(), m_mnt_pairs.end(), - [&](const MntPair& pair) { return pair.guest_path == guest_folder; }); + [&](const MntPair& pair) { return pair.mount == guest_folder; }); m_mnt_pairs.erase(it, m_mnt_pairs.end()); } @@ -31,47 +25,79 @@ void MntPoints::UnmountAll() { m_mnt_pairs.clear(); } -std::string MntPoints::GetHostDirectory(const std::string& guest_directory) { - std::scoped_lock lock{m_mutex}; - for (auto& pair : m_mnt_pairs) { - // horrible code but it works :D - int find = guest_directory.find(pair.guest_path); - if (find == 0) { - std::string npath = - guest_directory.substr(pair.guest_path.size(), guest_directory.size() - 1); - std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/'); - return pair.host_path + npath; - } +std::filesystem::path MntPoints::GetHostPath(const std::string& guest_directory) { + const MntPair* mount = GetMount(guest_directory); + if (!mount) { + return guest_directory; } - return ""; -} -std::string MntPoints::GetHostFile(const std::string& guest_file) { - std::scoped_lock lock{m_mutex}; + // Nothing to do if getting the mount itself. + if (guest_directory == mount->mount) { + return mount->host_path; + } - for (auto& pair : m_mnt_pairs) { - // horrible code but it works :D - int find = guest_file.find(pair.guest_path); - if (find != 0) { - continue; - } - std::string npath = guest_file.substr(pair.guest_path.size(), guest_file.size() - 1); - const auto host_path = pair.host_path + npath; -#ifndef _WIN64 - const std::filesystem::path path{host_path}; - if (!std::filesystem::exists(path)) { - const auto filename = Common::ToLower(path.filename()); - for (const auto& file : std::filesystem::directory_iterator(path.parent_path())) { - const auto exist_filename = Common::ToLower(file.path().filename()); - if (filename == exist_filename) { - return file.path(); - } - } - } -#endif + // Remove device (e.g /app0) from path to retrieve relative path. + const u32 pos = mount->mount.size() + 1; + const auto rel_path = std::string_view(guest_directory).substr(pos); + const auto host_path = mount->host_path / rel_path; + if (!NeedsCaseInsensiveSearch) { return host_path; } - return ""; + + // If the path does not exist attempt to verify this. + // Retrieve parent path until we find one that exists. + path_parts.clear(); + auto current_path = host_path; + while (!std::filesystem::exists(current_path)) { + // We have probably cached this if it's a folder. + if (auto it = path_cache.find(current_path); it != path_cache.end()) { + current_path = it->second; + break; + } + path_parts.emplace_back(current_path.filename()); + current_path = current_path.parent_path(); + } + + // We have found an anchor. Traverse parts we recoded and see if they + // exist in filesystem but in different case. + auto guest_path = current_path; + while (!path_parts.empty()) { + const auto& part = path_parts.back(); + const auto add_match = [&](const auto& host_part) { + current_path += host_part; + guest_path += part; + path_cache[guest_path] = current_path; + path_parts.pop_back(); + }; + + // Can happen when the mismatch is in upper folder. + if (std::filesystem::exists(current_path / part)) { + add_match(part); + continue; + } + const auto part_low = Common::ToLower(part.string()); + bool found_match = false; + for (const auto& path : std::filesystem::directory_iterator(current_path)) { + const auto candidate = path.path().filename(); + const auto filename = Common::ToLower(candidate.string()); + // Check if a filename matches in case insensitive manner. + if (filename != part_low) { + continue; + } + // We found a match, record the actual path in the cache. + add_match(candidate); + found_match = true; + break; + } + if (!found_match) { + // Opening the guest path will surely fail but at least gives + // a better error message than the empty path. + return host_path; + } + } + + // The path was found. + return current_path; } int HandleTable::CreateHandle() { @@ -105,14 +131,9 @@ File* HandleTable::GetFile(int d) { return m_files.at(d - RESERVED_HANDLES); } -File* HandleTable::getFile(const std::string& host_name) { - std::scoped_lock lock{m_mutex}; - for (auto* file : m_files) { - if (file != nullptr && file->m_host_name == host_name) { - return file; - } - } - return nullptr; +File* HandleTable::GetFile(const std::filesystem::path& host_name) { + const auto it = std::ranges::find(m_files, host_name, &File::m_host_name); + return it == m_files.end() ? nullptr : *it; } } // namespace Core::FileSys diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index b31931d1..d636f8bf 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -7,28 +7,42 @@ #include #include #include +#include #include "common/io_file.h" namespace Core::FileSys { class MntPoints { +#ifdef _WIN64 + static constexpr bool NeedsCaseInsensiveSearch = false; +#else + static constexpr bool NeedsCaseInsensiveSearch = true; +#endif public: struct MntPair { - std::string host_path; - std::string guest_path; // e.g /app0/ + std::filesystem::path host_path; + std::string mount; // e.g /app0/ }; - MntPoints() = default; - virtual ~MntPoints() = default; + explicit MntPoints() = default; + ~MntPoints() = default; void Mount(const std::filesystem::path& host_folder, const std::string& guest_folder); void Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder); void UnmountAll(); - std::string GetHostDirectory(const std::string& guest_directory); - std::string GetHostFile(const std::string& guest_file); + + std::filesystem::path GetHostPath(const std::string& guest_directory); + + const MntPair* GetMount(const std::string& guest_path) { + const auto it = std::ranges::find_if( + m_mnt_pairs, [&](const auto& mount) { return guest_path.starts_with(mount.mount); }); + return it == m_mnt_pairs.end() ? nullptr : &*it; + } private: std::vector m_mnt_pairs; + std::vector path_parts; + tsl::robin_map path_cache; std::mutex m_mutex; }; @@ -40,7 +54,7 @@ struct DirEntry { struct File { std::atomic_bool is_opened{}; std::atomic_bool is_directory{}; - std::string m_host_name; + std::filesystem::path m_host_name; std::string m_guest_name; Common::FS::IOFile f; std::vector dirents; @@ -56,7 +70,7 @@ public: int CreateHandle(); void DeleteHandle(int d); File* GetFile(int d); - File* getFile(const std::string& host_name); + File* GetFile(const std::filesystem::path& host_name); private: std::vector m_files; diff --git a/src/core/libraries/kernel/event_queues.cpp b/src/core/libraries/kernel/event_queues.cpp index 12f59e50..bb3d8ba7 100644 --- a/src/core/libraries/kernel/event_queues.cpp +++ b/src/core/libraries/kernel/event_queues.cpp @@ -7,8 +7,6 @@ #include "core/libraries/error_codes.h" #include "core/libraries/kernel/event_queues.h" -#include - namespace Libraries::Kernel { extern boost::asio::io_context io_context; @@ -136,8 +134,7 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* event.timer = std::make_unique( io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs)); - event.timer->async_wait( - std::bind(SmallTimerCallback, boost::asio::placeholders::error, eq, event.event)); + event.timer->async_wait(std::bind(SmallTimerCallback, std::placeholders::_1, eq, event.event)); if (!eq->AddEvent(event)) { return ORBIS_KERNEL_ERROR_ENOMEM; diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index eb6248d0..23b949a8 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -13,7 +13,7 @@ namespace Libraries::Kernel { -std::vector GetDirectoryEntries(const std::string& path) { +std::vector GetDirectoryEntries(const std::filesystem::path& path) { std::vector files; for (const auto& entry : std::filesystem::directory_iterator(path)) { auto& dir_entry = files.emplace_back(); @@ -58,7 +58,7 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { if (directory) { file->is_directory = true; file->m_guest_name = path; - file->m_host_name = mnt->GetHostDirectory(file->m_guest_name); + file->m_host_name = mnt->GetHostPath(file->m_guest_name); if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist h->DeleteHandle(handle); return ORBIS_KERNEL_ERROR_ENOTDIR; @@ -72,7 +72,7 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { } } else { file->m_guest_name = path; - file->m_host_name = mnt->GetHostFile(file->m_guest_name); + file->m_host_name = mnt->GetHostPath(file->m_guest_name); int e = 0; if (read) { e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read); @@ -165,8 +165,7 @@ int PS4_SYSV_ABI sceKernelUnlink(const char* path) { auto* h = Common::Singleton::Instance(); auto* mnt = Common::Singleton::Instance(); - std::string host_path = mnt->GetHostFile(path); - + const auto host_path = mnt->GetHostPath(path); if (host_path.empty()) { return SCE_KERNEL_ERROR_EACCES; } @@ -175,7 +174,7 @@ int PS4_SYSV_ABI sceKernelUnlink(const char* path) { return SCE_KERNEL_ERROR_EPERM; } - auto* file = h->getFile(host_path); + auto* file = h->GetFile(host_path); if (file != nullptr) { file->f.Unlink(); } @@ -250,7 +249,7 @@ int PS4_SYSV_ABI sceKernelMkdir(const char* path, u16 mode) { return SCE_KERNEL_ERROR_EINVAL; } auto* mnt = Common::Singleton::Instance(); - std::string dir_name = mnt->GetHostFile(path); + const auto dir_name = mnt->GetHostPath(path); if (std::filesystem::exists(dir_name)) { return SCE_KERNEL_ERROR_EEXIST; } @@ -279,7 +278,7 @@ int PS4_SYSV_ABI posix_mkdir(const char* path, u16 mode) { int PS4_SYSV_ABI sceKernelStat(const char* path, OrbisKernelStat* sb) { LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path); auto* mnt = Common::Singleton::Instance(); - const auto& path_name = mnt->GetHostFile(path); + const auto path_name = mnt->GetHostPath(path); std::memset(sb, 0, sizeof(OrbisKernelStat)); const bool is_dir = std::filesystem::is_directory(path_name); const bool is_file = std::filesystem::is_regular_file(path_name); @@ -314,7 +313,7 @@ int PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) { int PS4_SYSV_ABI sceKernelCheckReachability(const char* path) { auto* mnt = Common::Singleton::Instance(); - std::string path_name = mnt->GetHostFile(path); + const auto path_name = mnt->GetHostPath(path); if (!std::filesystem::exists(path_name)) { return SCE_KERNEL_ERROR_ENOENT; } diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index 9f57ff53..c9073029 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -222,7 +222,7 @@ s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, size_t arg } auto* mnt = Common::Singleton::Instance(); - const auto path = mnt->GetHostFile(moduleFileName); + const auto path = mnt->GetHostPath(moduleFileName); // Load PRX module and relocate any modules that import it. auto* linker = Common::Singleton::Instance(); diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 0838a4d5..62282473 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -1006,17 +1006,7 @@ ScePthread PThreadPool::Create() { } } -#ifdef _WIN64 auto* ret = new PthreadInternal{}; -#else - // TODO: Linux specific hack - static u8* hint_address = reinterpret_cast(0x7FFFFC000ULL); - auto* ret = reinterpret_cast( - mmap(hint_address, sizeof(PthreadInternal), PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0)); - hint_address += Common::AlignUp(sizeof(PthreadInternal), 4_KB); -#endif - ret->is_free = false; ret->is_detached = false; ret->is_almost_done = false; diff --git a/src/core/libraries/libc/libc_stdio.cpp b/src/core/libraries/libc/libc_stdio.cpp index b1e94676..2b15bd36 100644 --- a/src/core/libraries/libc/libc_stdio.cpp +++ b/src/core/libraries/libc/libc_stdio.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/assert.h" +#include "common/logging/log.h" #include "common/singleton.h" #include "core/file_sys/fs.h" #include "core/libraries/libc/libc_stdio.h" @@ -10,11 +10,12 @@ namespace Libraries::LibC { std::FILE* PS4_SYSV_ABI ps4_fopen(const char* filename, const char* mode) { auto* mnt = Common::Singleton::Instance(); - FILE* f = std::fopen(mnt->GetHostFile(filename).c_str(), mode); + const auto host_path = mnt->GetHostPath(filename).string(); + FILE* f = std::fopen(host_path.c_str(), mode); if (f != nullptr) { - LOG_INFO(Lib_LibC, "fopen = {}", mnt->GetHostFile(filename).c_str()); + LOG_INFO(Lib_LibC, "fopen = {}", host_path); } else { - LOG_INFO(Lib_LibC, "fopen can't open = {}", mnt->GetHostFile(filename).c_str()); + LOG_INFO(Lib_LibC, "fopen can't open = {}", host_path); } return f; } diff --git a/src/core/libraries/save_data/savedata.cpp b/src/core/libraries/save_data/savedata.cpp index 7d12ed81..71828b33 100644 --- a/src/core/libraries/save_data/savedata.cpp +++ b/src/core/libraries/save_data/savedata.cpp @@ -15,7 +15,8 @@ #include "error_codes.h" namespace Libraries::SaveData { -static std::string g_mount_point = "/savedata0"; // temp mount point (todo) + +static constexpr std::string_view g_mount_point = "/savedata0"; // temp mount point (todo) std::string game_serial; int PS4_SYSV_ABI sceSaveDataAbort() { @@ -50,11 +51,11 @@ int PS4_SYSV_ABI sceSaveDataChangeInternal() { int PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check) { auto* mnt = Common::Singleton::Instance(); - std::string mount_dir = mnt->GetHostFile(check->dirName->data); + const auto mount_dir = mnt->GetHostPath(check->dirName->data); if (!std::filesystem::exists(mount_dir)) { return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; } - LOG_INFO(Lib_SaveData, "called = {}", mount_dir); + LOG_INFO(Lib_SaveData, "called = {}", mount_dir.string()); return ORBIS_OK; } @@ -317,14 +318,14 @@ int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam return false; } file.Seek(getParam->data->offset); - size_t nbytes = file.ReadRaw(getParam->data->buf, getParam->data->bufSize); + file.ReadRaw(getParam->data->buf, getParam->data->bufSize); LOG_INFO(Lib_SaveData, "called: bufSize = {}, offset = {}", getParam->data->bufSize, getParam->data->offset); } if (getParam->param != nullptr) { - Common::FS::IOFile file1(mount_dir / "param.txt", Common::FS::FileAccessMode::Read); - size_t nbytes = file1.ReadRaw(getParam->param, sizeof(OrbisSaveDataParam)); + Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Read); + file.ReadRaw(getParam->param, sizeof(OrbisSaveDataParam)); } return ORBIS_OK; @@ -394,13 +395,13 @@ int PS4_SYSV_ABI sceSaveDataIsMounted() { int PS4_SYSV_ABI sceSaveDataLoadIcon(const OrbisSaveDataMountPoint* mountPoint, OrbisSaveDataIcon* icon) { auto* mnt = Common::Singleton::Instance(); - std::string mount_dir = mnt->GetHostFile(mountPoint->data); - LOG_INFO(Lib_SaveData, "called: dir = {}", mount_dir); + const auto mount_dir = mnt->GetHostPath(mountPoint->data); + LOG_INFO(Lib_SaveData, "called: dir = {}", mount_dir.string()); if (icon != nullptr) { - Common::FS::IOFile file(mount_dir + "/save_data.png", Common::FS::FileAccessMode::Read); + Common::FS::IOFile file(mount_dir / "save_data.png", Common::FS::FileAccessMode::Read); icon->bufSize = file.GetSize(); - size_t nbytes = file.ReadRaw(icon->buf, icon->bufSize); + file.ReadRaw(icon->buf, icon->bufSize); } return ORBIS_OK; } @@ -409,6 +410,7 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode, OrbisSaveDataMountResult* mount_result) { const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / std::to_string(user_id) / game_serial / dir_name; + auto* mnt = Common::Singleton::Instance(); switch (mount_mode) { case ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY: case ORBIS_SAVE_DATA_MOUNT_MODE_RDWR: @@ -417,9 +419,8 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode, if (!std::filesystem::exists(mount_dir)) { return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; } - auto* mnt = Common::Singleton::Instance(); mount_result->mount_status = 0; - std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + g_mount_point.copy(mount_result->mount_point.data, 16); mnt->Mount(mount_dir, mount_result->mount_point.data); } break; case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE: @@ -431,16 +432,15 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode, ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF | ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: { - auto* mnt = Common::Singleton::Instance(); if (std::filesystem::exists(mount_dir)) { - std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + g_mount_point.copy(mount_result->mount_point.data, 16); mnt->Mount(mount_dir, mount_result->mount_point.data); mount_result->required_blocks = 0; mount_result->mount_status = 0; return ORBIS_SAVE_DATA_ERROR_EXISTS; } if (std::filesystem::create_directories(mount_dir)) { - std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + g_mount_point.copy(mount_result->mount_point.data, 16); mnt->Mount(mount_dir, mount_result->mount_point.data); mount_result->mount_status = 1; } @@ -451,8 +451,7 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode, if (!std::filesystem::exists(mount_dir)) { std::filesystem::create_directories(mount_dir); } - auto* mnt = Common::Singleton::Instance(); - std::strncpy(mount_result->mount_point.data, g_mount_point.c_str(), 16); + g_mount_point.copy(mount_result->mount_point.data, 16); mnt->Mount(mount_dir, mount_result->mount_point.data); mount_result->mount_status = 1; } break; @@ -534,12 +533,12 @@ int PS4_SYSV_ABI sceSaveDataRestoreLoadSaveDataMemory() { int PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint, const OrbisSaveDataIcon* icon) { auto* mnt = Common::Singleton::Instance(); - std::string mount_dir = mnt->GetHostFile(mountPoint->data); - LOG_INFO(Lib_SaveData, "called = {}", mount_dir); + const auto mount_dir = mnt->GetHostPath(mountPoint->data); + LOG_INFO(Lib_SaveData, "called = {}", mount_dir.string()); if (icon != nullptr) { - Common::FS::IOFile file(mount_dir + "/save_data.png", Common::FS::FileAccessMode::Write); - file.WriteRaw((void*)icon->buf, icon->bufSize); + Common::FS::IOFile file(mount_dir / "save_data.png", Common::FS::FileAccessMode::Write); + file.WriteRaw(icon->buf, icon->bufSize); } return ORBIS_OK; } @@ -558,12 +557,13 @@ int PS4_SYSV_ABI sceSaveDataSetParam(const OrbisSaveDataMountPoint* mountPoint, OrbisSaveDataParamType paramType, const void* paramBuf, size_t paramBufSize) { auto* mnt = Common::Singleton::Instance(); - std::string mount_dir = mnt->GetHostFile(mountPoint->data); - LOG_INFO(Lib_SaveData, "called = {}, mountPoint->data = {}", mount_dir, mountPoint->data); + const auto mount_dir = mnt->GetHostPath(mountPoint->data); + LOG_INFO(Lib_SaveData, "called = {}, mountPoint->data = {}", mount_dir.string(), + mountPoint->data); if (paramBuf != nullptr) { - Common::FS::IOFile file(mount_dir + "/param.txt", Common::FS::FileAccessMode::Write); - file.WriteRaw((void*)paramBuf, paramBufSize); + Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Write); + file.WriteRaw(paramBuf, paramBufSize); } return ORBIS_OK; } @@ -711,24 +711,23 @@ int PS4_SYSV_ABI sceSaveDataUmountSys() { int PS4_SYSV_ABI sceSaveDataUmountWithBackup(const OrbisSaveDataMountPoint* mountPoint) { LOG_ERROR(Lib_SaveData, "called = {}", std::string(mountPoint->data)); auto* mnt = Common::Singleton::Instance(); - std::string mount_dir = mnt->GetHostFile(mountPoint->data); + const auto mount_dir = mnt->GetHostPath(mountPoint->data); if (!std::filesystem::exists(mount_dir)) { return ORBIS_SAVE_DATA_ERROR_NOT_FOUND; - } else { - std::filesystem::path mnt_dir(mount_dir); - std::filesystem::create_directories(mnt_dir.parent_path() / "backup"); - - for (const auto& entry : std::filesystem::recursive_directory_iterator(mnt_dir)) { - const auto& path = entry.path(); - std::filesystem::path target_path = mnt_dir.parent_path() / "backup"; - - if (std::filesystem::is_regular_file(path)) { - std::filesystem::copy(path, target_path, - std::filesystem::copy_options::overwrite_existing); - } - } - mnt->Unmount(mount_dir, mountPoint->data); } + + std::filesystem::create_directories(mount_dir.parent_path() / "backup"); + + for (const auto& entry : std::filesystem::recursive_directory_iterator(mount_dir)) { + const auto& path = entry.path(); + const auto target_path = mount_dir.parent_path() / "backup"; + if (std::filesystem::is_regular_file(path)) { + std::filesystem::copy(path, target_path, + std::filesystem::copy_options::overwrite_existing); + } + } + + mnt->Unmount(mount_dir, mountPoint->data); return ORBIS_OK; } diff --git a/src/core/tls.cpp b/src/core/tls.cpp index 3f7bbceb..0c2d973b 100644 --- a/src/core/tls.cpp +++ b/src/core/tls.cpp @@ -9,7 +9,8 @@ #ifdef _WIN32 #include #else -#include +#include /* Definition of ARCH_* constants */ +#include /* Definition of SYS_* constants */ #endif namespace Core { @@ -89,47 +90,28 @@ static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGe #else -static pthread_key_t slot = 0; +static u32 slot = 0; void SetTcbBase(void* image_address) { - ASSERT(pthread_setspecific(slot, image_address) == 0); + asm volatile("wrgsbase %0" ::"r"(image_address) : "memory"); } Tcb* GetTcbBase() { - return reinterpret_cast(pthread_getspecific(slot)); + Tcb* tcb; + asm volatile("rdgsbase %0" : "=r"(tcb)::"memory"); + return tcb; } -static void AllocTcbKey() { - ASSERT(pthread_key_create(&slot, nullptr) == 0); -} +static void AllocTcbKey() {} static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGenerator& c) { using namespace Xbyak::util; const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size; - // Replace mov instruction with near jump to the trampoline. - static constexpr u32 NearJmpSize = 5; + // Replace fs read with gs read. auto patch = Xbyak::CodeGenerator(total_size, code); - patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR); - patch.nop(total_size - NearJmpSize); - - // Write the trampoline. - // The following logic is based on the glibc implementation of pthread_getspecific - // https://github.com/bminor/glibc/blob/29807a27/nptl/pthread_getspecific.c#L23 - static constexpr u32 PthreadKeySecondLevelSize = 32; - static constexpr u32 PthreadSpecificOffset = 0x510; - static constexpr u32 PthreadKeyDataSize = 16; - ASSERT(slot >= PthreadKeySecondLevelSize); - - const u32 idx1st = slot / PthreadKeySecondLevelSize; - const u32 idx2nd = slot % PthreadKeySecondLevelSize; const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); - c.mov(target_reg, PthreadSpecificOffset); - c.putSeg(fs); - c.mov(target_reg, qword[target_reg + idx1st * 8]); // Load first level specific array. - c.mov(target_reg, qword[target_reg + idx2nd * 16 + - 8]); // Load data member of pthread_key_data our slot specifies. - c.jmp(code + total_size); // Return to the instruction right after the mov. + patch.putSeg(gs); } #endif diff --git a/src/shader_recompiler/frontend/translate/export.cpp b/src/shader_recompiler/frontend/translate/export.cpp index cc631ff2..51840537 100644 --- a/src/shader_recompiler/frontend/translate/export.cpp +++ b/src/shader_recompiler/frontend/translate/export.cpp @@ -7,7 +7,7 @@ namespace Shader::Gcn { void Translator::EXP(const GcnInst& inst) { - if (ir.block->has_multiple_predecessors) { + if (ir.block->has_multiple_predecessors && info.stage == Stage::Fragment) { LOG_WARNING(Render_Recompiler, "An ambiguous export appeared in translation"); ir.Discard(ir.LogicalNot(ir.GetExec())); } diff --git a/src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp index 8a24a68b..6a43ad6b 100644 --- a/src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp +++ b/src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp @@ -173,7 +173,7 @@ public: } template - IR::Value ReadVariable(Type variable, IR::Block* root_block) { + IR::Value ReadVariable(Type variable, IR::Block* root_block, bool is_thread_bit = false) { boost::container::small_vector, 64> stack{ ReadState(nullptr), ReadState(root_block), @@ -201,7 +201,7 @@ public: } else if (!block->IsSsaSealed()) { // Incomplete CFG IR::Inst* phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; - phi->SetFlags(IR::TypeOf(UndefOpcode(variable))); + phi->SetFlags(is_thread_bit ? IR::Type::U1 : IR::TypeOf(UndefOpcode(variable))); incomplete_phis[block].insert_or_assign(variable, phi); stack.back().result = IR::Value{&*phi}; @@ -214,7 +214,7 @@ public: } else { // Break potential cycles with operandless phi IR::Inst* const phi{&*block->PrependNewInst(block->begin(), IR::Opcode::Phi)}; - phi->SetFlags(IR::TypeOf(UndefOpcode(variable))); + phi->SetFlags(is_thread_bit ? IR::Type::U1 : IR::TypeOf(UndefOpcode(variable))); WriteVariable(variable, block, IR::Value{phi}); @@ -263,7 +263,9 @@ private: template IR::Value AddPhiOperands(Type variable, IR::Inst& phi, IR::Block* block) { for (IR::Block* const imm_pred : block->ImmPredecessors()) { - phi.AddPhiOperand(imm_pred, ReadVariable(variable, imm_pred)); + const bool is_thread_bit = + std::is_same_v && phi.Flags() == IR::Type::U1; + phi.AddPhiOperand(imm_pred, ReadVariable(variable, imm_pred, is_thread_bit)); } return TryRemoveTrivialPhi(phi, block, UndefOpcode(variable)); } @@ -346,7 +348,8 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) { case IR::Opcode::GetThreadBitScalarReg: case IR::Opcode::GetScalarRegister: { const IR::ScalarReg reg{inst.Arg(0).ScalarReg()}; - inst.ReplaceUsesWith(pass.ReadVariable(reg, block)); + inst.ReplaceUsesWith( + pass.ReadVariable(reg, block, opcode == IR::Opcode::GetThreadBitScalarReg)); break; } case IR::Opcode::GetVectorRegister: { diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 6a4fcd70..84539c28 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -1033,7 +1033,7 @@ private: Vulkan::Rasterizer* rasterizer{}; std::jthread process_thread{}; - u32 num_submits{}; + std::atomic num_submits{}; std::mutex submit_mutex; std::condition_variable_any submit_cv; };