mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-01-03 10:10:06 -06:00
Linux support. (#54)
* Initial Linux attempt. * Add clang toolchain & make tools compile. * vcpkg as submodule. * First implementation of IO rewrite. (#31) * Fix directory iteration resolving symlinks. * Refactor kernel objects to be lock-free. * Implement guest critical sections using std::atomic. * Make D3D12 support optional. (#33) * Make D3D12 support optional. * Update ShaderRecomp, fix macros. * Replace QueryPerformanceCounter. (#35) * Add Linux home path for GetUserPath(). (#36) * Cross-platform Sleep. (#37) * Add mmap implementations for virtual allocation. (#38) * Cross-platform TLS. (#34) * Cross-platform TLS. * Fix front() to back(), use Mutex. * Fix global variable namings. --------- Co-authored-by: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> * Unicode support. (#39) * Replace CreateDirectoryA with Unicode version. * Cross platform thread implementation. (#41) * Cross-platform thread implementation. * Put set thread name calls behind a Win32 macro. * Cross-platform semaphore implementation. (#43) * xam: use SDL for keyboard input * Cross-platform atomic operations. (#44) * Cross-platform spin lock implementation. * Cross-platform reference counting. * Cross-platform event implementation. (#47) * Compiling and running on Linux. (#49) * Current work trying to get it to compile. * Update vcpkg.json baseline. * vcpkg, memory mapped file. * Bitscan forward. * Fix localtime_s. * FPS patches high res clock. * Rename Window to GameWindow. Fix guest pointers. * GetCurrentThreadID gone. * Code cache pointers, RenderWindow type. * Add Linux stubs. * Refactor Config. * Fix paths. * Add linux-release config. * FS fixes. * Fix Windows compilation errors & unicode converter crash. * Rename physical memory allocation functions to not clash with X11. * Fix NULL character being added on RtlMultiByteToUnicodeN. * Use std::exit. * Add protection to memory on Linux. * Convert majority of dependencies to submodules. (#48) * Convert majority of dependencies to submodules. * Don't compile header-only libraries. * Fix a few incorrect data types. * Fix config directory. * Unicode fixes & sizeof asserts. * Change the exit function to not call static destructors. * Fix files picker. * Add RelWithDebInfo preset for Linux. * Implement OS Restart on Linux. (#50) --------- Co-authored-by: Dario <dariosamo@gmail.com> * Update PowerRecomp. * Add Env Var detection for VCPKG_ROOT, add DLC detection. * Use error code version on DLC directory iterator. * Set D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED flag. * Linux flatpak. (#51) * Add flatpak support. * Add game install directory override for flatpak. * Flatpak'ing. * Flatpak it some more. * We flat it, we pak it. * Flatpak'd. * The Marvelous Misadventures of Flatpak. * Attempt to change logic of NFD and show error. * Flattenpakken. * Use game install directory instead of current path. * Attempt to fix line endings. * Update io.github.hedge_dev.unleashedrecomp.json * Fix system time query implementation. * Add Present Wait to Vulkan to improve frame pacing and reduce latency. (#53) * Add present wait support to Vulkan. * Default to triple buffering if presentWait is supported. * Bracey fellas. * Update paths.h * SDL2 audio (again). (#52) * Implement SDL2 audio (again). * Call timeBeginPeriod/timeEndPeriod. * Replace miniaudio with SDL mixer. * Queue audio samples in a separate thread. * Enable CMake option override policy & fix compilation error. * Fix compilation error on Linux. * Fix but also trim shared strings. * Wayland support. (#55) * Make channel index a global variable in embedded player. * Fix SDL Audio selection for OGG on Flatpak. * Minor installer wizard fixes. * Fix compilation error. * Yield in model consumer and pipeline compiler threads. * Special case Sleep(0) to yield on Linux. * Add App Id hint. * Correct implementation for auto reset events. (#57) --------- Co-authored-by: Dario <dariosamo@gmail.com> Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com>
This commit is contained in:
@@ -27,11 +27,12 @@ GuestThreadContext::GuestThreadContext(uint32_t cpuNumber)
|
||||
*(thread + 0x10C) = cpuNumber;
|
||||
|
||||
*(uint32_t*)(thread + PCR_SIZE + 0x10) = 0xFFFFFFFF; // that one TLS entry that felt quirky
|
||||
*(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = ByteSwap(GetCurrentThreadId()); // thread id
|
||||
*(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = ByteSwap(GuestThread::GetCurrentThreadId()); // thread id
|
||||
|
||||
ppcContext.fn = (uint8_t*)g_codeCache.bucket;
|
||||
ppcContext.r1.u64 = g_memory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer
|
||||
ppcContext.r13.u64 = g_memory.MapVirtual(thread);
|
||||
ppcContext.fpscr.loadFromHost();
|
||||
|
||||
assert(GetPPCContext() == nullptr);
|
||||
SetPPCContext(ppcContext);
|
||||
@@ -42,42 +43,84 @@ GuestThreadContext::~GuestThreadContext()
|
||||
g_userHeap.Free(thread);
|
||||
}
|
||||
|
||||
DWORD GuestThread::Start(uint32_t function)
|
||||
static void GuestThreadFunc(GuestThreadHandle* hThread)
|
||||
{
|
||||
const GuestThreadParameter parameter{ function };
|
||||
return Start(parameter);
|
||||
hThread->suspended.wait(true);
|
||||
GuestThread::Start(hThread->params);
|
||||
}
|
||||
|
||||
DWORD GuestThread::Start(const GuestThreadParameter& parameter)
|
||||
GuestThreadHandle::GuestThreadHandle(const GuestThreadParams& params)
|
||||
: params(params), suspended((params.flags & 0x1) != 0), thread(GuestThreadFunc, this)
|
||||
{
|
||||
const auto procMask = (uint8_t)(parameter.flags >> 24);
|
||||
}
|
||||
|
||||
GuestThreadHandle::~GuestThreadHandle()
|
||||
{
|
||||
if (thread.joinable())
|
||||
thread.join();
|
||||
}
|
||||
|
||||
uint32_t GuestThreadHandle::Wait(uint32_t timeout)
|
||||
{
|
||||
assert(timeout == INFINITE);
|
||||
|
||||
if (thread.joinable())
|
||||
thread.join();
|
||||
|
||||
return STATUS_WAIT_0;
|
||||
}
|
||||
|
||||
uint32_t GuestThread::Start(const GuestThreadParams& params)
|
||||
{
|
||||
const auto procMask = (uint8_t)(params.flags >> 24);
|
||||
const auto cpuNumber = procMask == 0 ? 0 : 7 - std::countl_zero(procMask);
|
||||
|
||||
GuestThreadContext ctx(cpuNumber);
|
||||
ctx.ppcContext.r3.u64 = parameter.value;
|
||||
ctx.ppcContext.r3.u64 = params.value;
|
||||
|
||||
GuestCode::Run(g_codeCache.Find(parameter.function), &ctx.ppcContext, g_memory.Translate(0));
|
||||
reinterpret_cast<PPCFunc*>(g_codeCache.Find(params.function))(ctx.ppcContext, reinterpret_cast<uint8_t*>(g_memory.base));
|
||||
|
||||
return (DWORD)ctx.ppcContext.r3.u64;
|
||||
return ctx.ppcContext.r3.u32;
|
||||
}
|
||||
|
||||
DWORD HostThreadStart(void* pParameter)
|
||||
static uint32_t GetThreadId(const std::thread::id& id)
|
||||
{
|
||||
auto* parameter = static_cast<GuestThreadParameter*>(pParameter);
|
||||
const auto result = GuestThread::Start(*parameter);
|
||||
|
||||
delete parameter;
|
||||
return result;
|
||||
if constexpr (sizeof(id) == 4)
|
||||
return *reinterpret_cast<const uint32_t*>(&id);
|
||||
else
|
||||
return XXH32(&id, sizeof(id), 0);
|
||||
}
|
||||
|
||||
HANDLE GuestThread::Start(uint32_t function, uint32_t parameter, uint32_t flags, LPDWORD threadId)
|
||||
GuestThreadHandle* GuestThread::Start(const GuestThreadParams& params, uint32_t* threadId)
|
||||
{
|
||||
const auto hostCreationFlags = (flags & 1) != 0 ? CREATE_SUSPENDED : 0;
|
||||
//return CreateThread(nullptr, 0, Start, (void*)((uint64_t(parameter) << 32) | function), suspended ? CREATE_SUSPENDED : 0, threadId);
|
||||
return CreateThread(nullptr, 0, HostThreadStart, new GuestThreadParameter{ function, parameter, flags }, hostCreationFlags, threadId);
|
||||
auto hThread = CreateKernelObject<GuestThreadHandle>(params);
|
||||
|
||||
if (threadId != nullptr)
|
||||
*threadId = GetThreadId(hThread->thread.get_id());
|
||||
|
||||
return hThread;
|
||||
}
|
||||
|
||||
void GuestThread::SetThreadName(uint32_t id, const char* name)
|
||||
uint32_t GuestThread::GetCurrentThreadId()
|
||||
{
|
||||
return GetThreadId(std::this_thread::get_id());
|
||||
}
|
||||
|
||||
void GuestThread::SetLastError(uint32_t error)
|
||||
{
|
||||
auto* thread = (char*)g_memory.Translate(GetPPCContext()->r13.u32);
|
||||
if (*(uint32_t*)(thread + 0x150))
|
||||
{
|
||||
// Program doesn't want errors
|
||||
return;
|
||||
}
|
||||
|
||||
// TEB + 0x160 : Win32LastError
|
||||
*(uint32_t*)(thread + TEB_OFFSET + 0x160) = ByteSwap(error);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void GuestThread::SetThreadName(uint32_t threadId, const char* name)
|
||||
{
|
||||
#pragma pack(push,8)
|
||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
@@ -94,7 +137,7 @@ void GuestThread::SetThreadName(uint32_t id, const char* name)
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = id;
|
||||
info.dwThreadID = threadId;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
@@ -105,41 +148,31 @@ void GuestThread::SetThreadName(uint32_t id, const char* name)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void GuestThread::SetLastError(DWORD error)
|
||||
{
|
||||
auto* thread = (char*)g_memory.Translate(GetPPCContext()->r13.u32);
|
||||
if (*(DWORD*)(thread + 0x150))
|
||||
{
|
||||
// Program doesn't want errors
|
||||
return;
|
||||
}
|
||||
|
||||
// TEB + 0x160 : Win32LastError
|
||||
*(DWORD*)(thread + TEB_OFFSET + 0x160) = ByteSwap(error);
|
||||
}
|
||||
|
||||
PPCContext* GuestThread::Invoke(uint32_t address)
|
||||
{
|
||||
auto* ctx = GetPPCContext();
|
||||
GuestCode::Run(g_codeCache.Find(address), ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SetThreadNameImpl(uint32_t a1, uint32_t threadId, uint32_t* name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
GuestThread::SetThreadName(threadId, (const char*)g_memory.Translate(ByteSwap(*name)));
|
||||
#endif
|
||||
}
|
||||
|
||||
int GetThreadPriorityImpl(uint32_t hThread)
|
||||
int GetThreadPriorityImpl(GuestThreadHandle* hThread)
|
||||
{
|
||||
return GetThreadPriority((HANDLE)hThread);
|
||||
#ifdef _WIN32
|
||||
return GetThreadPriority(hThread == GetKernelObject(CURRENT_THREAD_HANDLE) ? GetCurrentThread() : hThread->thread.native_handle());
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD SetThreadIdealProcessorImpl(uint32_t hThread, DWORD dwIdealProcessor)
|
||||
uint32_t SetThreadIdealProcessorImpl(GuestThreadHandle* hThread, uint32_t dwIdealProcessor)
|
||||
{
|
||||
return SetThreadIdealProcessor((HANDLE)hThread, dwIdealProcessor);
|
||||
#ifdef _WIN32
|
||||
return SetThreadIdealProcessor(hThread == GetKernelObject(CURRENT_THREAD_HANDLE) ? GetCurrentThread() : hThread->thread.native_handle(), dwIdealProcessor);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl);
|
||||
|
||||
Reference in New Issue
Block a user