mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-06 06:51:26 +12:00
Merge branch 'master' into fix-fedora
This commit is contained in:
commit
5f67c6050d
23 changed files with 377 additions and 118 deletions
|
@ -40,19 +40,13 @@ bool cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
if (!_timeout)
|
|
||||||
{
|
|
||||||
verify(HERE), m_value--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
timespec timeout;
|
timespec timeout;
|
||||||
timeout.tv_sec = _timeout / 1000000;
|
timeout.tv_sec = _timeout / 1000000;
|
||||||
timeout.tv_nsec = (_timeout % 1000000) * 1000;
|
timeout.tv_nsec = (_timeout % 1000000) * 1000;
|
||||||
|
|
||||||
for (u32 value = _old + 1;; value = m_value)
|
for (u32 value = _old + 1;; value = m_value)
|
||||||
{
|
{
|
||||||
const int err = futex((int*)&m_value.raw(), FUTEX_WAIT_PRIVATE, value, is_inf ? nullptr : &timeout, nullptr, 0) == 0
|
const int err = futex(&m_value, FUTEX_WAIT_PRIVATE, value, is_inf ? nullptr : &timeout) == 0
|
||||||
? 0
|
? 0
|
||||||
: errno;
|
: errno;
|
||||||
|
|
||||||
|
@ -106,7 +100,7 @@ void cond_variable::imp_wake(u32 _count) noexcept
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const int res = futex((int*)&m_value.raw(), FUTEX_WAKE_PRIVATE, i > INT_MAX ? INT_MAX : i, nullptr, nullptr, 0))
|
if (const int res = futex(&m_value, FUTEX_WAKE_PRIVATE, i > INT_MAX ? INT_MAX : i))
|
||||||
{
|
{
|
||||||
verify(HERE), res >= 0 && (u32)res <= i;
|
verify(HERE), res >= 0 && (u32)res <= i;
|
||||||
i -= res;
|
i -= res;
|
||||||
|
@ -214,3 +208,88 @@ bool notifier::wait(u64 usec_timeout)
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cond_one::imp_wait(u32 _old, u64 _timeout) noexcept
|
||||||
|
{
|
||||||
|
verify(HERE), _old == c_lock;
|
||||||
|
|
||||||
|
const bool is_inf = _timeout > cond_variable::max_timeout;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
LARGE_INTEGER timeout;
|
||||||
|
timeout.QuadPart = _timeout * -10;
|
||||||
|
|
||||||
|
if (HRESULT rc = _timeout ? NtWaitForKeyedEvent(nullptr, &m_value, false, is_inf ? nullptr : &timeout) : WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
verify(HERE), rc == WAIT_TIMEOUT;
|
||||||
|
|
||||||
|
// Retire
|
||||||
|
const bool signaled = m_value.exchange(c_lock) == c_sig;
|
||||||
|
while (signaled)
|
||||||
|
{
|
||||||
|
timeout.QuadPart = 0;
|
||||||
|
|
||||||
|
if (HRESULT rc2 = NtWaitForKeyedEvent(nullptr, &m_value, false, &timeout))
|
||||||
|
{
|
||||||
|
verify(HERE), rc2 == WAIT_TIMEOUT;
|
||||||
|
SwitchToThread();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
timespec timeout;
|
||||||
|
timeout.tv_sec = _timeout / 1000000;
|
||||||
|
timeout.tv_nsec = (_timeout % 1000000) * 1000;
|
||||||
|
|
||||||
|
for (u32 value = _old - 1; value != c_sig; value = m_value)
|
||||||
|
{
|
||||||
|
const int err = futex(&m_value, FUTEX_WAIT_PRIVATE, value, is_inf ? nullptr : &timeout) == 0
|
||||||
|
? 0
|
||||||
|
: errno;
|
||||||
|
|
||||||
|
// Normal or timeout wakeup
|
||||||
|
if (!err || (!is_inf && err == ETIMEDOUT))
|
||||||
|
{
|
||||||
|
return m_value.exchange(c_lock) == c_sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a wakeup
|
||||||
|
verify(HERE), err == EAGAIN;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
verify(HERE), m_value.exchange(c_lock) == c_sig;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cond_one::imp_notify() noexcept
|
||||||
|
{
|
||||||
|
auto [old, ok] = m_value.fetch_op([](u32& v)
|
||||||
|
{
|
||||||
|
if (UNLIKELY(v > 0 && v < c_sig))
|
||||||
|
{
|
||||||
|
v = c_sig;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
verify(HERE), old <= c_sig;
|
||||||
|
|
||||||
|
if (LIKELY(!ok || old == c_lock))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
|
||||||
|
#else
|
||||||
|
futex(&m_value, FUTEX_WAKE_PRIVATE, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -127,3 +127,55 @@ public:
|
||||||
|
|
||||||
static constexpr u32 max_readers = 0x7f;
|
static constexpr u32 max_readers = 0x7f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class cond_one
|
||||||
|
{
|
||||||
|
enum : u32
|
||||||
|
{
|
||||||
|
c_wait = 1,
|
||||||
|
c_lock = 2,
|
||||||
|
c_sig = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
atomic_t<u32> m_value{0};
|
||||||
|
|
||||||
|
bool imp_wait(u32 _old, u64 _timeout) noexcept;
|
||||||
|
void imp_notify() noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr cond_one() = default;
|
||||||
|
|
||||||
|
void lock() noexcept
|
||||||
|
{
|
||||||
|
// Shouldn't be locked by more than one thread concurrently
|
||||||
|
while (UNLIKELY(!m_value.compare_and_swap_test(0, c_lock)))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() noexcept
|
||||||
|
{
|
||||||
|
m_value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wait(std::unique_lock<cond_one>& lock, u64 usec_timeout = -1) noexcept
|
||||||
|
{
|
||||||
|
AUDIT(lock.owns_lock());
|
||||||
|
AUDIT(lock.mutex() == this);
|
||||||
|
|
||||||
|
// State transition: c_sig -> c_lock, c_lock -> c_wait
|
||||||
|
const u32 _old = m_value.fetch_sub(1);
|
||||||
|
if (LIKELY(_old == c_sig))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return imp_wait(_old, usec_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notify() noexcept
|
||||||
|
{
|
||||||
|
// Early exit if notification is not required
|
||||||
|
if (LIKELY(!m_value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
imp_notify();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -66,7 +66,7 @@ void shared_mutex::imp_wait()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, value, nullptr, nullptr, c_sig);
|
futex(&m_value, FUTEX_WAIT_BITSET_PRIVATE, value, nullptr, c_sig);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,8 @@ void shared_mutex::imp_signal()
|
||||||
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
|
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
|
||||||
#else
|
#else
|
||||||
m_value += c_sig;
|
m_value += c_sig;
|
||||||
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig);
|
futex(&m_value, FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, c_sig);
|
||||||
//futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, c_one, nullptr, nullptr, c_sig - 1);
|
//futex(&m_value, FUTEX_WAKE_BITSET_PRIVATE, c_one, nullptr, c_sig - 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ void shared_mutex::imp_lock_unlock()
|
||||||
_max = val / c_one;
|
_max = val / c_one;
|
||||||
|
|
||||||
// Monitor all bits except c_sig
|
// Monitor all bits except c_sig
|
||||||
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, val, nullptr, nullptr, c_sig - 1);
|
futex(&m_value, FUTEX_WAIT_BITSET_PRIVATE, val, nullptr, c_sig - 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,11 @@ void semaphore_base::imp_wait()
|
||||||
if (value >= 0)
|
if (value >= 0)
|
||||||
{
|
{
|
||||||
// Signal other waiter to wake up or to restore sign bit
|
// Signal other waiter to wake up or to restore sign bit
|
||||||
futex(&m_value.raw(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
|
futex(&m_value, FUTEX_WAKE_PRIVATE, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
futex(&m_value.raw(), FUTEX_WAIT_PRIVATE, value, nullptr, nullptr, 0);
|
futex(&m_value, FUTEX_WAIT_PRIVATE, value);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ void semaphore_base::imp_post(s32 _old)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
|
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
|
||||||
#else
|
#else
|
||||||
futex(&m_value.raw(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
|
futex(&m_value, FUTEX_WAKE_PRIVATE, 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,24 +49,24 @@ enum
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int* uaddr2, int val3)
|
inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* timeout = nullptr, uint mask = 0)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3);
|
return syscall(SYS_futex, uaddr, futex_op, static_cast<int>(val), timeout, nullptr, static_cast<int>(mask));
|
||||||
#else
|
#else
|
||||||
static struct futex_map
|
static struct futex_manager
|
||||||
{
|
{
|
||||||
struct waiter
|
struct waiter
|
||||||
{
|
{
|
||||||
int val;
|
uint val;
|
||||||
uint mask;
|
uint mask;
|
||||||
std::condition_variable cv;
|
std::condition_variable cv;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::unordered_multimap<int*, waiter*, pointer_hash<int>> map;
|
std::unordered_multimap<volatile void*, waiter*, pointer_hash<volatile void, alignof(int)>> map;
|
||||||
|
|
||||||
int operator()(int* uaddr, int futex_op, int val, const timespec* timeout, int*, uint val3)
|
int operator()(volatile void* uaddr, int futex_op, uint val, const timespec* timeout, uint mask)
|
||||||
{
|
{
|
||||||
std::unique_lock lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
|
@ -74,12 +74,12 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int
|
||||||
{
|
{
|
||||||
case FUTEX_WAIT:
|
case FUTEX_WAIT:
|
||||||
{
|
{
|
||||||
val3 = -1;
|
mask = -1;
|
||||||
// Fallthrough
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case FUTEX_WAIT_BITSET:
|
case FUTEX_WAIT_BITSET:
|
||||||
{
|
{
|
||||||
if (*(volatile int*)uaddr != val)
|
if (*reinterpret_cast<volatile uint*>(uaddr) != val)
|
||||||
{
|
{
|
||||||
errno = EAGAIN;
|
errno = EAGAIN;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -87,7 +87,7 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int
|
||||||
|
|
||||||
waiter rec;
|
waiter rec;
|
||||||
rec.val = val;
|
rec.val = val;
|
||||||
rec.mask = val3;
|
rec.mask = mask;
|
||||||
const auto& ref = *map.emplace(uaddr, &rec);
|
const auto& ref = *map.emplace(uaddr, &rec);
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
@ -117,8 +117,8 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int
|
||||||
|
|
||||||
case FUTEX_WAKE:
|
case FUTEX_WAKE:
|
||||||
{
|
{
|
||||||
val3 = -1;
|
mask = -1;
|
||||||
// Fallthrough
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case FUTEX_WAKE_BITSET:
|
case FUTEX_WAKE_BITSET:
|
||||||
{
|
{
|
||||||
|
@ -128,7 +128,7 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int
|
||||||
{
|
{
|
||||||
auto& entry = *range.first->second;
|
auto& entry = *range.first->second;
|
||||||
|
|
||||||
if (entry.mask & val3)
|
if (entry.mask & mask)
|
||||||
{
|
{
|
||||||
entry.cv.notify_one();
|
entry.cv.notify_one();
|
||||||
entry.mask = 0;
|
entry.mask = 0;
|
||||||
|
@ -146,6 +146,6 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int
|
||||||
}
|
}
|
||||||
} g_futex;
|
} g_futex;
|
||||||
|
|
||||||
return g_futex(uaddr, futex_op, val, timeout, uaddr2, val3);
|
return g_futex(uaddr, futex_op, val, timeout, mask);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -641,15 +641,16 @@ error_code cellGameCreateGameData(vm::ptr<CellGameSetInitParams> init, vm::ptr<c
|
||||||
return CELL_GAME_ERROR_ACCESS_ERROR; // ???
|
return CELL_GAME_ERROR_ACCESS_ERROR; // ???
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cellGameContentPermit should then move files in non-temporary location and return their non-temporary displacement
|
||||||
|
if (tmp_contentInfoPath) strcpy_trunc(*tmp_contentInfoPath, tmp_contentInfo);
|
||||||
|
|
||||||
if (!fs::create_dir(vfs::get(tmp_usrdir)))
|
if (!fs::create_dir(vfs::get(tmp_usrdir)))
|
||||||
{
|
{
|
||||||
cellGame.error("cellGameCreateGameData(): failed to create directory '%s'", tmp_usrdir);
|
cellGame.error("cellGameCreateGameData(): failed to create directory '%s'", tmp_usrdir);
|
||||||
return CELL_GAME_ERROR_ACCESS_ERROR; // ???
|
return CELL_GAME_ERROR_ACCESS_ERROR; // ???
|
||||||
}
|
}
|
||||||
|
|
||||||
// cellGameContentPermit should then move files in non-temporary location and return their non-temporary displacement
|
if (tmp_usrdirPath) strcpy_trunc(*tmp_usrdirPath, tmp_usrdir);
|
||||||
strcpy_trunc(*tmp_contentInfoPath, tmp_contentInfo);
|
|
||||||
strcpy_trunc(*tmp_usrdirPath, tmp_usrdir);
|
|
||||||
|
|
||||||
prm->temp = vfs::get(tmp_contentInfo);
|
prm->temp = vfs::get(tmp_contentInfo);
|
||||||
cellGame.success("cellGameCreateGameData(): temporary directory '%s' has been created", tmp_contentInfo);
|
cellGame.success("cellGameCreateGameData(): temporary directory '%s' has been created", tmp_contentInfo);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "Emu/Memory/vm.h"
|
#include "Emu/Memory/vm.h"
|
||||||
#include "Emu/RSX/GSRender.h"
|
#include "Emu/RSX/GSRender.h"
|
||||||
|
#include "Emu/Cell/lv2/sys_ppu_thread.h"
|
||||||
#include "cellGcmSys.h"
|
#include "cellGcmSys.h"
|
||||||
#include "sysPrxForUser.h"
|
#include "sysPrxForUser.h"
|
||||||
|
|
||||||
|
@ -432,8 +433,9 @@ s32 _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> context, u32
|
||||||
|
|
||||||
vm::var<u64> _tid;
|
vm::var<u64> _tid;
|
||||||
vm::var<char[]> _name = vm::make_str("_gcm_intr_thread");
|
vm::var<char[]> _name = vm::make_str("_gcm_intr_thread");
|
||||||
ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 128, 0, 1, 0x4000, 0, +_name);
|
ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 128, 0, 1, 0x4000, SYS_PPU_THREAD_CREATE_INTERRUPT, +_name);
|
||||||
render->intr_thread = idm::get<named_thread<ppu_thread>>(*_tid);
|
render->intr_thread = idm::get<named_thread<ppu_thread>>(*_tid);
|
||||||
|
render->intr_thread->state -= cpu_flag::stop;
|
||||||
render->main_mem_addr = 0;
|
render->main_mem_addr = 0;
|
||||||
render->isHLE = true;
|
render->isHLE = true;
|
||||||
render->label_addr = m_config->gcm_info.label_addr;
|
render->label_addr = m_config->gcm_info.label_addr;
|
||||||
|
|
|
@ -467,10 +467,12 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
save_entry.dirName = dirName.get_ptr();
|
save_entry.dirName = dirName.get_ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string dir_path = base_dir + save_entry.dirName + "/";
|
const std::string dir_path = base_dir + save_entry.dirName + "/";
|
||||||
std::string sfo_path = dir_path + "PARAM.SFO";
|
const std::string old_path = base_dir + "../.backup_" + save_entry.dirName + "/";
|
||||||
|
const std::string new_path = base_dir + "../.working_" + save_entry.dirName + "/";
|
||||||
|
|
||||||
psf::registry psf = psf::load_object(fs::file(sfo_path));
|
psf::registry psf = psf::load_object(fs::file(dir_path + "PARAM.SFO"));
|
||||||
|
bool has_modified = false;
|
||||||
|
|
||||||
// Get save stats
|
// Get save stats
|
||||||
{
|
{
|
||||||
|
@ -598,6 +600,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
{ "SUB_TITLE", psf::string(128, statSet->setParam->subTitle) },
|
{ "SUB_TITLE", psf::string(128, statSet->setParam->subTitle) },
|
||||||
{ "TITLE", psf::string(128, statSet->setParam->title) },
|
{ "TITLE", psf::string(128, statSet->setParam->title) },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
has_modified = true;
|
||||||
}
|
}
|
||||||
//else if (psf.empty())
|
//else if (psf.empty())
|
||||||
//{
|
//{
|
||||||
|
@ -669,6 +673,17 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter the loop where the save files are read/created/deleted
|
// Enter the loop where the save files are read/created/deleted
|
||||||
|
std::map<std::string, fs::file> all_files;
|
||||||
|
|
||||||
|
// First, preload all files (TODO: beware of possible lag, although it should be insignificant)
|
||||||
|
for (auto&& entry : fs::dir(dir_path))
|
||||||
|
{
|
||||||
|
if (!entry.is_directory)
|
||||||
|
{
|
||||||
|
// Read file into a vector and make a memory file
|
||||||
|
all_files.emplace(std::move(entry.name), fs::make_stream(fs::file(dir_path + entry.name).to_vector<uchar>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fileGet->excSize = 0;
|
fileGet->excSize = 0;
|
||||||
memset(fileGet->reserved, 0, sizeof(fileGet->reserved));
|
memset(fileGet->reserved, 0, sizeof(fileGet->reserved));
|
||||||
|
@ -750,11 +765,14 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
|
|
||||||
psf.emplace("*" + file_path, fileSet->fileType == CELL_SAVEDATA_FILETYPE_SECUREFILE);
|
psf.emplace("*" + file_path, fileSet->fileType == CELL_SAVEDATA_FILETYPE_SECUREFILE);
|
||||||
|
|
||||||
|
const u32 access_size = std::min<u32>(fileSet->fileSize, fileSet->fileBufSize);
|
||||||
|
|
||||||
switch (const u32 op = fileSet->fileOperation)
|
switch (const u32 op = fileSet->fileOperation)
|
||||||
{
|
{
|
||||||
case CELL_SAVEDATA_FILEOP_READ:
|
case CELL_SAVEDATA_FILEOP_READ:
|
||||||
{
|
{
|
||||||
fs::file file(dir_path + file_path, fs::read);
|
fs::file& file = all_files[file_path];
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
// ****** sysutil savedata parameter error : 22 ******
|
// ****** sysutil savedata parameter error : 22 ******
|
||||||
|
@ -776,50 +794,55 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
return CELL_SAVEDATA_ERROR_PARAM;
|
return CELL_SAVEDATA_ERROR_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.seek(fileSet->fileOffset);
|
// Read from memory file to vm
|
||||||
std::vector<uchar> buf;
|
const u64 sr = file.seek(fileSet->fileOffset);
|
||||||
buf.resize(std::min<u32>(fileSet->fileSize, fileSet->fileBufSize));
|
const u64 rr = file.read(fileSet->fileBuf.get_ptr(), access_size);
|
||||||
buf.resize(file.read(buf.data(), buf.size()));
|
fileGet->excSize = ::narrow<u32>(rr);
|
||||||
std::memcpy(fileSet->fileBuf.get_ptr(), buf.data(), buf.size());
|
|
||||||
fileGet->excSize = ::size32(buf);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CELL_SAVEDATA_FILEOP_WRITE:
|
case CELL_SAVEDATA_FILEOP_WRITE:
|
||||||
{
|
{
|
||||||
fs::file file(dir_path + file_path, fs::write + fs::create);
|
fs::file& file = all_files[file_path];
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
fmt::throw_exception("Failed to open file. The file might be read-only: %s%s" HERE, dir_path, file_path);
|
file = fs::make_stream<std::vector<uchar>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
file.seek(fileSet->fileOffset);
|
// Write to memory file and truncate
|
||||||
const auto start = static_cast<uchar*>(fileSet->fileBuf.get_ptr());
|
const u64 sr = file.seek(fileSet->fileOffset);
|
||||||
std::vector<uchar> buf(start, start + std::min<u32>(fileSet->fileSize, fileSet->fileBufSize));
|
const u64 wr = file.write(fileSet->fileBuf.get_ptr(), access_size);
|
||||||
fileGet->excSize = ::narrow<u32>(file.write(buf.data(), buf.size()));
|
file.trunc(wr);
|
||||||
file.trunc(file.pos()); // truncate
|
fileGet->excSize = ::narrow<u32>(wr);
|
||||||
|
has_modified = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CELL_SAVEDATA_FILEOP_DELETE:
|
case CELL_SAVEDATA_FILEOP_DELETE:
|
||||||
{
|
{
|
||||||
fs::remove_file(dir_path + file_path);
|
// Delete memory file
|
||||||
|
all_files[file_path].close();
|
||||||
|
psf.erase("*" + file_path);
|
||||||
fileGet->excSize = 0;
|
fileGet->excSize = 0;
|
||||||
|
has_modified = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC:
|
case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC:
|
||||||
{
|
{
|
||||||
fs::file file(dir_path + file_path, fs::write + fs::create);
|
fs::file& file = all_files[file_path];
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
fmt::throw_exception("Failed to open file. The file might be read-only: %s%s" HERE, dir_path, file_path);
|
file = fs::make_stream<std::vector<uchar>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
file.seek(fileSet->fileOffset);
|
// Write to memory file normally
|
||||||
const auto start = static_cast<uchar*>(fileSet->fileBuf.get_ptr());
|
const u64 sr = file.seek(fileSet->fileOffset);
|
||||||
std::vector<uchar> buf(start, start + std::min<u32>(fileSet->fileSize, fileSet->fileBufSize));
|
const u64 wr = file.write(fileSet->fileBuf.get_ptr(), access_size);
|
||||||
fileGet->excSize = ::narrow<u32>(file.write(buf.data(), buf.size()));
|
fileGet->excSize = ::narrow<u32>(wr);
|
||||||
|
has_modified = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,10 +854,50 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write PARAM.SFO
|
// Write PARAM.SFO and savedata
|
||||||
if (psf.size())
|
if (!psf.empty() && has_modified)
|
||||||
{
|
{
|
||||||
psf::save_object(fs::file(sfo_path, fs::rewrite), psf);
|
// First, create temporary directory
|
||||||
|
if (fs::create_dir(new_path))
|
||||||
|
{
|
||||||
|
fs::remove_all(new_path, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fmt::throw_exception("Failed to create directory %s (%s)", new_path, fs::g_tls_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write all files in temporary directory
|
||||||
|
auto& fsfo = all_files["PARAM.SFO"];
|
||||||
|
fsfo = fs::make_stream<std::vector<uchar>>();
|
||||||
|
psf::save_object(fsfo, psf);
|
||||||
|
|
||||||
|
for (auto&& pair : all_files)
|
||||||
|
{
|
||||||
|
if (auto file = pair.second.release())
|
||||||
|
{
|
||||||
|
auto fvec = static_cast<fs::container_stream<std::vector<uchar>>&>(*file);
|
||||||
|
fs::file(new_path + pair.first, fs::rewrite).write(fvec.obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old backup
|
||||||
|
fs::remove_all(old_path, false);
|
||||||
|
|
||||||
|
// Backup old savedata
|
||||||
|
if (!fs::rename(dir_path, old_path, true))
|
||||||
|
{
|
||||||
|
fmt::throw_exception("Failed to move directory %s", dir_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit new savedata
|
||||||
|
if (!fs::rename(new_path, dir_path, false))
|
||||||
|
{
|
||||||
|
fmt::throw_exception("Failed to move directory %s", new_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove backup again (TODO: may be changed to persistent backup implementation)
|
||||||
|
fs::remove_all(old_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
|
|
@ -89,7 +89,7 @@ struct vdec_context final
|
||||||
|
|
||||||
atomic_t<u32> au_count{0};
|
atomic_t<u32> au_count{0};
|
||||||
|
|
||||||
notifier in_cv;
|
cond_one in_cv;
|
||||||
lf_queue<std::variant<vdec_start_seq_t, vdec_close_t, vdec_cmd, CellVdecFrameRate>> in_cmd;
|
lf_queue<std::variant<vdec_start_seq_t, vdec_close_t, vdec_cmd, CellVdecFrameRate>> in_cmd;
|
||||||
|
|
||||||
vdec_context(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
|
vdec_context(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
|
||||||
|
@ -160,13 +160,13 @@ struct vdec_context final
|
||||||
{
|
{
|
||||||
ppu_tid = ppu.id;
|
ppu_tid = ppu.id;
|
||||||
|
|
||||||
std::shared_lock no_lock(in_cv, std::try_to_lock);
|
std::unique_lock cv_lock(in_cv);
|
||||||
|
|
||||||
for (auto cmds = in_cmd.pop_all(); !Emu.IsStopped(); cmds ? cmds = cmds->pop_all() : cmds = in_cmd.pop_all())
|
for (auto cmds = in_cmd.pop_all(); !Emu.IsStopped(); cmds ? cmds = cmds->pop_all() : cmds = in_cmd.pop_all())
|
||||||
{
|
{
|
||||||
if (!cmds)
|
if (!cmds)
|
||||||
{
|
{
|
||||||
in_cv.wait(1000);
|
in_cv.wait(cv_lock, 1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +378,7 @@ struct vdec_context final
|
||||||
|
|
||||||
while (!Emu.IsStopped() && out_max && (std::lock_guard{mutex}, out.size() > out_max))
|
while (!Emu.IsStopped() && out_max && (std::lock_guard{mutex}, out.size() > out_max))
|
||||||
{
|
{
|
||||||
in_cv.wait(1000);
|
in_cv.wait(cv_lock, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (auto* frc = std::get_if<CellVdecFrameRate>(&cmds->get()))
|
else if (auto* frc = std::get_if<CellVdecFrameRate>(&cmds->get()))
|
||||||
|
@ -486,7 +486,7 @@ s32 cellVdecClose(ppu_thread& ppu, u32 handle)
|
||||||
lv2_obj::sleep(ppu);
|
lv2_obj::sleep(ppu);
|
||||||
vdec->out_max = 0;
|
vdec->out_max = 0;
|
||||||
vdec->in_cmd.push(vdec_close);
|
vdec->in_cmd.push(vdec_close);
|
||||||
vdec->in_cv.notify_all();
|
vdec->in_cv.notify();
|
||||||
ppu_execute<&sys_interrupt_thread_disestablish>(ppu, vdec->ppu_tid);
|
ppu_execute<&sys_interrupt_thread_disestablish>(ppu, vdec->ppu_tid);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -503,7 +503,7 @@ s32 cellVdecStartSeq(u32 handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
vdec->in_cmd.push(vdec_start_seq);
|
vdec->in_cmd.push(vdec_start_seq);
|
||||||
vdec->in_cv.notify_all();
|
vdec->in_cv.notify();
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,7 +519,7 @@ s32 cellVdecEndSeq(u32 handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
vdec->in_cmd.push(vdec_cmd{-1});
|
vdec->in_cmd.push(vdec_cmd{-1});
|
||||||
vdec->in_cv.notify_all();
|
vdec->in_cv.notify();
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,7 +541,7 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInf
|
||||||
|
|
||||||
// TODO: check info
|
// TODO: check info
|
||||||
vdec->in_cmd.push(vdec_cmd{mode, *auInfo});
|
vdec->in_cmd.push(vdec_cmd{mode, *auInfo});
|
||||||
vdec->in_cv.notify_all();
|
vdec->in_cv.notify();
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,7 +574,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify)
|
if (notify)
|
||||||
vdec->in_cv.notify_all();
|
vdec->in_cv.notify();
|
||||||
|
|
||||||
if (outBuff)
|
if (outBuff)
|
||||||
{
|
{
|
||||||
|
@ -878,7 +878,7 @@ s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
|
||||||
|
|
||||||
// TODO: check frc value
|
// TODO: check frc value
|
||||||
vdec->in_cmd.push(frc);
|
vdec->in_cmd.push(frc);
|
||||||
vdec->in_cv.notify_all();
|
vdec->in_cv.notify();
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -557,7 +557,7 @@ void ppu_thread::cpu_task()
|
||||||
}
|
}
|
||||||
case ppu_cmd::reset_stack:
|
case ppu_cmd::reset_stack:
|
||||||
{
|
{
|
||||||
cmd_pop(), gpr[1] = ::align(stack_addr + stack_size, 0x200) - 0x200;
|
cmd_pop(), gpr[1] = stack_addr + stack_size - 0x70;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -691,7 +691,7 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
|
||||||
, joiner(-!!detached)
|
, joiner(-!!detached)
|
||||||
, ppu_name(name)
|
, ppu_name(name)
|
||||||
{
|
{
|
||||||
gpr[1] = ::align(stack_addr + stack_size, 0x200) - 0x200;
|
gpr[1] = stack_addr + stack_size - 0x70;
|
||||||
|
|
||||||
gpr[13] = param.tls_addr;
|
gpr[13] = param.tls_addr;
|
||||||
|
|
||||||
|
|
|
@ -1580,12 +1580,26 @@ void spu_recompiler::STOP(spu_opcode_t op)
|
||||||
c->align(kAlignCode, 16);
|
c->align(kAlignCode, 16);
|
||||||
c->bind(ret);
|
c->bind(ret);
|
||||||
|
|
||||||
|
c->mov(SPU_OFF_32(pc), m_pos + 4);
|
||||||
|
|
||||||
if (g_cfg.core.spu_block_size == spu_block_size_type::safe)
|
if (g_cfg.core.spu_block_size == spu_block_size_type::safe)
|
||||||
{
|
{
|
||||||
c->mov(SPU_OFF_32(pc), m_pos + 4);
|
|
||||||
c->ret();
|
c->ret();
|
||||||
m_pos = -1;
|
m_pos = -1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Label label_next = c->newLabel();
|
||||||
|
Label label_check = c->newLabel();
|
||||||
|
c->cmp(SPU_OFF_32(state), 0);
|
||||||
|
c->jnz(label_check);
|
||||||
|
c->jmp(label_next);
|
||||||
|
c->bind(label_check);
|
||||||
|
c->lea(*ls, x86::qword_ptr(label_next));
|
||||||
|
c->jmp(imm_ptr(&check_state));
|
||||||
|
c->align(kAlignCode, 16);
|
||||||
|
c->bind(label_next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void spu_recompiler::LNOP(spu_opcode_t op)
|
void spu_recompiler::LNOP(spu_opcode_t op)
|
||||||
|
|
|
@ -117,7 +117,18 @@ void spu_interpreter::set_interrupt_status(spu_thread& spu, spu_opcode_t op)
|
||||||
|
|
||||||
bool spu_interpreter::STOP(spu_thread& spu, spu_opcode_t op)
|
bool spu_interpreter::STOP(spu_thread& spu, spu_opcode_t op)
|
||||||
{
|
{
|
||||||
return spu.stop_and_signal(op.opcode & 0x3fff);
|
if (!spu.stop_and_signal(op.opcode & 0x3fff))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spu.state)
|
||||||
|
{
|
||||||
|
spu.pc += 4;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spu_interpreter::LNOP(spu_thread& spu, spu_opcode_t op)
|
bool spu_interpreter::LNOP(spu_thread& spu, spu_opcode_t op)
|
||||||
|
|
|
@ -3056,6 +3056,10 @@ public:
|
||||||
m_ir->CreateStore(m_ir->getInt32(m_pos + 4), spu_ptr<u32>(&spu_thread::pc));
|
m_ir->CreateStore(m_ir->getInt32(m_pos + 4), spu_ptr<u32>(&spu_thread::pc));
|
||||||
m_ir->CreateRetVoid();
|
m_ir->CreateRetVoid();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
check_state(m_pos + 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void STOPD(spu_opcode_t op) //
|
void STOPD(spu_opcode_t op) //
|
||||||
|
|
|
@ -509,7 +509,10 @@ void spu_thread::cpu_task()
|
||||||
}
|
}
|
||||||
|
|
||||||
// save next PC and current SPU Interrupt status
|
// save next PC and current SPU Interrupt status
|
||||||
|
if (!group && offset >= RAW_SPU_BASE_ADDR)
|
||||||
|
{
|
||||||
npc = pc | (interrupts_enabled);
|
npc = pc | (interrupts_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
// Print some stats
|
// Print some stats
|
||||||
LOG_NOTICE(SPU, "Stats: Block Weight: %u (Retreats: %u);", block_counter, block_failure);
|
LOG_NOTICE(SPU, "Stats: Block Weight: %u (Retreats: %u);", block_counter, block_failure);
|
||||||
|
@ -595,8 +598,11 @@ void spu_thread::cpu_task()
|
||||||
}
|
}
|
||||||
|
|
||||||
// save next PC and current SPU Interrupt status
|
// save next PC and current SPU Interrupt status
|
||||||
|
if (!group && offset >= RAW_SPU_BASE_ADDR)
|
||||||
|
{
|
||||||
npc = pc | (interrupts_enabled);
|
npc = pc | (interrupts_enabled);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void spu_thread::cpu_mem()
|
void spu_thread::cpu_mem()
|
||||||
{
|
{
|
||||||
|
@ -2060,7 +2066,7 @@ bool spu_thread::stop_and_signal(u32 code)
|
||||||
|
|
||||||
int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT);
|
int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT);
|
||||||
state += cpu_flag::stop;
|
state += cpu_flag::stop;
|
||||||
return true; // ???
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (code)
|
switch (code)
|
||||||
|
|
|
@ -1789,20 +1789,22 @@ namespace rsx
|
||||||
{
|
{
|
||||||
auto &vinfo = state.vertex_arrays_info[index];
|
auto &vinfo = state.vertex_arrays_info[index];
|
||||||
|
|
||||||
|
if (vinfo.size() > 0)
|
||||||
|
{
|
||||||
|
// Attribute stride must be updated even if the stream is disabled
|
||||||
|
info.attribute_stride += rsx::get_vertex_type_size_on_host(vinfo.type(), vinfo.size());
|
||||||
|
|
||||||
if (input_mask & (1u << index))
|
if (input_mask & (1u << index))
|
||||||
{
|
{
|
||||||
result.attribute_placement[index] = attribute_buffer_placement::transient;
|
result.attribute_placement[index] = attribute_buffer_placement::transient;
|
||||||
}
|
|
||||||
|
|
||||||
if (vinfo.size() > 0)
|
|
||||||
{
|
|
||||||
info.locations.push_back(index);
|
info.locations.push_back(index);
|
||||||
info.attribute_stride += rsx::get_vertex_type_size_on_host(vinfo.type(), vinfo.size());
|
|
||||||
}
|
}
|
||||||
else if (state.register_vertex_info[index].size > 0)
|
}
|
||||||
|
else if (state.register_vertex_info[index].size > 0 && input_mask & (1u << index))
|
||||||
{
|
{
|
||||||
//Reads from register
|
//Reads from register
|
||||||
result.referenced_registers.push_back(index);
|
result.referenced_registers.push_back(index);
|
||||||
|
result.attribute_placement[index] = attribute_buffer_placement::transient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2847,13 +2849,7 @@ namespace rsx
|
||||||
|
|
||||||
void thread::handle_emu_flip(u32 buffer)
|
void thread::handle_emu_flip(u32 buffer)
|
||||||
{
|
{
|
||||||
if (user_asked_for_frame_capture && !g_cfg.video.strict_rendering_mode)
|
if (user_asked_for_frame_capture && !capture_current_frame)
|
||||||
{
|
|
||||||
// not dealing with non-strict rendering capture for now
|
|
||||||
user_asked_for_frame_capture = false;
|
|
||||||
LOG_FATAL(RSX, "RSX Capture: Capture only supported when ran with strict rendering mode.");
|
|
||||||
}
|
|
||||||
else if (user_asked_for_frame_capture && !capture_current_frame)
|
|
||||||
{
|
{
|
||||||
capture_current_frame = true;
|
capture_current_frame = true;
|
||||||
user_asked_for_frame_capture = false;
|
user_asked_for_frame_capture = false;
|
||||||
|
@ -2874,10 +2870,10 @@ namespace rsx
|
||||||
capture_current_frame = false;
|
capture_current_frame = false;
|
||||||
std::stringstream os;
|
std::stringstream os;
|
||||||
cereal::BinaryOutputArchive archive(os);
|
cereal::BinaryOutputArchive archive(os);
|
||||||
const std::string& filePath = fs::get_config_dir() + "capture.rrc";
|
const std::string& filePath = fs::get_config_dir() + "captures/" + Emu.GetTitleID() + "_" + date_time::current_time_narrow() + "_capture.rrc";
|
||||||
archive(frame_capture);
|
archive(frame_capture);
|
||||||
{
|
{
|
||||||
// todo: 'dynamicly' create capture filename, also may want to compress this data?
|
// todo: may want to compress this data?
|
||||||
fs::file f(filePath, fs::rewrite);
|
fs::file f(filePath, fs::rewrite);
|
||||||
f.write(os.str());
|
f.write(os.str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1037,15 +1037,15 @@ enum Method
|
||||||
|
|
||||||
RSX_METHOD_INCREMENT_CMD_MASK = 0xe0030003,
|
RSX_METHOD_INCREMENT_CMD_MASK = 0xe0030003,
|
||||||
RSX_METHOD_INCREMENT_CMD = 0,
|
RSX_METHOD_INCREMENT_CMD = 0,
|
||||||
RSX_METHOD_INCREMENT_COUNT_MASK = 0x0ffc0000,
|
RSX_METHOD_INCREMENT_COUNT_MASK = 0x1ffc0000,
|
||||||
RSX_METHOD_INCREMENT_COUNT_SHIFT = 18,
|
RSX_METHOD_INCREMENT_COUNT_SHIFT = 18,
|
||||||
RSX_METHOD_INCREMENT_METHOD_MASK = 0x00001ffc,
|
RSX_METHOD_INCREMENT_METHOD_MASK = 0x0000fffc,
|
||||||
|
|
||||||
RSX_METHOD_NON_INCREMENT_CMD_MASK = 0xe0030003,
|
RSX_METHOD_NON_INCREMENT_CMD_MASK = 0xe0030003,
|
||||||
RSX_METHOD_NON_INCREMENT_CMD = 0x40000000,
|
RSX_METHOD_NON_INCREMENT_CMD = 0x40000000,
|
||||||
RSX_METHOD_NON_INCREMENT_COUNT_MASK = 0x0ffc0000,
|
RSX_METHOD_NON_INCREMENT_COUNT_MASK = 0x1ffc0000,
|
||||||
RSX_METHOD_NON_INCREMENT_COUNT_SHIFT = 18,
|
RSX_METHOD_NON_INCREMENT_COUNT_SHIFT = 18,
|
||||||
RSX_METHOD_NON_INCREMENT_METHOD_MASK = 0x00001ffc,
|
RSX_METHOD_NON_INCREMENT_METHOD_MASK = 0x0000fffc,
|
||||||
|
|
||||||
RSX_METHOD_NEW_JUMP_CMD_MASK = 0x00000003,
|
RSX_METHOD_NEW_JUMP_CMD_MASK = 0x00000003,
|
||||||
RSX_METHOD_NEW_JUMP_CMD = 0x00000001,
|
RSX_METHOD_NEW_JUMP_CMD = 0x00000001,
|
||||||
|
@ -1055,6 +1055,7 @@ enum Method
|
||||||
RSX_METHOD_CALL_CMD = 0x00000002,
|
RSX_METHOD_CALL_CMD = 0x00000002,
|
||||||
RSX_METHOD_CALL_OFFSET_MASK = 0xfffffffc,
|
RSX_METHOD_CALL_OFFSET_MASK = 0xfffffffc,
|
||||||
|
|
||||||
|
RSX_METHOD_NON_METHOD_CMD_MASK = 0xa0030003,
|
||||||
RSX_METHOD_RETURN_CMD = 0x00020000,
|
RSX_METHOD_RETURN_CMD = 0x00020000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -290,12 +290,14 @@ void Emulator::Init()
|
||||||
// Reload global configuration
|
// Reload global configuration
|
||||||
g_cfg.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string());
|
g_cfg.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string());
|
||||||
|
|
||||||
// Create directories
|
// Create directories (can be disabled if necessary)
|
||||||
const std::string emu_dir = GetEmuDir();
|
const std::string emu_dir = GetEmuDir();
|
||||||
const std::string dev_hdd0 = GetHddDir();
|
const std::string dev_hdd0 = GetHddDir();
|
||||||
const std::string dev_hdd1 = fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir);
|
const std::string dev_hdd1 = fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir);
|
||||||
const std::string dev_usb = fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir);
|
const std::string dev_usb = fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir);
|
||||||
|
|
||||||
|
if (g_cfg.vfs.init_dirs)
|
||||||
|
{
|
||||||
fs::create_path(dev_hdd0);
|
fs::create_path(dev_hdd0);
|
||||||
fs::create_path(dev_hdd1);
|
fs::create_path(dev_hdd1);
|
||||||
fs::create_path(dev_usb);
|
fs::create_path(dev_usb);
|
||||||
|
@ -314,6 +316,7 @@ void Emulator::Init()
|
||||||
fs::create_dir(dev_hdd0 + "savedata/vmc/");
|
fs::create_dir(dev_hdd0 + "savedata/vmc/");
|
||||||
fs::create_dir(dev_hdd1 + "cache/");
|
fs::create_dir(dev_hdd1 + "cache/");
|
||||||
fs::create_dir(dev_hdd1 + "game/");
|
fs::create_dir(dev_hdd1 + "game/");
|
||||||
|
}
|
||||||
|
|
||||||
fs::create_path(fs::get_config_dir() + "shaderlog/");
|
fs::create_path(fs::get_config_dir() + "shaderlog/");
|
||||||
fs::create_path(fs::get_config_dir() + "captures/");
|
fs::create_path(fs::get_config_dir() + "captures/");
|
||||||
|
|
|
@ -394,6 +394,7 @@ struct cfg_root : cfg::node
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::_bool host_root{this, "Enable /host_root/"};
|
cfg::_bool host_root{this, "Enable /host_root/"};
|
||||||
|
cfg::_bool init_dirs{this, "Initialize Directories", true};
|
||||||
|
|
||||||
} vfs{this};
|
} vfs{this};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "TRP.h"
|
#include "TRP.h"
|
||||||
#include "Crypto/sha1.h"
|
#include "Crypto/sha1.h"
|
||||||
|
#include "Utilities/StrUtil.h"
|
||||||
|
|
||||||
TRPLoader::TRPLoader(const fs::file& f)
|
TRPLoader::TRPLoader(const fs::file& f)
|
||||||
: trp_f(f)
|
: trp_f(f)
|
||||||
|
@ -141,11 +142,11 @@ void TRPLoader::RemoveEntry(const char *filename)
|
||||||
|
|
||||||
void TRPLoader::RenameEntry(const char *oldname, const char *newname)
|
void TRPLoader::RenameEntry(const char *oldname, const char *newname)
|
||||||
{
|
{
|
||||||
for (const TRPEntry& entry : m_entries)
|
for (TRPEntry& entry : m_entries)
|
||||||
{
|
{
|
||||||
if (!strcmp(entry.name, oldname))
|
if (!strcmp(entry.name, oldname))
|
||||||
{
|
{
|
||||||
memcpy((void*)entry.name, newname, 32);
|
strcpy_trunc(entry.name, newname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Utilities/types.h"
|
#include "Utilities/types.h"
|
||||||
#include "Utilities/Config.h"
|
#include "Utilities/Config.h"
|
||||||
|
@ -199,6 +199,9 @@ class evdev_joystick_handler final : public PadHandlerBase
|
||||||
{ BTN_TRIGGER_HAPPY38 , "Happy 38" },
|
{ BTN_TRIGGER_HAPPY38 , "Happy 38" },
|
||||||
{ BTN_TRIGGER_HAPPY39 , "Happy 39" },
|
{ BTN_TRIGGER_HAPPY39 , "Happy 39" },
|
||||||
{ BTN_TRIGGER_HAPPY40 , "Happy 40" },
|
{ BTN_TRIGGER_HAPPY40 , "Happy 40" },
|
||||||
|
// Xbox One S Controller returns some buttons as key when connected through bluetooth
|
||||||
|
{ KEY_BACK , "Back Key" },
|
||||||
|
{ KEY_HOMEPAGE , "Homepage Key"},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Unique positive axis names for the config files and our pad settings dialog
|
// Unique positive axis names for the config files and our pad settings dialog
|
||||||
|
|
|
@ -551,7 +551,7 @@ void main_window::InstallPup(const QString& dropPath)
|
||||||
std::string version_string = pup.get_file(0x100).to_string();
|
std::string version_string = pup.get_file(0x100).to_string();
|
||||||
version_string.erase(version_string.find('\n'));
|
version_string.erase(version_string.find('\n'));
|
||||||
|
|
||||||
const std::string cur_version = "4.82";
|
const std::string cur_version = "4.83";
|
||||||
|
|
||||||
if (version_string < cur_version &&
|
if (version_string < cur_version &&
|
||||||
QMessageBox::question(this, tr("RPCS3 Firmware Installer"), tr("Old firmware detected.\nThe newest firmware version is %1 and you are trying to install version %2\nContinue installation?").arg(qstr(cur_version), qstr(version_string)),
|
QMessageBox::question(this, tr("RPCS3 Firmware Installer"), tr("Old firmware detected.\nThe newest firmware version is %1 and you are trying to install version %2\nContinue installation?").arg(qstr(cur_version), qstr(version_string)),
|
||||||
|
@ -1163,6 +1163,22 @@ void main_window::CreateConnects()
|
||||||
connect(ui->bootGameAct, &QAction::triggered, this, &main_window::BootGame);
|
connect(ui->bootGameAct, &QAction::triggered, this, &main_window::BootGame);
|
||||||
connect(ui->actionopen_rsx_capture, &QAction::triggered, [this](){ BootRsxCapture(); });
|
connect(ui->actionopen_rsx_capture, &QAction::triggered, [this](){ BootRsxCapture(); });
|
||||||
|
|
||||||
|
connect(ui->addGamesAct, &QAction::triggered, [this]() {
|
||||||
|
QStringList paths;
|
||||||
|
|
||||||
|
// Only select one folder for now
|
||||||
|
paths << QFileDialog::getExistingDirectory(this, tr("Select a folder containing one or more games"), qstr(fs::get_config_dir()), QFileDialog::ShowDirsOnly);
|
||||||
|
|
||||||
|
if (!paths.isEmpty())
|
||||||
|
{
|
||||||
|
for (const QString& path : paths)
|
||||||
|
{
|
||||||
|
AddGamesFromDir(path);
|
||||||
|
}
|
||||||
|
m_gameListFrame->Refresh(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(ui->bootRecentMenu, &QMenu::aboutToShow, [=]
|
connect(ui->bootRecentMenu, &QMenu::aboutToShow, [=]
|
||||||
{
|
{
|
||||||
// Enable/Disable Recent Games List
|
// Enable/Disable Recent Games List
|
||||||
|
|
|
@ -169,6 +169,8 @@
|
||||||
<addaction name="bootGameAct"/>
|
<addaction name="bootGameAct"/>
|
||||||
<addaction name="bootRecentMenu"/>
|
<addaction name="bootRecentMenu"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="addGamesAct"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
<addaction name="bootInstallPkgAct"/>
|
<addaction name="bootInstallPkgAct"/>
|
||||||
<addaction name="bootInstallPupAct"/>
|
<addaction name="bootInstallPupAct"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
@ -913,6 +915,11 @@
|
||||||
<string>Open RSX Capture</string>
|
<string>Open RSX Capture</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="addGamesAct">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Games</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
|
@ -120,6 +120,14 @@ rsx_debugger::rsx_debugger(std::shared_ptr<gui_settings> gui_settings, QWidget*
|
||||||
return table;
|
return table;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (const auto render = rsx::get_current_renderer())
|
||||||
|
{
|
||||||
|
if (RSXIOMem.RealAddr(render->ctrl->get.load()))
|
||||||
|
{
|
||||||
|
m_addr = render->ctrl->get.load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_list_commands = l_addRSXTab(m_list_commands, tr("RSX Commands"), 4);
|
m_list_commands = l_addRSXTab(m_list_commands, tr("RSX Commands"), 4);
|
||||||
m_list_captured_frame = l_addRSXTab(m_list_captured_frame, tr("Captured Frame"), 1);
|
m_list_captured_frame = l_addRSXTab(m_list_captured_frame, tr("Captured Frame"), 1);
|
||||||
m_list_captured_draw_calls = l_addRSXTab(m_list_captured_draw_calls, tr("Captured Draw Calls"), 1);
|
m_list_captured_draw_calls = l_addRSXTab(m_list_captured_draw_calls, tr("Captured Draw Calls"), 1);
|
||||||
|
@ -639,10 +647,7 @@ void rsx_debugger::GetMemory()
|
||||||
m_list_commands->setItem(i, 2, new QTableWidgetItem(DisAsmCommand(cmd, count, addr)));
|
m_list_commands->setItem(i, 2, new QTableWidgetItem(DisAsmCommand(cmd, count, addr)));
|
||||||
m_list_commands->setItem(i, 3, new QTableWidgetItem(QString::number(count)));
|
m_list_commands->setItem(i, 3, new QTableWidgetItem(QString::number(count)));
|
||||||
|
|
||||||
if((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) != RSX_METHOD_OLD_JUMP_CMD
|
if(!(cmd & RSX_METHOD_NON_METHOD_CMD_MASK))
|
||||||
&& (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) != RSX_METHOD_NEW_JUMP_CMD
|
|
||||||
&& (cmd & RSX_METHOD_CALL_CMD_MASK) != RSX_METHOD_CALL_CMD
|
|
||||||
&& cmd != RSX_METHOD_RETURN_CMD)
|
|
||||||
{
|
{
|
||||||
addr += 4 * count;
|
addr += 4 * count;
|
||||||
}
|
}
|
||||||
|
@ -1095,21 +1100,18 @@ QString rsx_debugger::DisAsmCommand(u32 cmd, u32 count, u32 ioAddr)
|
||||||
u32 callAddr = cmd & RSX_METHOD_CALL_OFFSET_MASK;
|
u32 callAddr = cmd & RSX_METHOD_CALL_OFFSET_MASK;
|
||||||
DISASM("CALL: %08x -> %08x", ioAddr, callAddr);
|
DISASM("CALL: %08x -> %08x", ioAddr, callAddr);
|
||||||
}
|
}
|
||||||
if(cmd == RSX_METHOD_RETURN_CMD)
|
if((cmd & ~0xfffc) == RSX_METHOD_RETURN_CMD)
|
||||||
{
|
{
|
||||||
DISASM("RETURN");
|
DISASM("RETURN");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd == 0)
|
if((cmd & ~(RSX_METHOD_NON_INCREMENT_CMD | 0xfffc)) == 0)
|
||||||
{
|
{
|
||||||
DISASM("NOP");
|
DISASM("NOP");
|
||||||
}
|
}
|
||||||
else if ((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) != RSX_METHOD_OLD_JUMP_CMD
|
else if (!(cmd & RSX_METHOD_NON_METHOD_CMD_MASK))
|
||||||
&& (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) != RSX_METHOD_NEW_JUMP_CMD
|
|
||||||
&& (cmd & RSX_METHOD_CALL_CMD_MASK) != RSX_METHOD_CALL_CMD
|
|
||||||
&& cmd != RSX_METHOD_RETURN_CMD)
|
|
||||||
{
|
{
|
||||||
auto args = vm::ptr<u32>::make(RSXIOMem.RealAddr(ioAddr + 4));
|
auto args = vm::get_super_ptr<u32>(RSXIOMem.RealAddr(ioAddr + 4));
|
||||||
|
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
switch((cmd & 0x3ffff) >> 2)
|
switch((cmd & 0x3ffff) >> 2)
|
||||||
|
@ -1173,11 +1175,8 @@ void rsx_debugger::PerformJump(u32 address)
|
||||||
if (!vm::check_addr(address, 4))
|
if (!vm::check_addr(address, 4))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u32 cmd = vm::read32(address);
|
u32 cmd = *vm::get_super_ptr<u32>(address);
|
||||||
u32 count = ((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD)
|
u32 count = cmd & RSX_METHOD_NON_METHOD_CMD_MASK ? 0 : (cmd >> 18) & 0x7ff;
|
||||||
|| ((cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD)
|
|
||||||
|| ((cmd & RSX_METHOD_CALL_CMD_MASK) == RSX_METHOD_CALL_CMD)
|
|
||||||
|| cmd == RSX_METHOD_RETURN_CMD ? 0 : (cmd >> 18) & 0x7ff;
|
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue