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:
Skyth (Asilkan)
2024-12-21 00:44:05 +03:00
committed by GitHub
parent f547c7ca6d
commit 67633917bf
109 changed files with 3373 additions and 2850 deletions

View File

@@ -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);