diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index a112a28a6..241da1038 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -28,6 +28,7 @@ $end_info$ #include #include "Windows/Common/Allocator.h" +#include "Windows/Common/EnvironmentVariablesHandling.h" #include "Common/CallRetStack.h" #include "Common/JITGuardPage.h" #include "Common/Config.h" @@ -595,6 +596,8 @@ NTSTATUS ProcessInit() { const bool IsWine = !!GetProcAddress(NtDll, "wine_get_version"); OvercommitTracker.emplace(IsWine); + FEX::Windows::SetupEnvironmentVariableValues(NtDll); + FEX::Windows::Allocator::SetupHooks(NtDll); { diff --git a/Source/Windows/Common/CMakeLists.txt b/Source/Windows/Common/CMakeLists.txt index d7e2da9c7..3a0a71c07 100644 --- a/Source/Windows/Common/CMakeLists.txt +++ b/Source/Windows/Common/CMakeLists.txt @@ -9,6 +9,7 @@ target_include_directories(CommonWindowsRuntime PRIVATE "${CMAKE_SOURCE_DIR}/Sou add_library(CommonWindows STATIC Allocator.cpp CPUFeatures.cpp + EnvironmentVariablesHandling.cpp SHMStats.cpp InvalidationTracker.cpp ImageTracker.cpp diff --git a/Source/Windows/Common/EnvironmentVariablesHandling.cpp b/Source/Windows/Common/EnvironmentVariablesHandling.cpp new file mode 100644 index 000000000..9d8a0483b --- /dev/null +++ b/Source/Windows/Common/EnvironmentVariablesHandling.cpp @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +#include +#include +#include +#include + +namespace FEX::Windows { +void SetupEnvironmentVariableValues(HMODULE NtDll) { + auto Sym = GetProcAddress(NtDll, "__wine_set_unix_env"); + + // On an ARM system we are expecting uncached memory to have marked overhead due to atomic memory usage. + // If `tu_override_uncached_as_cache_coherent` isn't already controlled by the user, then set it here. + // This lets the `turnip` mesa driver allocate uncached memory types as cached coherent instead if the hardware supports it. + // + // The only downside for this approach is that the GPU /may/ need to snoop CPU cachelines which could add some additional load + // on to the GPU side, but is unlikely to matter due to x86 emulation using excessive load-acquire/store-release semantic memory operations. + // + // Other UMA ARM platforms will run in to the same problem, with their own workarounds: + // - NVIDIA Tegra/Spark: Their proprietary driver always maps uncached as cached-coherent. + // - Windows Snapdragon: Same as Tegra + // - Asahi,Mali,PowerVR,Exynos,etc: Unknown behaviour + // + // This `__wine_set_unix_env` path may also not be long-term viable. + // Make sure to communicate with the Wine/Proton people if this interface is expected to change! + // A /possible/ workaround for Proton would be to set the environment variable in the launch script. + // - That would have the downside that arm64 native Windows applications would get workaround set, which isn't strictly necessary. + if (Sym && getenv("tu_override_uncached_as_cache_coherent") == nullptr) { + auto WineSetEnv = reinterpret_cast(Sym); + WineSetEnv("tu_override_uncached_as_cache_coherent", "true"); + } +} +} // namespace FEX::Windows diff --git a/Source/Windows/Common/EnvironmentVariablesHandling.h b/Source/Windows/Common/EnvironmentVariablesHandling.h new file mode 100644 index 000000000..bb7aeecfc --- /dev/null +++ b/Source/Windows/Common/EnvironmentVariablesHandling.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +#pragma once +#include + +namespace FEX::Windows { +void SetupEnvironmentVariableValues(HMODULE NtDll); +} diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index e4772ffea..d5ba1853e 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -29,6 +29,7 @@ $end_info$ #include #include "Windows/Common/Allocator.h" +#include "Windows/Common/EnvironmentVariablesHandling.h" #include "Common/CallRetStack.h" #include "Common/JITGuardPage.h" #include "Common/Config.h" @@ -563,6 +564,8 @@ void BTCpuProcessInit() { WineUnixCall = *reinterpret_cast(Sym); } + FEX::Windows::SetupEnvironmentVariableValues(NtDll); + // wow64.dll will only initialise the cross-process queue if this is set GetTLS().Wow64Info().CpuFlags = WOW64_CPUFLAGS_SOFTWARE; diff --git a/Source/Windows/include/wine/unixlib.h b/Source/Windows/include/wine/unixlib.h index 1b8f39929..fd77405b6 100644 --- a/Source/Windows/include/wine/unixlib.h +++ b/Source/Windows/include/wine/unixlib.h @@ -11,6 +11,8 @@ extern "C" { typedef UINT64 unixlib_handle_t; +extern NTSTATUS(WINAPI* __wine_set_unix_env)(const char*, const char*); + extern NTSTATUS(WINAPI* __wine_unix_call_dispatcher)(unixlib_handle_t, unsigned int, void*); static inline NTSTATUS __wine_unix_call(unixlib_handle_t handle, unsigned int code, void* args) {