mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-13 06:03:16 +00:00
Merge branch 'shadps4-emu:main' into main
This commit is contained in:
commit
0f37c903ef
83 changed files with 2729 additions and 801 deletions
|
@ -459,8 +459,28 @@ void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, u32
|
|||
#endif
|
||||
}
|
||||
|
||||
void AddressSpace::Unmap(VAddr virtual_addr, size_t size, bool has_backing) {
|
||||
return impl->Unmap(virtual_addr, size, has_backing);
|
||||
void AddressSpace::Unmap(VAddr virtual_addr, size_t size, VAddr start_in_vma, VAddr end_in_vma,
|
||||
PAddr phys_base, bool is_exec, bool has_backing) {
|
||||
#ifdef _WIN32
|
||||
// There does not appear to be comparable support for partial unmapping on Windows.
|
||||
// Unfortunately, a least one title was found to require this. The workaround is to unmap
|
||||
// the entire allocation and remap the portions outside of the requested unmapping range.
|
||||
impl->Unmap(virtual_addr, size, has_backing);
|
||||
|
||||
// TODO: Determine if any titles require partial unmapping support for flexible allocations.
|
||||
ASSERT_MSG(has_backing || (start_in_vma == 0 && end_in_vma == size),
|
||||
"Partial unmapping of flexible allocations is not supported");
|
||||
|
||||
if (start_in_vma != 0) {
|
||||
Map(virtual_addr, start_in_vma, 0, phys_base, is_exec);
|
||||
}
|
||||
|
||||
if (end_in_vma != size) {
|
||||
Map(virtual_addr + end_in_vma, size - end_in_vma, 0, phys_base + end_in_vma, is_exec);
|
||||
}
|
||||
#else
|
||||
impl->Unmap(virtual_addr + start_in_vma, end_in_vma - start_in_vma, has_backing);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission perms) {
|
||||
|
|
|
@ -91,7 +91,8 @@ public:
|
|||
void* MapFile(VAddr virtual_addr, size_t size, size_t offset, u32 prot, uintptr_t fd);
|
||||
|
||||
/// Unmaps specified virtual memory area.
|
||||
void Unmap(VAddr virtual_addr, size_t size, bool has_backing);
|
||||
void Unmap(VAddr virtual_addr, size_t size, VAddr start_in_vma, VAddr end_in_vma,
|
||||
PAddr phys_base, bool is_exec, bool has_backing);
|
||||
|
||||
void Protect(VAddr virtual_addr, size_t size, MemoryPermission perms);
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ std::filesystem::path MntPoints::GetHostPath(const std::string& guest_directory)
|
|||
|
||||
// If the path does not exist attempt to verify this.
|
||||
// Retrieve parent path until we find one that exists.
|
||||
std::scoped_lock lk{m_mutex};
|
||||
path_parts.clear();
|
||||
auto current_path = host_path;
|
||||
while (!std::filesystem::exists(current_path)) {
|
||||
|
|
|
@ -235,6 +235,9 @@ int PS4_SYSV_ABI sceAudioOutGetSystemState() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutInit() {
|
||||
if (audio != nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT;
|
||||
}
|
||||
audio = std::make_unique<Audio::SDLAudio>();
|
||||
LOG_INFO(Lib_AudioOut, "called");
|
||||
return ORBIS_OK;
|
||||
|
|
|
@ -956,9 +956,9 @@ int PS4_SYSV_ABI sceGnmGetGpuBlockStatus() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency() {
|
||||
LOG_DEBUG(Lib_GnmDriver, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency() {
|
||||
LOG_TRACE(Lib_GnmDriver, "called");
|
||||
return Config::isNeoMode() ? 911'000'000 : 800'000'000;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmGetGpuInfoStatus() {
|
||||
|
@ -1706,8 +1706,18 @@ int PS4_SYSV_ABI sceGnmSetupMipStatsReport() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmSetVgtControl() {
|
||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||
s32 PS4_SYSV_ABI sceGnmSetVgtControl(u32* cmdbuf, u32 size, u32 prim_group_sz_minus_one,
|
||||
u32 partial_vs_wave_mode, u32 wd_switch_only_on_eop_mode) {
|
||||
LOG_TRACE(Lib_GnmDriver, "called");
|
||||
|
||||
if (!cmdbuf || size != 3 || (prim_group_sz_minus_one >= 0x100) ||
|
||||
((wd_switch_only_on_eop_mode | partial_vs_wave_mode) >= 2)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const u32 reg_value =
|
||||
((partial_vs_wave_mode & 1) << 0x10) | (prim_group_sz_minus_one & 0xffffu);
|
||||
PM4CmdSetData::SetContextReg(cmdbuf, 0x2aau, reg_value); // IA_MULTI_VGT_PARAM
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ int PS4_SYSV_ABI sceGnmGetDebugTimestamp();
|
|||
int PS4_SYSV_ABI sceGnmGetEqEventType();
|
||||
int PS4_SYSV_ABI sceGnmGetEqTimeStamp();
|
||||
int PS4_SYSV_ABI sceGnmGetGpuBlockStatus();
|
||||
int PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
|
||||
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
|
||||
int PS4_SYSV_ABI sceGnmGetGpuInfoStatus();
|
||||
int PS4_SYSV_ABI sceGnmGetLastWaitedAddress();
|
||||
int PS4_SYSV_ABI sceGnmGetNumTcaUnits();
|
||||
|
@ -161,7 +161,8 @@ int PS4_SYSV_ABI sceGnmSetResourceUserData();
|
|||
int PS4_SYSV_ABI sceGnmSetSpiEnableSqCounters();
|
||||
int PS4_SYSV_ABI sceGnmSetSpiEnableSqCountersForUnitInstance();
|
||||
int PS4_SYSV_ABI sceGnmSetupMipStatsReport();
|
||||
int PS4_SYSV_ABI sceGnmSetVgtControl();
|
||||
s32 PS4_SYSV_ABI sceGnmSetVgtControl(u32* cmdbuf, u32 size, u32 prim_group_sz_minus_one,
|
||||
u32 partial_vs_wave_mode, u32 wd_switch_only_on_eop_mode);
|
||||
s32 PS4_SYSV_ABI sceGnmSetVsShader(u32* cmdbuf, u32 size, const u32* vs_regs, u32 shader_modifier);
|
||||
int PS4_SYSV_ABI sceGnmSetWaveLimitMultiplier();
|
||||
int PS4_SYSV_ABI sceGnmSetWaveLimitMultipliers();
|
||||
|
|
|
@ -360,7 +360,6 @@ int PS4_SYSV_ABI posix_connect() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI _sigprocmask() {
|
||||
LOG_DEBUG(Lib_Kernel, "STUBBED");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,13 +75,22 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
|
|||
size_t* sizeOut) {
|
||||
LOG_WARNING(Kernel_Vmm, "called searchStart = {:#x}, searchEnd = {:#x}, alignment = {:#x}",
|
||||
searchStart, searchEnd, alignment);
|
||||
|
||||
if (searchEnd <= searchStart) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (searchEnd > SCE_KERNEL_MAIN_DMEM_SIZE) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
|
||||
PAddr physAddr;
|
||||
s32 size = memory->DirectQueryAvailable(searchStart, searchEnd, alignment, &physAddr, sizeOut);
|
||||
s32 result =
|
||||
memory->DirectQueryAvailable(searchStart, searchEnd, alignment, &physAddr, sizeOut);
|
||||
*physAddrOut = static_cast<u64>(physAddr);
|
||||
|
||||
return size;
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
|
||||
|
@ -244,9 +253,9 @@ s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* out_size) {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func) {
|
||||
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]) {
|
||||
auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||
linker->SetHeapApiFunc(func);
|
||||
linker->SetHeapAPI(func);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
|
||||
|
|
|
@ -102,7 +102,7 @@ int PS4_SYSV_ABI sceKernelMTypeProtect(void* addr, size_t size, int mtype, int p
|
|||
int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info,
|
||||
size_t infoSize);
|
||||
s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut);
|
||||
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func);
|
||||
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]);
|
||||
int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
|
||||
void** directMemoryStartOut,
|
||||
void** directMemoryEndOut);
|
||||
|
|
|
@ -421,13 +421,21 @@ ScePthreadMutex* createMutex(ScePthreadMutex* addr) {
|
|||
return addr;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr,
|
||||
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* mutex_attr,
|
||||
const char* name) {
|
||||
const ScePthreadMutexattr* attr;
|
||||
|
||||
if (mutex == nullptr) {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (attr == nullptr) {
|
||||
if (mutex_attr == nullptr) {
|
||||
attr = g_pthread_cxt->getDefaultMutexattr();
|
||||
} else {
|
||||
if (*mutex_attr == nullptr) {
|
||||
attr = g_pthread_cxt->getDefaultMutexattr();
|
||||
} else {
|
||||
attr = mutex_attr;
|
||||
}
|
||||
}
|
||||
|
||||
*mutex = new PthreadMutexInternal{};
|
||||
|
@ -1086,6 +1094,19 @@ int PS4_SYSV_ABI scePthreadAttrGetstack(ScePthreadAttr* attr, void** addr, size_
|
|||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadAttrSetstack(ScePthreadAttr* attr, void* addr, size_t size) {
|
||||
if (attr == nullptr || *attr == nullptr || addr == nullptr || size < 0x4000) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
int result = pthread_attr_setstack(&(*attr)->pth_attr, addr, size);
|
||||
LOG_INFO(Kernel_Pthread, "scePthreadAttrSetstack: result = {}", result);
|
||||
|
||||
if (result == 0) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadJoin(ScePthread thread, void** res) {
|
||||
int result = pthread_join(thread->pth, res);
|
||||
LOG_INFO(Kernel_Pthread, "scePthreadJoin result = {}", result);
|
||||
|
@ -1542,6 +1563,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("B5GmVDKwpn0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_yield);
|
||||
|
||||
LIB_FUNCTION("-quPa4SEJUw", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstack);
|
||||
LIB_FUNCTION("Bvn74vj6oLo", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetstack);
|
||||
LIB_FUNCTION("Ru36fiTtJzA", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstackaddr);
|
||||
LIB_FUNCTION("-fA+7ZlGDQs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstacksize);
|
||||
LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, scePthreadOnce);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/thread_management.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
|
@ -82,7 +81,6 @@ public:
|
|||
|
||||
public:
|
||||
struct WaitingThread : public ListBaseHook {
|
||||
std::string name;
|
||||
std::condition_variable cv;
|
||||
u32 priority;
|
||||
s32 need_count;
|
||||
|
@ -90,7 +88,6 @@ public:
|
|||
bool was_cancled{};
|
||||
|
||||
explicit WaitingThread(s32 need_count, bool is_fifo) : need_count{need_count} {
|
||||
name = scePthreadSelf()->name;
|
||||
if (is_fifo) {
|
||||
return;
|
||||
}
|
||||
|
@ -174,10 +171,16 @@ s32 PS4_SYSV_ABI sceKernelCreateSema(OrbisKernelSema* sem, const char* pName, u3
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelWaitSema(OrbisKernelSema sem, s32 needCount, u32* pTimeout) {
|
||||
if (!sem) {
|
||||
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
return sem->Wait(true, needCount, pTimeout);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSignalSema(OrbisKernelSema sem, s32 signalCount) {
|
||||
if (!sem) {
|
||||
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
if (!sem->Signal(signalCount)) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
@ -185,10 +188,16 @@ s32 PS4_SYSV_ABI sceKernelSignalSema(OrbisKernelSema sem, s32 signalCount) {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelPollSema(OrbisKernelSema sem, s32 needCount) {
|
||||
if (!sem) {
|
||||
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
return sem->Wait(false, needCount, nullptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelCancelSema(OrbisKernelSema sem, s32 setCount, s32* pNumWaitThreads) {
|
||||
if (!sem) {
|
||||
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
return sem->Cancel(setCount, pNumWaitThreads);
|
||||
}
|
||||
|
||||
|
|
|
@ -974,8 +974,11 @@ int PS4_SYSV_ABI sceNpGetGamePresenceStatusA() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetNpId() {
|
||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId userId, OrbisNpId* npId) {
|
||||
LOG_ERROR(Lib_NpManager, "(DUMMY) called");
|
||||
|
||||
std::string name = "shadps4";
|
||||
strcpy(npId->handle.data, name.c_str());
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,22 @@ class SymbolsResolver;
|
|||
|
||||
namespace Libraries::NpManager {
|
||||
|
||||
constexpr int ORBIS_NP_ONLINEID_MAX_LENGTH = 16;
|
||||
|
||||
typedef int OrbisUserServiceUserId;
|
||||
|
||||
struct OrbisNpOnlineId {
|
||||
char data[ORBIS_NP_ONLINEID_MAX_LENGTH];
|
||||
char term;
|
||||
char dummy[3];
|
||||
};
|
||||
|
||||
struct OrbisNpId {
|
||||
OrbisNpOnlineId handle;
|
||||
u8 opt[8];
|
||||
u8 reserved[8];
|
||||
};
|
||||
|
||||
int PS4_SYSV_ABI Func_EF4378573542A508();
|
||||
int PS4_SYSV_ABI _sceNpIpcCreateMemoryFromKernel();
|
||||
int PS4_SYSV_ABI _sceNpIpcCreateMemoryFromPool();
|
||||
|
@ -204,7 +220,7 @@ int PS4_SYSV_ABI sceNpGetAccountLanguage2();
|
|||
int PS4_SYSV_ABI sceNpGetAccountLanguageA();
|
||||
int PS4_SYSV_ABI sceNpGetGamePresenceStatus();
|
||||
int PS4_SYSV_ABI sceNpGetGamePresenceStatusA();
|
||||
int PS4_SYSV_ABI sceNpGetNpId();
|
||||
int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId userId, OrbisNpId* npId);
|
||||
int PS4_SYSV_ABI sceNpGetNpReachabilityState();
|
||||
int PS4_SYSV_ABI sceNpGetOnlineId();
|
||||
int PS4_SYSV_ABI sceNpGetParentalControlInfo();
|
||||
|
|
|
@ -419,8 +419,14 @@ int PS4_SYSV_ABI scePadSetForceIntercepted() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) {
|
||||
LOG_ERROR(Lib_Pad, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
if (pParam != nullptr) {
|
||||
LOG_INFO(Lib_Pad, "scePadSetLightBar called handle = {} rgb = {} {} {}", handle, pParam->r,
|
||||
pParam->g, pParam->b);
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
controller->SetLightBarRGB(pParam->r, pParam->g, pParam->b);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
return ORBIS_PAD_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadSetLightBarBaseBrightness() {
|
||||
|
@ -479,8 +485,14 @@ int PS4_SYSV_ABI scePadSetUserColor() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadSetVibration(s32 handle, const OrbisPadVibrationParam* pParam) {
|
||||
LOG_DEBUG(Lib_Pad, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
if (pParam != nullptr) {
|
||||
LOG_INFO(Lib_Pad, "scePadSetVibration called handle = {} data = {} , {}", handle,
|
||||
pParam->smallMotor, pParam->largeMotor);
|
||||
auto* controller = Common::Singleton<Input::GameController>::Instance();
|
||||
controller->SetVibration(pParam->smallMotor, pParam->largeMotor);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
return ORBIS_PAD_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadSetVibrationForce() {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/time_management.h"
|
||||
#include "core/libraries/videoout/driver.h"
|
||||
#include "core/platform.h"
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
|
||||
extern std::unique_ptr<Vulkan::RendererVulkan> renderer;
|
||||
|
@ -173,14 +174,19 @@ std::chrono::microseconds VideoOutDriver::Flip(const Request& req) {
|
|||
|
||||
// Update flip status.
|
||||
auto* port = req.port;
|
||||
auto& flip_status = port->flip_status;
|
||||
flip_status.count++;
|
||||
flip_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
flip_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
||||
flip_status.submitTsc = Libraries::Kernel::sceKernelReadTsc();
|
||||
flip_status.flipArg = req.flip_arg;
|
||||
flip_status.currentBuffer = req.index;
|
||||
flip_status.flipPendingNum = static_cast<int>(requests.size());
|
||||
{
|
||||
std::unique_lock lock{port->port_mutex};
|
||||
auto& flip_status = port->flip_status;
|
||||
flip_status.count++;
|
||||
flip_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
flip_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
||||
flip_status.flipArg = req.flip_arg;
|
||||
flip_status.currentBuffer = req.index;
|
||||
if (req.eop) {
|
||||
--flip_status.gcQueueNum;
|
||||
}
|
||||
--flip_status.flipPendingNum;
|
||||
}
|
||||
|
||||
// Trigger flip events for the port.
|
||||
for (auto& event : port->flip_events) {
|
||||
|
@ -202,34 +208,54 @@ std::chrono::microseconds VideoOutDriver::Flip(const Request& req) {
|
|||
|
||||
bool VideoOutDriver::SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg,
|
||||
bool is_eop /*= false*/) {
|
||||
{
|
||||
std::unique_lock lock{port->port_mutex};
|
||||
if (index != -1 && port->flip_status.flipPendingNum >= port->NumRegisteredBuffers()) {
|
||||
LOG_ERROR(Lib_VideoOut, "Flip queue is full");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_eop) {
|
||||
++port->flip_status.gcQueueNum;
|
||||
}
|
||||
++port->flip_status.flipPendingNum; // integral GPU and CPU pending flips counter
|
||||
port->flip_status.submitTsc = Libraries::Kernel::sceKernelReadTsc();
|
||||
}
|
||||
|
||||
if (!is_eop) {
|
||||
// Before processing the flip we need to ask GPU thread to flush command list as at this
|
||||
// point VO surface is ready to be presented, and we will need have an actual state of
|
||||
// Vulkan image at the time of frame presentation.
|
||||
liverpool->SendCommand([=, this]() {
|
||||
renderer->FlushDraw();
|
||||
SubmitFlipInternal(port, index, flip_arg, is_eop);
|
||||
});
|
||||
} else {
|
||||
SubmitFlipInternal(port, index, flip_arg, is_eop);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoOutDriver::SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_arg,
|
||||
bool is_eop /*= false*/) {
|
||||
Vulkan::Frame* frame;
|
||||
if (index == -1) {
|
||||
frame = renderer->PrepareBlankFrame();
|
||||
frame = renderer->PrepareBlankFrame(is_eop);
|
||||
} else {
|
||||
const auto& buffer = port->buffer_slots[index];
|
||||
const auto& group = port->groups[buffer.group_index];
|
||||
frame = renderer->PrepareFrame(group, buffer.address_left, is_eop);
|
||||
}
|
||||
|
||||
if (index != -1 && requests.size() >= port->NumRegisteredBuffers()) {
|
||||
LOG_ERROR(Lib_VideoOut, "Flip queue is full");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{mutex};
|
||||
requests.push({
|
||||
.frame = frame,
|
||||
.port = port,
|
||||
.index = index,
|
||||
.flip_arg = flip_arg,
|
||||
.submit_tsc = Libraries::Kernel::sceKernelReadTsc(),
|
||||
.eop = is_eop,
|
||||
});
|
||||
|
||||
port->flip_status.flipPendingNum = static_cast<int>(requests.size());
|
||||
port->flip_status.gcQueueNum = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||
|
|
|
@ -29,6 +29,7 @@ struct VideoOutPort {
|
|||
std::vector<Kernel::SceKernelEqueue> flip_events;
|
||||
std::vector<Kernel::SceKernelEqueue> vblank_events;
|
||||
std::mutex vo_mutex;
|
||||
std::mutex port_mutex;
|
||||
std::condition_variable vo_cv;
|
||||
std::condition_variable vblank_cv;
|
||||
int flip_rate = 0;
|
||||
|
@ -93,7 +94,6 @@ private:
|
|||
VideoOutPort* port;
|
||||
s32 index;
|
||||
s64 flip_arg;
|
||||
u64 submit_tsc;
|
||||
bool eop;
|
||||
|
||||
operator bool() const noexcept {
|
||||
|
@ -102,6 +102,7 @@ private:
|
|||
};
|
||||
|
||||
std::chrono::microseconds Flip(const Request& req);
|
||||
void SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
|
||||
void PresentThread(std::stop_token token);
|
||||
|
||||
std::mutex mutex;
|
||||
|
|
|
@ -113,7 +113,9 @@ s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate) {
|
|||
|
||||
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle) {
|
||||
LOG_INFO(Lib_VideoOut, "called");
|
||||
s32 pending = driver->GetPort(handle)->flip_status.flipPendingNum;
|
||||
auto* port = driver->GetPort(handle);
|
||||
std::unique_lock lock{port->port_mutex};
|
||||
s32 pending = port->flip_status.flipPendingNum;
|
||||
return pending;
|
||||
}
|
||||
|
||||
|
@ -161,6 +163,7 @@ s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status) {
|
|||
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
std::unique_lock lock{port->port_mutex};
|
||||
*status = port->flip_status;
|
||||
|
||||
LOG_INFO(Lib_VideoOut,
|
||||
|
|
|
@ -305,7 +305,8 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
|||
// Module was just loaded by above code. Allocate TLS block for it.
|
||||
Module* module = m_modules[module_index - 1].get();
|
||||
const u32 init_image_size = module->tls.init_image_size;
|
||||
u8* dest = reinterpret_cast<u8*>(heap_api_func(module->tls.image_size));
|
||||
// TODO: Determine if Windows will crash from this
|
||||
u8* dest = reinterpret_cast<u8*>(heap_api->heap_malloc(module->tls.image_size));
|
||||
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
||||
std::memcpy(dest, src, init_image_size);
|
||||
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
|
||||
|
@ -335,10 +336,23 @@ void Linker::InitTlsForThread(bool is_primary) {
|
|||
&addr_out, tls_aligned, 3, 0, "SceKernelPrimaryTcbTls");
|
||||
ASSERT_MSG(ret == 0, "Unable to allocate TLS+TCB for the primary thread");
|
||||
} else {
|
||||
if (heap_api_func) {
|
||||
addr_out = heap_api_func(total_tls_size);
|
||||
if (heap_api) {
|
||||
#ifndef WIN32
|
||||
addr_out = heap_api->heap_malloc(total_tls_size);
|
||||
} else {
|
||||
addr_out = std::malloc(total_tls_size);
|
||||
#else
|
||||
// TODO: Windows tls malloc replacement, refer to rtld_tls_block_malloc
|
||||
LOG_ERROR(Core_Linker, "TLS user malloc called, using std::malloc");
|
||||
addr_out = std::malloc(total_tls_size);
|
||||
if (!addr_out) {
|
||||
auto pth_id = pthread_self();
|
||||
auto handle = pthread_gethandle(pth_id);
|
||||
ASSERT_MSG(addr_out,
|
||||
"Cannot allocate TLS block defined for handle=%x, index=%d size=%d",
|
||||
handle, pth_id, total_tls_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,21 @@ struct EntryParams {
|
|||
const char* argv[3];
|
||||
};
|
||||
|
||||
using HeapApiFunc = PS4_SYSV_ABI void* (*)(size_t);
|
||||
struct HeapAPI {
|
||||
PS4_SYSV_ABI void* (*heap_malloc)(size_t);
|
||||
PS4_SYSV_ABI void (*heap_free)(void*);
|
||||
PS4_SYSV_ABI void* (*heap_calloc)(size_t, size_t);
|
||||
PS4_SYSV_ABI void* (*heap_realloc)(void*, size_t);
|
||||
PS4_SYSV_ABI void* (*heap_memalign)(size_t, size_t);
|
||||
PS4_SYSV_ABI int (*heap_posix_memalign)(void**, size_t, size_t);
|
||||
// NOTE: Fields below may be inaccurate
|
||||
PS4_SYSV_ABI int (*heap_reallocalign)(void);
|
||||
PS4_SYSV_ABI void (*heap_malloc_stats)(void);
|
||||
PS4_SYSV_ABI int (*heap_malloc_stats_fast)(void);
|
||||
PS4_SYSV_ABI size_t (*heap_malloc_usable_size)(void*);
|
||||
};
|
||||
|
||||
using AppHeapAPI = HeapAPI*;
|
||||
|
||||
class Linker {
|
||||
public:
|
||||
|
@ -75,8 +89,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void SetHeapApiFunc(void* func) {
|
||||
heap_api_func = *reinterpret_cast<HeapApiFunc*>(func);
|
||||
void SetHeapAPI(void* func[]) {
|
||||
heap_api = reinterpret_cast<AppHeapAPI>(func);
|
||||
}
|
||||
|
||||
void AdvanceGenerationCounter() noexcept {
|
||||
|
@ -104,7 +118,7 @@ private:
|
|||
size_t static_tls_size{};
|
||||
u32 max_tls_index{};
|
||||
u32 num_static_modules{};
|
||||
HeapApiFunc heap_api_func{};
|
||||
AppHeapAPI heap_api{};
|
||||
std::vector<std::unique_ptr<Module>> m_modules;
|
||||
Loader::SymbolsResolver m_hle_symbols{};
|
||||
};
|
||||
|
|
|
@ -55,7 +55,7 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
|
|||
free_addr = alignment > 0 ? Common::AlignUp(free_addr, alignment) : free_addr;
|
||||
|
||||
// Add the allocated region to the list and commit its pages.
|
||||
auto& area = CarveDmemArea(free_addr, size);
|
||||
auto& area = CarveDmemArea(free_addr, size)->second;
|
||||
area.memory_type = memory_type;
|
||||
area.is_free = false;
|
||||
return free_addr;
|
||||
|
@ -64,9 +64,8 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
|
|||
void MemoryManager::Free(PAddr phys_addr, size_t size) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
const auto dmem_area = FindDmemArea(phys_addr);
|
||||
ASSERT(dmem_area != dmem_map.end() && dmem_area->second.base == phys_addr &&
|
||||
dmem_area->second.size == size);
|
||||
auto dmem_area = CarveDmemArea(phys_addr, size);
|
||||
ASSERT(dmem_area != dmem_map.end() && dmem_area->second.size >= size);
|
||||
|
||||
// Release any dmem mappings that reference this physical block.
|
||||
std::vector<std::pair<VAddr, u64>> remove_list;
|
||||
|
@ -75,10 +74,11 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
|
|||
continue;
|
||||
}
|
||||
if (mapping.phys_base <= phys_addr && phys_addr < mapping.phys_base + mapping.size) {
|
||||
LOG_INFO(Kernel_Vmm, "Unmaping direct mapping {:#x} with size {:#x}", addr,
|
||||
mapping.size);
|
||||
auto vma_segment_start_addr = phys_addr - mapping.phys_base + addr;
|
||||
LOG_INFO(Kernel_Vmm, "Unmaping direct mapping {:#x} with size {:#x}",
|
||||
vma_segment_start_addr, size);
|
||||
// Unmaping might erase from vma_map. We can't do it here.
|
||||
remove_list.emplace_back(addr, mapping.size);
|
||||
remove_list.emplace_back(vma_segment_start_addr, size);
|
||||
}
|
||||
}
|
||||
for (const auto& [addr, size] : remove_list) {
|
||||
|
@ -105,8 +105,6 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
const auto& vma = FindVMA(mapped_addr)->second;
|
||||
// If the VMA is mapped, unmap the region first.
|
||||
if (vma.IsMapped()) {
|
||||
ASSERT_MSG(vma.base == mapped_addr && vma.size == size,
|
||||
"Region must match when reserving a mapped region");
|
||||
UnmapMemory(mapped_addr, size);
|
||||
}
|
||||
const size_t remaining_size = vma.base + vma.size - mapped_addr;
|
||||
|
@ -170,6 +168,7 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
|
|||
new_vma.prot = prot;
|
||||
new_vma.name = name;
|
||||
new_vma.type = type;
|
||||
new_vma.is_exec = is_exec;
|
||||
|
||||
if (type == VMAType::Direct) {
|
||||
new_vma.phys_base = phys_addr;
|
||||
|
@ -217,10 +216,16 @@ void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
|
|||
std::scoped_lock lk{mutex};
|
||||
|
||||
const auto it = FindVMA(virtual_addr);
|
||||
ASSERT_MSG(it->second.Contains(virtual_addr, size),
|
||||
const auto& vma_base = it->second;
|
||||
ASSERT_MSG(vma_base.Contains(virtual_addr, size),
|
||||
"Existing mapping does not contain requested unmap range");
|
||||
|
||||
const auto type = it->second.type;
|
||||
const auto vma_base_addr = vma_base.base;
|
||||
const auto vma_base_size = vma_base.size;
|
||||
const auto phys_base = vma_base.phys_base;
|
||||
const bool is_exec = vma_base.is_exec;
|
||||
const auto start_in_vma = virtual_addr - vma_base_addr;
|
||||
const auto type = vma_base.type;
|
||||
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
|
||||
if (type == VMAType::Direct) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
|
@ -240,7 +245,8 @@ void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
|
|||
MergeAdjacent(vma_map, new_it);
|
||||
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(virtual_addr, size, has_backing);
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base, is_exec,
|
||||
has_backing);
|
||||
TRACK_FREE(virtual_addr, "VMEM");
|
||||
}
|
||||
|
||||
|
@ -364,10 +370,10 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
|
|||
std::scoped_lock lk{mutex};
|
||||
|
||||
auto it = FindVMA(addr);
|
||||
if (!it->second.IsMapped() && flags == 1) {
|
||||
if (it->second.type == VMAType::Free && flags == 1) {
|
||||
it++;
|
||||
}
|
||||
if (!it->second.IsMapped()) {
|
||||
if (it->second.type == VMAType::Free) {
|
||||
LOG_WARNING(Kernel_Vmm, "VirtualQuery on free memory region");
|
||||
return ORBIS_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
|
@ -494,13 +500,12 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
|
|||
return vma_handle;
|
||||
}
|
||||
|
||||
DirectMemoryArea& MemoryManager::CarveDmemArea(PAddr addr, size_t size) {
|
||||
MemoryManager::DMemHandle MemoryManager::CarveDmemArea(PAddr addr, size_t size) {
|
||||
auto dmem_handle = FindDmemArea(addr);
|
||||
ASSERT_MSG(dmem_handle != dmem_map.end(), "Physical address not in dmem_map");
|
||||
|
||||
const DirectMemoryArea& area = dmem_handle->second;
|
||||
ASSERT_MSG(area.is_free && area.base <= addr,
|
||||
"Adding an allocation to already allocated region");
|
||||
ASSERT_MSG(area.base <= addr, "Adding an allocation to already allocated region");
|
||||
|
||||
const PAddr start_in_area = addr - area.base;
|
||||
const PAddr end_in_vma = start_in_area + size;
|
||||
|
@ -515,7 +520,7 @@ DirectMemoryArea& MemoryManager::CarveDmemArea(PAddr addr, size_t size) {
|
|||
dmem_handle = Split(dmem_handle, start_in_area);
|
||||
}
|
||||
|
||||
return dmem_handle->second;
|
||||
return dmem_handle;
|
||||
}
|
||||
|
||||
MemoryManager::VMAHandle MemoryManager::Split(VMAHandle vma_handle, size_t offset_in_vma) {
|
||||
|
|
|
@ -84,6 +84,7 @@ struct VirtualMemoryArea {
|
|||
bool disallow_merge = false;
|
||||
std::string name = "";
|
||||
uintptr_t fd = 0;
|
||||
bool is_exec = false;
|
||||
|
||||
bool Contains(VAddr addr, size_t size) const {
|
||||
return addr >= base && (addr + size) <= (base + this->size);
|
||||
|
@ -210,7 +211,7 @@ private:
|
|||
|
||||
VMAHandle CarveVMA(VAddr virtual_addr, size_t size);
|
||||
|
||||
DirectMemoryArea& CarveDmemArea(PAddr addr, size_t size);
|
||||
DMemHandle CarveDmemArea(PAddr addr, size_t size);
|
||||
|
||||
VMAHandle Split(VMAHandle vma_handle, size_t offset_in_vma);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue