From 5834b82efb6eda53b8a4cbab867681528b8c9e3b Mon Sep 17 00:00:00 2001 From: IndecisiveTurtle <47210458+raphaelthegreat@users.noreply.github.com> Date: Sat, 15 Jun 2024 03:43:42 +0300 Subject: [PATCH] Improve linux support --- CMakeLists.txt | 4 +- src/common/io_file.cpp | 7 +- src/common/io_file.h | 4 +- src/core/address_space.cpp | 13 +-- src/core/address_space.h | 4 +- src/core/libraries/gnmdriver/gnmdriver.cpp | 2 +- src/core/libraries/kernel/file_system.cpp | 4 + src/core/libraries/kernel/libkernel.cpp | 32 +++++-- .../libraries/kernel/memory_management.cpp | 14 +-- .../libraries/kernel/thread_management.cpp | 91 ++++++++++--------- src/core/libraries/kernel/thread_management.h | 1 - src/core/libraries/kernel/threads/keys.cpp | 7 +- src/core/libraries/kernel/threads/rwlock.cpp | 39 ++++++-- .../libraries/kernel/threads/semaphore.cpp | 8 +- src/core/libraries/kernel/time_management.cpp | 15 ++- src/core/libraries/libs.h | 12 +-- src/core/libraries/save_data/savedata.cpp | 2 +- src/core/linker.h | 1 + src/core/memory.cpp | 5 +- src/core/memory.h | 4 +- src/core/module.h | 2 +- src/core/tls.cpp | 3 +- src/emulator.cpp | 12 +-- src/video_core/amdgpu/liverpool.cpp | 24 ++--- src/video_core/amdgpu/liverpool.h | 9 +- 25 files changed, 193 insertions(+), 126 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5cb24076..027645d0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,8 +224,6 @@ set(COMMON src/common/logging/backend.cpp src/common/debug.h src/common/disassembler.cpp src/common/disassembler.h - src/common/discord.cpp - src/common/discord.h src/common/endian.h src/common/enum.h src/common/io_file.cpp @@ -509,7 +507,7 @@ endif() create_target_directory_groups(shadps4) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak Tracy::TracyClient) -target_link_libraries(shadps4 PRIVATE discord-rpc boost vma sirit vulkan-headers xxhash Zydis SPIRV glslang SDL3-shared) +target_link_libraries(shadps4 PRIVATE boost vma sirit vulkan-headers xxhash Zydis SPIRV glslang SDL3-shared) if (NOT ENABLE_QT_GUI) target_link_libraries(shadps4 PRIVATE SDL3-shared) diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp index 985bc667b..3b66c6a87 100644 --- a/src/common/io_file.cpp +++ b/src/common/io_file.cpp @@ -216,17 +216,20 @@ void IOFile::Close() { #endif } -void* IOFile::GetFileMapping() { -#ifdef _WIN64 +uintptr_t IOFile::GetFileMapping() { if (file_mapping) { return file_mapping; } +#ifdef _WIN64 const int fd = fileno(file); HANDLE hfile = reinterpret_cast(_get_osfhandle(fd)); file_mapping = CreateFileMapping2(hfile, NULL, FILE_MAP_READ, PAGE_READONLY, SEC_COMMIT, 0, NULL, NULL, 0); ASSERT_MSG(file_mapping, "{}", Common::GetLastErrorMsg()); return file_mapping; +#else + file_mapping = fileno(file); + return file_mapping; #endif } diff --git a/src/common/io_file.h b/src/common/io_file.h index ff5d103bd..e57a5a783 100644 --- a/src/common/io_file.h +++ b/src/common/io_file.h @@ -100,7 +100,7 @@ public: return file != nullptr; } - void* GetFileMapping(); + uintptr_t GetFileMapping(); void Open(const std::filesystem::path& path, FileAccessMode mode, FileType type = FileType::BinaryFile, @@ -214,7 +214,7 @@ private: FileType file_type{}; std::FILE* file = nullptr; - void* file_mapping = nullptr; + uintptr_t file_mapping = 0; }; } // namespace Common::FS diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp index 10862a8d0..df31de8ec 100644 --- a/src/core/address_space.cpp +++ b/src/core/address_space.cpp @@ -255,13 +255,14 @@ struct AddressSpace::Impl { m_free_regions.insert({start_addr, start_addr + virtual_size}); } - void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, PosixPageProtection prot) { + void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, PosixPageProtection prot, + int fd = -1) { m_free_regions.subtract({virtual_addr, virtual_addr + size}); - const int fd = phys_addr != -1 ? backing_fd : -1; - const int host_offset = phys_addr != -1 ? phys_addr : 0; + const int handle = phys_addr != -1 ? (fd == -1 ? backing_fd : fd) : -1; + const off_t host_offset = phys_addr != -1 ? phys_addr : 0; const int flag = phys_addr != -1 ? MAP_SHARED : (MAP_ANONYMOUS | MAP_PRIVATE); - void* ret = mmap(reinterpret_cast(virtual_addr), size, prot, MAP_FIXED | flag, fd, - host_offset); + void* ret = mmap(reinterpret_cast(virtual_addr), size, prot, MAP_FIXED | flag, + handle, host_offset); ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); return ret; } @@ -324,7 +325,7 @@ void* AddressSpace::Map(VAddr virtual_addr, size_t size, u64 alignment, PAddr ph is_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); } -void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, void* fd) { +void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, uintptr_t fd) { return impl->Map(virtual_addr, offset, size, fd ? PAGE_READONLY : PAGE_READWRITE, fd); } diff --git a/src/core/address_space.h b/src/core/address_space.h index 547afa375..5bb553aec 100644 --- a/src/core/address_space.h +++ b/src/core/address_space.h @@ -20,7 +20,7 @@ DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission) constexpr VAddr SYSTEM_RESERVED = 0x800000000ULL; constexpr VAddr CODE_BASE_OFFSET = 0x100000000ULL; -constexpr VAddr SYSTEM_MANAGED_MIN = 0x0000040000ULL; +constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL; constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL; constexpr VAddr USER_MIN = 0x1000000000ULL; constexpr VAddr USER_MAX = 0xFBFFFFFFFFULL; @@ -63,7 +63,7 @@ public: bool exec = false); /// Memory maps a specified file descriptor. - void* MapFile(VAddr virtual_addr, size_t size, size_t offset, void* fd); + void* MapFile(VAddr virtual_addr, size_t size, size_t offset, uintptr_t fd); /// Unmaps specified virtual memory area. void Unmap(VAddr virtual_addr, size_t size, bool has_backing); diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index f4e2c1b85..fb829ce5c 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -989,7 +989,7 @@ s32 PS4_SYSV_ABI sceGnmSetEmbeddedVsShader(u32* cmdbuf, u32 size, u32 shader_id, // a check for zero in the upper part of shader address. In our case, the address is a // pointer to a stack memory, so the check will likely fail. To workaround it we will // repeat set shader functionality here as it is trivial. - cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x48u, vs_regs[0], 0u); // SPI_SHADER_PGM_LO_VS + cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x48u, vs_regs[0], vs_regs[1]); // SPI_SHADER_PGM_LO_VS cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x4au, vs_regs[2], vs_regs[3]); // SPI_SHADER_PGM_RSRC1_VS cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x207u, vs_regs[6]); // PA_CL_VS_OUT_CNTL diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 4fdddde95..537f959b1 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -31,6 +31,10 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0; bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0; + if (std::string_view{path} == "/dev/console" || std::string_view{path} == "/dev/deci_tty6") { + return ORBIS_OK; + } + if (directory) { LOG_ERROR(Kernel_Fs, "called on directory"); } else { diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index 8b26ab664..8b093d25d 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -73,17 +73,16 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, fmt::ptr(addr), len, prot, flags, fd, offset); auto* h = Common::Singleton::Instance(); auto* memory = Core::Memory::Instance(); - void* handle = NULL; - if (fd == -1) { - handle = - CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, len + offset, NULL); - } else { - handle = h->GetFile(fd)->f.GetFileMapping(); - } const auto mem_prot = static_cast(prot); const auto mem_flags = static_cast(flags); - return memory->MapFile(res, std::bit_cast(addr), len, mem_prot, mem_flags, handle, - offset); + if (fd == -1) { + return memory->MapMemory(res, std::bit_cast(addr), len, mem_prot, mem_flags, + Core::VMAType::Flexible); + } else { + const uintptr_t handle = h->GetFile(fd)->f.GetFileMapping(); + return memory->MapFile(res, std::bit_cast(addr), len, mem_prot, mem_flags, handle, + offset); + } } void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) { @@ -248,6 +247,15 @@ s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, int flags, return ORBIS_OK; } +int PS4_SYSV_ABI sceKernelGetModuleInfoFromAddr(VAddr addr, int flags, + Core::OrbisKernelModuleInfoEx* info) { + LOG_INFO(Lib_Kernel, "called addr = {:#x}, flags = {:#x}", addr, flags); + auto* linker = Common::Singleton::Instance(); + auto* module = linker->FindByAddress(addr); + *info = module->GetModuleInfoEx(); + return ORBIS_OK; +} + int PS4_SYSV_ABI sceKernelDebugRaiseException() { UNREACHABLE(); return 0; @@ -267,6 +275,10 @@ int PS4_SYSV_ABI sceKernelGetCpumode() { return 5; } +void PS4_SYSV_ABI sched_yield() { + return std::this_thread::yield(); +} + void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { // obj LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); @@ -292,6 +304,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("wzvqT4UqKX8", "libkernel", 1, "libkernel", 1, 1, sceKernelLoadStartModule); LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym); LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind); + LIB_FUNCTION("f7KBOafysXo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoFromAddr); LIB_FUNCTION("VOx8NGmHXTs", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCpumode); // equeue @@ -326,6 +339,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1, sceLibcHeapGetTraceInfo); LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write); + LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield); } } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index 9f24ac4a3..4683440aa 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -90,10 +90,10 @@ s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtual int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment, const char* name) { - LOG_INFO( - Kernel_Vmm, - "len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = {:#x}", - len, prot, flags, directMemoryStart, alignment); + LOG_INFO(Kernel_Vmm, + "addr = {}, len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, " + "alignment = {:#x}", + fmt::ptr(*addr), len, prot, flags, directMemoryStart, alignment); if (len == 0 || !Common::Is16KBAligned(len)) { LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!"); @@ -120,11 +120,7 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment) { - LOG_INFO(Kernel_Vmm, - "redirected to sceKernelMapNamedDirectMemory: " - "len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = " - "{:#x}", - len, prot, flags, directMemoryStart, alignment); + LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory"); return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment, ""); } diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 3200fcd28..afe50c9e5 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -5,6 +5,7 @@ #include #include #include "common/assert.h" +#include "common/error.h" #include "common/logging/log.h" #include "common/singleton.h" #include "common/thread.h" @@ -138,9 +139,8 @@ int PS4_SYSV_ABI scePthreadAttrGetdetachstate(const ScePthreadAttr* attr, int* s return SCE_KERNEL_ERROR_EINVAL; } - // int result = pthread_attr_getdetachstate(&(*attr)->p, state); + // int result = pthread_attr_getdetachstate(&(*attr)->pth_attr, state); int result = 0; - *state = ((*attr)->detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE); switch (*state) { @@ -174,12 +174,9 @@ int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachst UNREACHABLE_MSG("Invalid detachstate: {}", detachstate); } - // int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate); doesn't seem to work - // correctly + // int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate); int result = 0; - (*attr)->detached = (pstate == PTHREAD_CREATE_DETACHED); - return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL; } @@ -246,7 +243,6 @@ int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr, } int PS4_SYSV_ABI scePthreadAttrGetschedpolicy(const ScePthreadAttr* attr, int* policy) { - if (policy == nullptr || attr == nullptr || *attr == nullptr) { return SCE_KERNEL_ERROR_EINVAL; } @@ -275,16 +271,26 @@ int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy) return SCE_KERNEL_ERROR_EINVAL; } - int ppolicy = SCHED_OTHER; // winpthreads only supports SCHED_OTHER - if (policy != SCHED_OTHER) { - LOG_ERROR(Kernel_Pthread, "policy={} not supported by winpthreads\n", policy); + int ppolicy = SCHED_OTHER; + switch (policy) { + case 0: + ppolicy = SCHED_OTHER; + break; + case 1: + ppolicy = SCHED_FIFO; + break; + case 3: + ppolicy = SCHED_OTHER; + break; + default: + UNREACHABLE(); } + (*attr)->policy = policy; - int result = pthread_attr_setschedpolicy(&(*attr)->pth_attr, ppolicy); - return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL; } + ScePthread PS4_SYSV_ABI scePthreadSelf() { return g_pthread_self; } @@ -298,7 +304,6 @@ int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr, } (*pattr)->affinity = mask; - return SCE_OK; } @@ -391,16 +396,18 @@ int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpuma return result; } -void* createMutex(void* addr) { - if (addr == nullptr || *static_cast(addr) != nullptr) { +ScePthreadMutex* createMutex(ScePthreadMutex* addr) { + if (addr == nullptr || *addr != nullptr) { return addr; } static std::mutex mutex; std::scoped_lock lk{mutex}; - auto vaddr = reinterpret_cast(addr); - + if (*addr != nullptr) { + return addr; + } + const VAddr vaddr = reinterpret_cast(addr); std::string name = fmt::format("mutex{:#x}", vaddr); - scePthreadMutexInit(static_cast(addr), nullptr, name.c_str()); + scePthreadMutexInit(addr, nullptr, name.c_str()); return addr; } @@ -468,7 +475,7 @@ int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr) { int result = pthread_mutexattr_init(&(*attr)->pth_mutex_attr); - result = (result == 0 ? scePthreadMutexattrSettype(attr, 2) : result); + result = (result == 0 ? scePthreadMutexattrSettype(attr, 1) : result); result = (result == 0 ? scePthreadMutexattrSetprotocol(attr, 0) : result); switch (result) { @@ -519,22 +526,20 @@ int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int p UNREACHABLE_MSG("Invalid protocol: {}", protocol); } - int result = 0; // pthread_mutexattr_setprotocol(&(*attr)->p, pprotocol); //it appears that - // pprotocol has issues in winpthreads + int result = pthread_mutexattr_setprotocol(&(*attr)->pth_mutex_attr, pprotocol); (*attr)->pprotocol = pprotocol; - return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL; } -int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) { - mutex = static_cast(createMutex(mutex)); +int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) { + mutex = createMutex(mutex); if (mutex == nullptr) { return SCE_KERNEL_ERROR_EINVAL; } int result = pthread_mutex_lock(&(*mutex)->pth_mutex); if (result != 0) { - LOG_TRACE(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result); + LOG_TRACE(Kernel_Pthread, "Locked name={}, result={}", (*mutex)->name, result); } switch (result) { case 0: @@ -549,20 +554,20 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) { return SCE_KERNEL_ERROR_EINVAL; } } + int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) { - mutex = static_cast(createMutex(mutex)); + mutex = createMutex(mutex); if (mutex == nullptr) { return SCE_KERNEL_ERROR_EINVAL; } int result = pthread_mutex_unlock(&(*mutex)->pth_mutex); if (result != 0) { - LOG_TRACE(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result); + LOG_TRACE(Kernel_Pthread, "Unlocking name={}, result={}", (*mutex)->name, result); } switch (result) { case 0: return SCE_OK; - case EINVAL: return SCE_KERNEL_ERROR_EINVAL; case EPERM: @@ -573,7 +578,6 @@ int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) { } int PS4_SYSV_ABI scePthreadMutexattrDestroy(ScePthreadMutexattr* attr) { - int result = pthread_mutexattr_destroy(&(*attr)->pth_mutex_attr); delete *attr; @@ -589,12 +593,16 @@ int PS4_SYSV_ABI scePthreadMutexattrDestroy(ScePthreadMutexattr* attr) { } } -void* createCond(void* addr) { - if (addr == nullptr || *static_cast(addr) != nullptr) { +ScePthreadCond* createCond(ScePthreadCond* addr) { + if (addr == nullptr || *addr != nullptr) { return addr; } - auto vaddr = reinterpret_cast(addr); - + static std::mutex mutex; + std::scoped_lock lk{mutex}; + if (*addr != nullptr) { + return addr; + } + const VAddr vaddr = reinterpret_cast(addr); std::string name = fmt::format("cond{:#x}", vaddr); scePthreadCondInit(static_cast(addr), nullptr, name.c_str()); return addr; @@ -654,8 +662,7 @@ int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr) { } int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) { - cond = static_cast(createCond(cond)); - + cond = createCond(cond); if (cond == nullptr) { return SCE_KERNEL_ERROR_EINVAL; } @@ -668,7 +675,7 @@ int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) { } int PS4_SYSV_ABI scePthreadCondTimedwait(ScePthreadCond* cond, ScePthreadMutex* mutex, u64 usec) { - cond = static_cast(createCond(cond)); + cond = createCond(cond); if (cond == nullptr) { return SCE_KERNEL_ERROR_EINVAL; } @@ -1032,9 +1039,9 @@ int PS4_SYSV_ABI scePthreadCondSignal(ScePthreadCond* cond) { } int PS4_SYSV_ABI scePthreadCondWait(ScePthreadCond* cond, ScePthreadMutex* mutex) { - if (cond == nullptr || *cond == nullptr) { - // return SCE_KERNEL_ERROR_EINVAL; - cond = static_cast(createCond(cond)); // check this. Kero Blaster. + cond = createCond(cond); + if (cond == nullptr) { + return SCE_KERNEL_ERROR_EINVAL; } if (mutex == nullptr || *mutex == nullptr) { return SCE_KERNEL_ERROR_EINVAL; @@ -1074,7 +1081,7 @@ int PS4_SYSV_ABI scePthreadCondattrDestroy(ScePthreadCondattr* attr) { } int PS4_SYSV_ABI scePthreadMutexTrylock(ScePthreadMutex* mutex) { - mutex = reinterpret_cast(createMutex(mutex)); + mutex = createMutex(mutex); if (mutex == nullptr) { return ORBIS_KERNEL_ERROR_EINVAL; } @@ -1250,7 +1257,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("4qGrR6eoP9Y", "libkernel", 1, "libkernel", 1, 1, scePthreadDetach); LIB_FUNCTION("3PtV6p3QNX4", "libkernel", 1, "libkernel", 1, 1, scePthreadEqual); LIB_FUNCTION("7Xl257M4VNI", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_equal); - LIB_FUNCTION("7Xl257M4VNI", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_join); + LIB_FUNCTION("h9CcP3J0oVM", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_join); LIB_FUNCTION("aI+OeCz8xrQ", "libkernel", 1, "libkernel", 1, 1, scePthreadSelf); LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self); @@ -1331,6 +1338,4 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { SemaphoreSymbolsRegister(sym); } - - } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/thread_management.h b/src/core/libraries/kernel/thread_management.h index edd6d539d..6452bad08 100644 --- a/src/core/libraries/kernel/thread_management.h +++ b/src/core/libraries/kernel/thread_management.h @@ -10,7 +10,6 @@ #include #include #include "common/types.h" -#include namespace Core::Loader { class SymbolsResolver; diff --git a/src/core/libraries/kernel/threads/keys.cpp b/src/core/libraries/kernel/threads/keys.cpp index 009ed4986..10a81855b 100644 --- a/src/core/libraries/kernel/threads/keys.cpp +++ b/src/core/libraries/kernel/threads/keys.cpp @@ -1,10 +1,11 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include "common/logging/log.h" #include "core/libraries/error_codes.h" +#include "core/libraries/kernel/threads/threads.h" #include "core/libraries/libs.h" -#include "threads.h" namespace Libraries::Kernel { @@ -25,6 +26,7 @@ bool PthreadKeys::CreateKey(int* key, PthreadKeyDestructor destructor) { return false; } + bool PthreadKeys::GetKey(int key, int thread_id, void** data) { std::scoped_lock lk{m_mutex}; @@ -88,7 +90,6 @@ void* PS4_SYSV_ABI scePthreadGetspecific(OrbisPthreadKey key) { } int PS4_SYSV_ABI scePthreadSetspecific(OrbisPthreadKey key, /* const*/ void* value) { - auto id = std::this_thread::get_id(); int thread_id = *(unsigned*)&id; @@ -99,4 +100,4 @@ int PS4_SYSV_ABI scePthreadSetspecific(OrbisPthreadKey key, /* const*/ void* val return ORBIS_OK; } -} // namespace Libraries::Kernel \ No newline at end of file +} // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/rwlock.cpp b/src/core/libraries/kernel/threads/rwlock.cpp index 0f2e90a44..87271fe21 100644 --- a/src/core/libraries/kernel/threads/rwlock.cpp +++ b/src/core/libraries/kernel/threads/rwlock.cpp @@ -34,10 +34,23 @@ int PS4_SYSV_ABI posix_pthread_rwlock_init(OrbisPthreadRwlock* rwlock, return ORBIS_OK; } -int PS4_SYSV_ABI posix_pthread_rwlock_rdlock(OrbisPthreadRwlock* rwlock) { - if (*rwlock == nullptr) { - posix_pthread_rwlock_init(rwlock, nullptr, nullptr); +OrbisPthreadRwlock* createRwlock(OrbisPthreadRwlock* rwlock) { + if (rwlock == nullptr || *rwlock != nullptr) { + return rwlock; } + static std::mutex mutex; + std::scoped_lock lk{mutex}; + if (*rwlock != nullptr) { + return rwlock; + } + const VAddr addr = std::bit_cast(rwlock); + const auto name = fmt::format("rwlock{:#x}", addr); + posix_pthread_rwlock_init(rwlock, nullptr, name.c_str()); + return rwlock; +} + +int PS4_SYSV_ABI posix_pthread_rwlock_rdlock(OrbisPthreadRwlock* rwlock) { + rwlock = createRwlock(rwlock); int result = pthread_rwlock_rdlock(&(*rwlock)->pth_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_rdlock: error = {}", result); @@ -72,6 +85,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_timedwrlock() { } int PS4_SYSV_ABI posix_pthread_rwlock_tryrdlock(OrbisPthreadRwlock* rwlock) { + rwlock = createRwlock(rwlock); + if (rwlock == nullptr) { + return ORBIS_KERNEL_ERROR_EINVAL; + } int result = pthread_rwlock_tryrdlock(&(*rwlock)->pth_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_tryrdlock: error = {}", result); @@ -80,6 +97,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_tryrdlock(OrbisPthreadRwlock* rwlock) { } int PS4_SYSV_ABI posix_pthread_rwlock_trywrlock(OrbisPthreadRwlock* rwlock) { + rwlock = createRwlock(rwlock); + if (rwlock == nullptr) { + return ORBIS_KERNEL_ERROR_EINVAL; + } int result = pthread_rwlock_trywrlock(&(*rwlock)->pth_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_trywrlock: error = {}", result); @@ -88,6 +109,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_trywrlock(OrbisPthreadRwlock* rwlock) { } int PS4_SYSV_ABI posix_pthread_rwlock_unlock(OrbisPthreadRwlock* rwlock) { + rwlock = createRwlock(rwlock); + if (rwlock == nullptr) { + return ORBIS_KERNEL_ERROR_EINVAL; + } int result = pthread_rwlock_unlock(&(*rwlock)->pth_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_unlock: error = {}", result); @@ -96,6 +121,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_unlock(OrbisPthreadRwlock* rwlock) { } int PS4_SYSV_ABI posix_pthread_rwlock_wrlock(OrbisPthreadRwlock* rwlock) { + rwlock = createRwlock(rwlock); + if (rwlock == nullptr) { + return ORBIS_KERNEL_ERROR_EINVAL; + } int result = pthread_rwlock_wrlock(&(*rwlock)->pth_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_wrlock: error = {}", result); @@ -274,9 +303,7 @@ int PS4_SYSV_ABI scePthreadRwlockUnlock(OrbisPthreadRwlock* rwlock) { } int PS4_SYSV_ABI scePthreadRwlockWrlock(OrbisPthreadRwlock* rwlock) { - if (rwlock == nullptr || *rwlock == nullptr) { - return ORBIS_KERNEL_ERROR_EINVAL; - } + rwlock = createRwlock(rwlock); int result = pthread_rwlock_wrlock(&(*rwlock)->pth_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "scePthreadRwlockWrlock: error = {}", result); diff --git a/src/core/libraries/kernel/threads/semaphore.cpp b/src/core/libraries/kernel/threads/semaphore.cpp index 5ec3b3be5..e6fc667d2 100644 --- a/src/core/libraries/kernel/threads/semaphore.cpp +++ b/src/core/libraries/kernel/threads/semaphore.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include #include "common/assert.h" @@ -17,8 +18,8 @@ using ListBaseHook = class Semaphore { public: - Semaphore(s32 init_count, s32 max_count, bool is_fifo) - : token_count{init_count}, max_count{max_count}, is_fifo{is_fifo} {} + Semaphore(s32 init_count, s32 max_count, const char* name, bool is_fifo) + : name{name}, token_count{init_count}, max_count{max_count}, is_fifo{is_fifo} {} bool Wait(bool can_block, s32 need_count, u64* timeout) { if (HasAvailableTokens(need_count)) { @@ -131,6 +132,7 @@ private: boost::intrusive::list, boost::intrusive::constant_time_size>; WaitingThreads wait_list; + std::string name; std::atomic token_count; std::mutex mutex; s32 max_count; @@ -145,7 +147,7 @@ s32 PS4_SYSV_ABI sceKernelCreateSema(OrbisKernelSema* sem, const char* pName, u3 LOG_ERROR(Lib_Kernel, "Semaphore creation parameters are invalid!"); return ORBIS_KERNEL_ERROR_EINVAL; } - *sem = new Semaphore(initCount, maxCount, attr == 1); + *sem = new Semaphore(initCount, maxCount, pName, attr == 1); return ORBIS_OK; } diff --git a/src/core/libraries/kernel/time_management.cpp b/src/core/libraries/kernel/time_management.cpp index e969015ca..eaf2c535f 100644 --- a/src/core/libraries/kernel/time_management.cpp +++ b/src/core/libraries/kernel/time_management.cpp @@ -63,9 +63,13 @@ int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) { } int PS4_SYSV_ABI posix_usleep(u32 microseconds) { - ASSERT(microseconds >= 1000); +#ifdef _WIN64 + ASSERT(microseconds >= 1000 || microseconds == 0); std::this_thread::sleep_for(std::chrono::microseconds(microseconds)); return 0; +#else + return usleep(microseconds); +#endif } u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) { @@ -152,6 +156,7 @@ int PS4_SYSV_ABI gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) { } s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) { +#ifdef _WIN64 ASSERT(tz); static int tzflag = 0; if (!tzflag) { @@ -160,6 +165,13 @@ s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) { } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; +#else + struct timezone tzz; + struct timeval tv; + gettimeofday(&tv, &tzz); + tz->tz_dsttime = tzz.tz_dsttime; + tz->tz_minuteswest = tzz.tz_minuteswest; +#endif return ORBIS_OK; } @@ -176,6 +188,7 @@ void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, gettimeofday); LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, gettimeofday); LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep); + LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep); LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep); LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep); LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, sceKernelSleep); diff --git a/src/core/libraries/libs.h b/src/core/libraries/libs.h index 56ff4fb53..72eca312c 100644 --- a/src/core/libraries/libs.h +++ b/src/core/libraries/libs.h @@ -24,15 +24,13 @@ template { static R PS4_SYSV_ABI wrap(Args... args) { if (std::string_view(name.value) != "scePthreadEqual" && - std::string_view(name.value) != "sceUserServiceGetEvent" && - !std::string_view(name.value).contains("mutex") && - !std::string_view(name.value).contains("Mutex")) { - // LOG_WARNING(Core_Linker, "Function {} called", name.value); + std::string_view(name.value) != "sceUserServiceGetEvent") { + LOG_WARNING(Core_Linker, "Function {} called", name.value); } if constexpr (std::is_same_v || std::is_same_v) { - const int ret = f(args...); + const u32 ret = f(args...); if (ret != 0 && std::string_view(name.value) != "scePthreadEqual") { - LOG_WARNING(Core_Linker, "Function {} returned {}", name.value, ret); + LOG_WARNING(Core_Linker, "Function {} returned {:#x}", name.value, ret); } return ret; } @@ -44,7 +42,7 @@ struct wrapper_impl { template constexpr auto wrapper = wrapper_impl::wrap; -//#define W(foo) wrapper<#foo, decltype(&foo), foo> +// #define W(foo) wrapper<#foo, decltype(&foo), foo> #define W(foo) foo #define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \ diff --git a/src/core/libraries/save_data/savedata.cpp b/src/core/libraries/save_data/savedata.cpp index e5db45b60..a2086af29 100644 --- a/src/core/libraries/save_data/savedata.cpp +++ b/src/core/libraries/save_data/savedata.cpp @@ -733,4 +733,4 @@ void RegisterlibSceSaveData(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("AuTE0gFxZCI", "libSceSaveData", 1, "libSceSaveData", 1, 1, Func_02E4C4D201716422); }; -} // namespace Libraries::SaveData \ No newline at end of file +} // namespace Libraries::SaveData diff --git a/src/core/linker.h b/src/core/linker.h index f958e20c7..bc12de7d0 100644 --- a/src/core/linker.h +++ b/src/core/linker.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include "core/module.h" diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a735400ad..21261d2d6 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -91,6 +91,7 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M // When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed // flag so we will take the branch that searches for free (or reserved) mappings. virtual_addr = (virtual_addr == 0) ? impl.VirtualBase() : virtual_addr; + alignment = alignment > 0 ? alignment : 16_KB; VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr; SCOPE_EXIT { @@ -141,7 +142,7 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M } int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, - MemoryMapFlags flags, void* fd, size_t offset) { + MemoryMapFlags flags, uintptr_t fd, size_t offset) { ASSERT(virtual_addr == 0); virtual_addr = impl.VirtualBase(); const size_t size_aligned = Common::AlignUp(size, 16_KB); @@ -155,7 +156,7 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem // Map the file. const VAddr mapped_addr = it->second.base; - impl.MapFile(mapped_addr, Common::AlignDown(size, 4_KB), offset, fd); + impl.MapFile(mapped_addr, size, offset, fd); // Add virtual memory area auto& new_vma = AddMapping(mapped_addr, size_aligned); diff --git a/src/core/memory.h b/src/core/memory.h index 711fdc609..d7ec6fc6b 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -86,7 +86,7 @@ struct VirtualMemoryArea { MemoryProt prot = MemoryProt::NoAccess; bool disallow_merge = false; std::string name = ""; - void* fd = nullptr; + uintptr_t fd = 0; bool Contains(VAddr addr, size_t size) const { return addr >= base && (addr + size) < (base + this->size); @@ -134,7 +134,7 @@ public: bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0); int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, - MemoryMapFlags flags, void* fd, size_t offset); + MemoryMapFlags flags, uintptr_t fd, size_t offset); void UnmapMemory(VAddr virtual_addr, size_t size); diff --git a/src/core/module.h b/src/core/module.h index 4deea6557..d4079c7a3 100644 --- a/src/core/module.h +++ b/src/core/module.h @@ -17,7 +17,7 @@ static constexpr size_t SCE_DBG_NUM_FINGERPRINT = 20; struct OrbisKernelModuleSegmentInfo { VAddr address; - u64 size; + u32 size; s32 prot; }; diff --git a/src/core/tls.cpp b/src/core/tls.cpp index a6eb36fa4..cf7e15846 100644 --- a/src/core/tls.cpp +++ b/src/core/tls.cpp @@ -125,7 +125,8 @@ static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGe const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); c.putSeg(fs); c.mov(target_reg, qword[SelfInTcbheadOffset]); // Load self member pointer of tcbhead_t. - c.add(target_reg, SpecificFirstBlockOffset + sizeof(uintptr_t) + slot * PthreadKeyDataSize); + c.add(target_reg, SpecificFirstBlockOffset + sizeof(uintptr_t) * 2 + slot * PthreadKeyDataSize); + c.mov(target_reg, qword[target_reg]); c.jmp(code + total_size); // Return to the instruction right after the mov. } diff --git a/src/emulator.cpp b/src/emulator.cpp index 25fa4ee97..95fbbfa8b 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -94,11 +94,11 @@ void Emulator::Run(const std::filesystem::path& file) { if (std::filesystem::is_directory(sce_module_folder)) { for (const auto& entry : std::filesystem::directory_iterator(sce_module_folder)) { if (entry.path().filename() == "libc.prx" || - entry.path().filename() == "libSceFios2.prx" /*|| + entry.path().filename() == "libSceFios2.prx" || entry.path().filename() == "libSceAudioLatencyEstimation.prx" || entry.path().filename() == "libSceJobManager.prx" || entry.path().filename() == "libSceNpToolkit2.prx" || - entry.path().filename() == "libSceS3DConversion.prx"*/) { + entry.path().filename() == "libSceS3DConversion.prx") { found = true; LOG_INFO(Loader, "Loading {}", entry.path().string().c_str()); linker->LoadModule(entry.path()); @@ -115,15 +115,10 @@ void Emulator::Run(const std::filesystem::path& file) { std::jthread([this](std::stop_token stop_token) { linker->Execute(); }); // Begin main window loop until the application exits -<<<<<<< HEAD - static constexpr std::chrono::milliseconds FlipPeriod{16}; -======= static constexpr std::chrono::microseconds FlipPeriod{10}; ->>>>>>> 31bd502764f1ac975fc55bd2a788a7e08a9f34ec while (window.isOpen()) { window.waitEvent(); - std::this_thread::sleep_for(FlipPeriod); Libraries::VideoOut::Flip(FlipPeriod); Libraries::VideoOut::Vblank(); FRAME_END; @@ -135,7 +130,8 @@ void Emulator::Run(const std::filesystem::path& file) { void Emulator::LoadSystemModules(const std::filesystem::path& file) { const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir); for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) { - if (entry.path().filename() == "libSceNgs2.sprx") { + if (entry.path().filename() == "libSceNgs2.sprx" || + entry.path().filename() == "libSceLibcInternal.sprx") { LOG_INFO(Loader, "Loading {}", entry.path().string().c_str()); linker->LoadModule(entry.path()); } diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index e0cf86aa5..833794588 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include "common/assert.h" #include "common/debug.h" #include "common/thread.h" @@ -22,8 +23,6 @@ Liverpool::Liverpool() { Liverpool::~Liverpool() { process_thread.request_stop(); - num_submits = -1; - num_submits.notify_one(); process_thread.join(); } @@ -31,8 +30,10 @@ void Liverpool::Process(std::stop_token stoken) { Common::SetCurrentThreadName("GPU_CommandProcessor"); while (!stoken.stop_requested()) { - num_submits.wait(0); - + { + std::unique_lock lk{submit_mutex}; + submit_cv.wait(lk, stoken, [this] { return num_submits != 0; }); + } if (stoken.stop_requested()) { break; } @@ -67,7 +68,8 @@ void Liverpool::Process(std::stop_token stoken) { } if (submit_done) { - num_submits.notify_all(); + std::scoped_lock lk{submit_mutex}; + submit_cv.notify_all(); submit_done = false; } } @@ -76,9 +78,8 @@ void Liverpool::Process(std::stop_token stoken) { void Liverpool::WaitGpuIdle() { RENDERER_TRACE; - while (const auto old = num_submits.load()) { - num_submits.wait(old); - } + std::unique_lock lk{submit_mutex}; + submit_cv.wait(lk, [this] { return num_submits == 0; }); } Liverpool::Task Liverpool::ProcessCeUpdate(std::span ccb) { @@ -369,7 +370,6 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::span(opcode), count); } - dcb = dcb.subspan(header->type3.NumWords() + 1); } @@ -415,8 +415,9 @@ void Liverpool::SubmitGfx(std::span dcb, std::span ccb) { queue.submits.emplace(task.handle); } + std::scoped_lock lk{submit_mutex}; ++num_submits; - num_submits.notify_one(); + submit_cv.notify_one(); } void Liverpool::SubmitAsc(u32 vqid, std::span acb) { @@ -429,8 +430,9 @@ void Liverpool::SubmitAsc(u32 vqid, std::span acb) { queue.submits.emplace(task.handle); } + std::scoped_lock lk{submit_mutex}; ++num_submits; - num_submits.notify_one(); + submit_cv.notify_one(); } } // namespace AmdGpu diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 35a0917ae..dd7179900 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -10,6 +10,7 @@ #include "video_core/amdgpu/pixel_format.h" #include +#include #include #include #include @@ -865,13 +866,15 @@ public: void SubmitAsc(u32 vqid, std::span acb); void WaitGpuIdle(); + bool IsGpuIdle() const { return num_submits == 0; } void NotifySubmitDone() { + std::scoped_lock lk{submit_mutex}; submit_done = true; - num_submits.notify_all(); + submit_cv.notify_all(); } void BindRasterizer(Vulkan::Rasterizer* rasterizer_) { @@ -939,7 +942,9 @@ private: Vulkan::Rasterizer* rasterizer{}; std::jthread process_thread{}; - std::atomic num_submits{}; + u32 num_submits{}; + std::mutex submit_mutex; + std::condition_variable_any submit_cv; std::atomic submit_done{}; };