dxvk: refactor to better support Darwin and Linux
- Move the synchronization primitive changes to their own patch, so it can be applied conditionally on Darwin. Also, document why this change is needed; and - Refactor how `src` is handled to support allowing Darwin and Linux to diverge in case the Darwin patches do not apply to the latest version. This should address some post-merger concerns that were raised about Darwin’s blocking updates for Linux.
This commit is contained in:
parent
31c068329c
commit
e2369cb9c9
186
pkgs/misc/dxvk/darwin-thread-primitives.patch
Normal file
186
pkgs/misc/dxvk/darwin-thread-primitives.patch
Normal file
@ -0,0 +1,186 @@
|
||||
diff --git a/src/util/thread.h b/src/util/thread.h
|
||||
index 28aeca8a..db5c9913 100644
|
||||
--- a/src/util/thread.h
|
||||
+++ b/src/util/thread.h
|
||||
@@ -149,178 +149,8 @@ namespace dxvk {
|
||||
}
|
||||
}
|
||||
|
||||
-
|
||||
- /**
|
||||
- * \brief SRW-based mutex implementation
|
||||
- *
|
||||
- * Drop-in replacement for \c std::mutex that uses Win32
|
||||
- * SRW locks, which are implemented with \c futex in wine.
|
||||
- */
|
||||
- class mutex {
|
||||
-
|
||||
- public:
|
||||
-
|
||||
- using native_handle_type = PSRWLOCK;
|
||||
-
|
||||
- mutex() { }
|
||||
-
|
||||
- mutex(const mutex&) = delete;
|
||||
- mutex& operator = (const mutex&) = delete;
|
||||
-
|
||||
- void lock() {
|
||||
- AcquireSRWLockExclusive(&m_lock);
|
||||
- }
|
||||
-
|
||||
- void unlock() {
|
||||
- ReleaseSRWLockExclusive(&m_lock);
|
||||
- }
|
||||
-
|
||||
- bool try_lock() {
|
||||
- return TryAcquireSRWLockExclusive(&m_lock);
|
||||
- }
|
||||
-
|
||||
- native_handle_type native_handle() {
|
||||
- return &m_lock;
|
||||
- }
|
||||
-
|
||||
- private:
|
||||
-
|
||||
- SRWLOCK m_lock = SRWLOCK_INIT;
|
||||
-
|
||||
- };
|
||||
-
|
||||
-
|
||||
- /**
|
||||
- * \brief Recursive mutex implementation
|
||||
- *
|
||||
- * Drop-in replacement for \c std::recursive_mutex that
|
||||
- * uses Win32 critical sections.
|
||||
- */
|
||||
- class recursive_mutex {
|
||||
-
|
||||
- public:
|
||||
-
|
||||
- using native_handle_type = PCRITICAL_SECTION;
|
||||
-
|
||||
- recursive_mutex() {
|
||||
- InitializeCriticalSection(&m_lock);
|
||||
- }
|
||||
-
|
||||
- ~recursive_mutex() {
|
||||
- DeleteCriticalSection(&m_lock);
|
||||
- }
|
||||
-
|
||||
- recursive_mutex(const recursive_mutex&) = delete;
|
||||
- recursive_mutex& operator = (const recursive_mutex&) = delete;
|
||||
-
|
||||
- void lock() {
|
||||
- EnterCriticalSection(&m_lock);
|
||||
- }
|
||||
-
|
||||
- void unlock() {
|
||||
- LeaveCriticalSection(&m_lock);
|
||||
- }
|
||||
-
|
||||
- bool try_lock() {
|
||||
- return TryEnterCriticalSection(&m_lock);
|
||||
- }
|
||||
-
|
||||
- native_handle_type native_handle() {
|
||||
- return &m_lock;
|
||||
- }
|
||||
-
|
||||
- private:
|
||||
-
|
||||
- CRITICAL_SECTION m_lock;
|
||||
-
|
||||
- };
|
||||
-
|
||||
-
|
||||
- /**
|
||||
- * \brief SRW-based condition variable implementation
|
||||
- *
|
||||
- * Drop-in replacement for \c std::condition_variable that
|
||||
- * uses Win32 condition variables on SRW locks.
|
||||
- */
|
||||
- class condition_variable {
|
||||
-
|
||||
- public:
|
||||
-
|
||||
- using native_handle_type = PCONDITION_VARIABLE;
|
||||
-
|
||||
- condition_variable() {
|
||||
- InitializeConditionVariable(&m_cond);
|
||||
- }
|
||||
-
|
||||
- condition_variable(condition_variable&) = delete;
|
||||
-
|
||||
- condition_variable& operator = (condition_variable&) = delete;
|
||||
-
|
||||
- void notify_one() {
|
||||
- WakeConditionVariable(&m_cond);
|
||||
- }
|
||||
-
|
||||
- void notify_all() {
|
||||
- WakeAllConditionVariable(&m_cond);
|
||||
- }
|
||||
-
|
||||
- void wait(std::unique_lock<dxvk::mutex>& lock) {
|
||||
- auto srw = lock.mutex()->native_handle();
|
||||
- SleepConditionVariableSRW(&m_cond, srw, INFINITE, 0);
|
||||
- }
|
||||
-
|
||||
- template<typename Predicate>
|
||||
- void wait(std::unique_lock<dxvk::mutex>& lock, Predicate pred) {
|
||||
- while (!pred())
|
||||
- wait(lock);
|
||||
- }
|
||||
-
|
||||
- template<typename Clock, typename Duration>
|
||||
- std::cv_status wait_until(std::unique_lock<dxvk::mutex>& lock, const std::chrono::time_point<Clock, Duration>& time) {
|
||||
- auto now = Clock::now();
|
||||
-
|
||||
- return (now < time)
|
||||
- ? wait_for(lock, now - time)
|
||||
- : std::cv_status::timeout;
|
||||
- }
|
||||
-
|
||||
- template<typename Clock, typename Duration, typename Predicate>
|
||||
- bool wait_until(std::unique_lock<dxvk::mutex>& lock, const std::chrono::time_point<Clock, Duration>& time, Predicate pred) {
|
||||
- if (pred())
|
||||
- return true;
|
||||
-
|
||||
- auto now = Clock::now();
|
||||
- return now < time && wait_for(lock, now - time, pred);
|
||||
- }
|
||||
-
|
||||
- template<typename Rep, typename Period>
|
||||
- std::cv_status wait_for(std::unique_lock<dxvk::mutex>& lock, const std::chrono::duration<Rep, Period>& timeout) {
|
||||
- auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
|
||||
- auto srw = lock.mutex()->native_handle();
|
||||
-
|
||||
- return SleepConditionVariableSRW(&m_cond, srw, ms.count(), 0)
|
||||
- ? std::cv_status::no_timeout
|
||||
- : std::cv_status::timeout;
|
||||
- }
|
||||
-
|
||||
- template<typename Rep, typename Period, typename Predicate>
|
||||
- bool wait_for(std::unique_lock<dxvk::mutex>& lock, const std::chrono::duration<Rep, Period>& timeout, Predicate pred) {
|
||||
- bool result = pred();
|
||||
-
|
||||
- if (!result && wait_for(lock, timeout) == std::cv_status::no_timeout)
|
||||
- result = pred();
|
||||
-
|
||||
- return result;
|
||||
- }
|
||||
-
|
||||
- native_handle_type native_handle() {
|
||||
- return &m_cond;
|
||||
- }
|
||||
-
|
||||
- private:
|
||||
-
|
||||
- CONDITION_VARIABLE m_cond;
|
||||
-
|
||||
- };
|
||||
+ using mutex = std::mutex;
|
||||
+ using recursive_mutex = std::recursive_mutex;
|
||||
+ using condition_variable = std::condition_variable;
|
||||
|
||||
}
|
@ -1,33 +1,52 @@
|
||||
{ lib
|
||||
, pkgs
|
||||
, stdenv
|
||||
, hostPlatform
|
||||
, stdenvNoCC
|
||||
, fetchFromGitHub
|
||||
, pkgsCross
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (hostPlatform.uname) system;
|
||||
|
||||
# DXVK needs to be a separate derivation because it’s actually a set of DLLs for Windows that
|
||||
# needs to be built with a cross-compiler.
|
||||
dxvk32 = pkgsCross.mingw32.callPackage ./dxvk.nix { inherit (self) src version dxvkPatches; };
|
||||
dxvk64 = pkgsCross.mingwW64.callPackage ./dxvk.nix { inherit (self) src version dxvkPatches; };
|
||||
|
||||
# Split out by platform to make maintenance easy in case supported versions on Darwin and other
|
||||
# platforms diverge (due to the need for Darwin-specific patches that would fail to apply).
|
||||
# Should that happen, set `darwin` to the last working `rev` and `hash`.
|
||||
srcs = rec {
|
||||
darwin = { inherit (default) rev hash version; };
|
||||
default = {
|
||||
rev = "v${self.version}";
|
||||
hash = "sha256-/zH6vER/6s/d+Tt181UJOa97sqdkJyKGw6E36+1owzQ=";
|
||||
version = "1.10";
|
||||
};
|
||||
};
|
||||
|
||||
# Use the self pattern to support overriding `src` and `version` via `overrideAttrs`. A recursive
|
||||
# attrset wouldn’t work.
|
||||
self = stdenv.mkDerivation {
|
||||
self = stdenvNoCC.mkDerivation {
|
||||
name = "dxvk";
|
||||
version = "1.10";
|
||||
inherit (srcs."${system}" or srcs.default) version;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "doitsujin";
|
||||
repo = "dxvk";
|
||||
rev = "v${self.version}";
|
||||
hash = "sha256-/zH6vER/6s/d+Tt181UJOa97sqdkJyKGw6E36+1owzQ=";
|
||||
inherit (srcs."${system}" or srcs.default) rev hash;
|
||||
};
|
||||
|
||||
# Patch DXVK to work with MoltenVK even though it doesn’t support some required features.
|
||||
# Some games will work poorly (particularly Unreal Engine 4 games), but others work pretty well.
|
||||
# Override this to patch DXVK itself (rather than the setup script).
|
||||
dxvkPatches = lib.optional stdenv.isDarwin ./darwin-dxvk-compat.patch;
|
||||
dxvkPatches = lib.optionals stdenvNoCC.isDarwin [
|
||||
# Patch DXVK to work with MoltenVK even though it doesn’t support some required features.
|
||||
# Some games work poorly (particularly Unreal Engine 4 games), but others work pretty well.
|
||||
./darwin-dxvk-compat.patch
|
||||
# Use synchronization primitives from the C++ standard library to avoid deadlocks on Darwin.
|
||||
# See: https://www.reddit.com/r/macgaming/comments/t8liua/comment/hzsuce9/
|
||||
./darwin-thread-primitives.patch
|
||||
];
|
||||
|
||||
outputs = [ "out" "bin" "lib" ];
|
||||
|
||||
|
@ -19,18 +19,6 @@ stdenv.mkDerivation {
|
||||
|
||||
patches = dxvkPatches;
|
||||
|
||||
# Replace use of DXVK’s threading classes with the ones from the C++ standard library, which uses
|
||||
# mcfgthreads in nixpkgs.
|
||||
postPatch = ''
|
||||
for class in mutex recursive_mutex condition_variable; do
|
||||
for file in $(grep -rl dxvk::$class *); do
|
||||
if [ "$(basename "$file")" != "thread.h" ]; then
|
||||
substituteInPlace "$file" --replace dxvk::$class std::$class
|
||||
fi
|
||||
done
|
||||
done
|
||||
'';
|
||||
|
||||
mesonFlags =
|
||||
let
|
||||
arch = if stdenv.is32bit then "32" else "64";
|
||||
|
Loading…
Reference in New Issue
Block a user