diff --git a/pkgs/misc/dxvk/default.nix b/pkgs/misc/dxvk/default.nix index 2c55b6b50cef..0e46011e7e10 100644 --- a/pkgs/misc/dxvk/default.nix +++ b/pkgs/misc/dxvk/default.nix @@ -1,75 +1,34 @@ { lib -, pkgs , stdenvNoCC , fetchFromGitHub , pkgsCross +, stdenv +, bash }: stdenvNoCC.mkDerivation (finalAttrs: let - system = lib.toLower stdenvNoCC.targetPlatform.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 (finalAttrs) src version dxvkPatches; - }; - dxvk64 = pkgsCross.mingwW64.callPackage ./dxvk.nix { - inherit (finalAttrs) 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 = { - rev = "v${finalAttrs.version}"; - hash = "sha256-T93ZylxzJGprrP+j6axZwl2d3hJowMCUOKNjIyNzkmE="; - version = "1.10.3"; - }; - default = { - rev = "v${finalAttrs.version}"; - hash = "sha256-mboVLdPgZMzmqyeF0jAloEz6xqfIDiY/X98e7l2KZnw="; - version = "2.0"; - }; - }; + dxvk32 = if stdenv.isDarwin then pkgsCross.mingw32.dxvk_1 else pkgsCross.mingw32.dxvk_2; + dxvk64 = if stdenv.isDarwin then pkgsCross.mingwW64.dxvk_1 else pkgsCross.mingwW64.dxvk_2; in { name = "dxvk"; - inherit (srcs."${system}" or srcs.default) version; - - src = fetchFromGitHub { - owner = "doitsujin"; - repo = "dxvk"; - inherit (srcs."${system}" or srcs.default) rev hash; - }; - - # Override this to patch DXVK itself (rather than the setup script). - 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 - ]; + inherit (dxvk64) version; outputs = [ "out" "bin" "lib" ]; - # Also copy `mcfgthread-12.dll` due to DXVK’s being built in a MinGW cross environment. - patches = [ ./mcfgthread.patch ]; - + dontUnpack = true; dontConfigure = true; dontBuild = true; installPhase = '' mkdir -p $out/bin $bin $lib - # Replace both basedir forms to support both DXVK 2.0 and older versions. - substitute setup_dxvk.sh $out/bin/setup_dxvk.sh \ + substitute ${./setup_dxvk.sh} $out/bin/setup_dxvk.sh \ + --subst-var-by bash ${bash} \ + --subst-var-by dxvk32 ${dxvk32} \ + --subst-var-by dxvk64 ${dxvk64} \ --subst-var-by mcfgthreads32 "${pkgsCross.mingw32.windows.mcfgthreads}" \ - --subst-var-by mcfgthreads64 "${pkgsCross.mingwW64.windows.mcfgthreads}" \ - --replace 'basedir=$(dirname "$(readlink -f $0)")' "basedir=$bin" \ - --replace 'basedir="$(dirname "$(readlink -f "$0")")"' "basedir=$bin" + --subst-var-by mcfgthreads64 "${pkgsCross.mingwW64.windows.mcfgthreads}" chmod a+x $out/bin/setup_dxvk.sh declare -A dxvks=( [x32]=${dxvk32} [x64]=${dxvk64} ) for arch in "''${!dxvks[@]}"; do @@ -79,7 +38,7 @@ stdenvNoCC.mkDerivation (finalAttrs: ''; meta = { - description = "A Vulkan-based translation layer for Direct3D 9/10/11"; + description = "Setup script for DXVK"; homepage = "https://github.com/doitsujin/dxvk"; changelog = "https://github.com/doitsujin/dxvk/releases"; maintainers = [ lib.maintainers.reckenrode ]; diff --git a/pkgs/misc/dxvk/dxvk.nix b/pkgs/misc/dxvk/dxvk.nix index 7607c9ee4412..793264f9b30b 100644 --- a/pkgs/misc/dxvk/dxvk.nix +++ b/pkgs/misc/dxvk/dxvk.nix @@ -5,31 +5,81 @@ , meson , ninja , windows -, src -, version +, dxvkVersion , spirv-headers , vulkan-headers -, dxvkPatches +, SDL2 +, glfw +, pkgsBuildHost +, sdl2Support ? true +, glfwSupport ? false }: +# SDL2 and GLFW support are mutually exclusive. +assert !sdl2Support || !glfwSupport; + let # DXVK 2.0+ no longer vendors certain dependencies. This derivation also needs to build on Darwin, # which does not currently support DXVK 2.0, so adapt conditionally for this situation. - isDxvk2 = lib.versionAtLeast version "2.0"; + isDxvk2 = lib.versionAtLeast (srcs.${dxvkVersion}.version) "2.0"; + + # DXVK has effectively the same build script regardless of platform. + srcs = { + "1.10" = rec { + version = "1.10.3"; + src = fetchFromGitHub { + owner = "doitsujin"; + repo = "dxvk"; + rev = "v${version}"; + hash = "sha256-T93ZylxzJGprrP+j6axZwl2d3hJowMCUOKNjIyNzkmE="; + }; + # These patches are required when using DXVK with Wine on Darwin. + patches = lib.optionals stdenv.buildPlatform.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 + ]; + }; + "2.1" = rec { + version = "2.1"; + src = fetchFromGitHub { + owner = "doitsujin"; + repo = "dxvk"; + rev = "v${version}"; + hash = "sha256-A4KR11brfQbR56dGt371MRwMN/H6HFAU8TlFC97/bRs="; + fetchSubmodules = true; # Needed for the DirectX headers and libdisplay-info + }; + patches = [ ]; + }; + }; + + isWindows = stdenv.targetPlatform.uname.system == "Windows"; + isCross = stdenv.hostPlatform != stdenv.targetPlatform; in stdenv.mkDerivation { pname = "dxvk"; - inherit src version; + inherit (srcs.${dxvkVersion}) version src patches; nativeBuildInputs = [ glslang meson ninja ]; - buildInputs = [ windows.pthreads ] - ++ lib.optionals isDxvk2 [ spirv-headers vulkan-headers ]; + buildInputs = lib.optional isWindows [ windows.pthreads ] + ++ lib.optionals isDxvk2 ( + [ spirv-headers vulkan-headers ] + ++ lib.optional (!isWindows && sdl2Support) SDL2 + ++ lib.optional (!isWindows && glfwSupport) glfw + ); - patches = dxvkPatches; + postPatch = lib.optionalString isDxvk2 '' + substituteInPlace "subprojects/libdisplay-info/tool/gen-search-table.py" \ + --replace "/usr/bin/env python3" "${lib.getBin pkgsBuildHost.python3}/bin/python3" + ''; - preConfigure = lib.optionalString isDxvk2 '' - ln -s ${lib.getDev spirv-headers}/include include/spirv/include - ln -s ${lib.getDev vulkan-headers}/include include/vulkan/include + # Build with the Vulkan SDK in nixpkgs. + preConfigure = '' + rm -rf include/spirv/include include/vulkan/include + mkdir -p include/spirv/include include/vulkan/include ''; mesonFlags = @@ -38,9 +88,12 @@ stdenv.mkDerivation { in [ "--buildtype" "release" - "--cross-file" "build-win${arch}.txt" "--prefix" "${placeholder "out"}" - ]; + ] + ++ lib.optionals isCross [ "--cross-file" "build-win${arch}.txt" ] + ++ lib.optional glfwSupport "-Ddxvk_native_wsi=glfw"; + + doCheck = isDxvk2 && !isCross; meta = { description = "A Vulkan-based translation layer for Direct3D 9/10/11"; @@ -48,6 +101,6 @@ stdenv.mkDerivation { changelog = "https://github.com/doitsujin/dxvk/releases"; maintainers = [ lib.maintainers.reckenrode ]; license = lib.licenses.zlib; - platforms = lib.platforms.windows; + platforms = lib.platforms.windows ++ lib.optionals isDxvk2 lib.platforms.linux; }; } diff --git a/pkgs/misc/dxvk/mcfgthread.patch b/pkgs/misc/dxvk/mcfgthread.patch deleted file mode 100644 index 037071630172..000000000000 --- a/pkgs/misc/dxvk/mcfgthread.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/setup_dxvk.sh b/setup_dxvk.sh -index 3e63ecf0..87c04f23 100755 ---- a/setup_dxvk.sh -+++ b/setup_dxvk.sh -@@ -133,6 +133,8 @@ - rm -v "${dstfile}" - fi - $file_cmd "${srcfile}" "${dstfile}" -+ elif [ "${4}" = "--force" ]; then -+ $file_cmd "${srcfile}" "${dstfile}" - else - echo "${dstfile}: File not found in wine prefix" >&2 - return 1 -@@ -170,12 +172,12 @@ - } - - install() { -- installFile "$win64_sys_path" "$dxvk_lib64" "$1" -+ installFile "$win64_sys_path" "$dxvk_lib64" "$1" "${2-}" - inst64_ret="$?" - - inst32_ret=-1 - if $wow64; then -- installFile "$win32_sys_path" "$dxvk_lib32" "$1" -+ installFile "$win32_sys_path" "$dxvk_lib32" "$1" "${2-}" - inst32_ret="$?" - fi - -@@ -214,3 +216,5 @@ - - $action d3d10core - $action d3d11 -+ -+basedir="" dxvk_lib32=@mcfgthreads32@/bin dxvk_lib64=@mcfgthreads64@/bin $action mcfgthread-12 --force diff --git a/pkgs/misc/dxvk/setup_dxvk.sh b/pkgs/misc/dxvk/setup_dxvk.sh new file mode 100644 index 000000000000..8fadb264fd3d --- /dev/null +++ b/pkgs/misc/dxvk/setup_dxvk.sh @@ -0,0 +1,265 @@ +#!@bash@/bin/bash -e + +set -eu -o pipefail + +dxvk32_dir=@dxvk32@/bin +dxvk64_dir=@dxvk64@/bin + +mcfgthreads32_dir=@mcfgthreads32@/bin +mcfgthreads64_dir=@mcfgthreads64@/bin + +## Defaults + +declare -A dlls=( + [d3d9]="dxvk/d3d9.dll" + [d3d10]="dxvk/d3d10.dll dxvk/d3d10_1.dll dxvk/d3d10core.dll" + [d3d11]="dxvk/d3d11.dll" + [dxgi]="dxvk/dxgi.dll" + [mcfgthreads]="mcfgthreads/mcfgthread-12.dll" +) + +declare -A targets=([d3d9]=1 [d3d11]=1 [dxgi]=1 [mcfgthreads]=1) + +## Command-line Parsing + +usage() { + echo "DXVK @version@" + echo "Set up Wine prefix with DXVK DLLs" + echo + echo "USAGE" + echo " $0 [install|uninstall] [OPTIONS]" + echo + echo "COMMANDS" + echo " install Copy the DXVK DLLs into the prefix" + echo " uninstall Restore the backed up Wine DLLs in the prefix" + echo + echo "OPTIONS" + echo " --with(out)-dxgi Copy DXVK DXGI DLL into prefix (default: with DXGI)" + echo " --with(out)-d3d10 Copy D3D10 DLLs into prefix (default: without D3D10)" + echo " -s, --symlink Symlink instead of copy" + echo " -f, --force Create a Wine prefix even if it does not exist" + echo " -p, --prefix Wine prefix to manage (default: \$WINEPREFIX)" + exit 1 +} + +case "$1" in + uninstall|install) + action=$1 + shift + ;; + -h|--help) + usage + ;; + *) + if [ ! -z "${1:-}" ]; then + echo "Unrecognized command: $1" + fi + usage + ;; +esac + + +do_symlink=false +do_makeprefix=false + +while [ ! -z "${1:-}" ]; do + case "$1" in + --with-dxgi) + targets[dxgi]=1 + ;; + --without-dxgi) + unset targets[dxgi] + ;; + --with-d3d10) + targets[d3d10]=1 + ;; + --without-d3d10) + unset targets[d3d10] + ;; + -s|--symlink) + do_symlink=true + ;; + --no-symlink) + do_symlink=false + ;; + -f|--force) + do_makeprefix=true + ;; + --no-force) + do_makeprefix=false + ;; + -p|--prefix) + shift + if [ ! -z "${1:-}" ]; then + WINEPREFIX=$1 + else + echo "Required PREFIX missing" + usage + fi + ;; + -h|--help) + usage + ;; + *) + echo "Unrecognized option: $1" + usage + ;; + esac + shift +done + +## Get information on the Wine environment + +export WINEPREFIX=${WINEPREFIX:-"$HOME/.wine"} + +# check wine prefix before invoking wine, so that we +# don't accidentally create one if the user screws up +if ! $do_makeprefix && [ -n "$WINEPREFIX" ] && ! [ -f "$WINEPREFIX/system.reg" ]; then + echo "$WINEPREFIX: Not a valid wine prefix." >&2 + exit 1 +fi + +export WINEDEBUG=-all +# disable mscoree and mshtml to avoid downloading +# wine gecko and mono +export WINEDLLOVERRIDES="mscoree,mshtml=" + +wine="wine" +wine64="wine64" +wineboot="wineboot" + +# $PATH is the way for user to control where wine is located (including custom Wine versions). +# Pure 64-bit Wine (non Wow64) requries skipping 32-bit steps. +# In such case, wine64 and winebooot will be present, but wine binary will be missing, +# however it can be present in other PATHs, so it shouldn't be used, to avoid versions mixing. +wine_path=$(dirname "$(command -v $wineboot)") +wow64=true +if ! [ -f "$wine_path/$wine" ]; then + wine=$wine64 + wow64=false +fi + +# resolve 32-bit and 64-bit system32 path +winever=$($wine --version | grep wine) +if [ -z "$winever" ]; then + echo "$wine: Not a wine executable. Check your $wine." >&2 + exit 1 +fi + +# ensure wine placeholder dlls are recreated +# if they are missing +$wineboot -u + +win64_sys_path=$($wine64 winepath -u 'C:\windows\system32' 2> /dev/null) +win64_sys_path="${win64_sys_path/$'\r'/}" +if $wow64; then + win32_sys_path=$($wine winepath -u 'C:\windows\system32' 2> /dev/null) + win32_sys_path="${win32_sys_path/$'\r'/}" +fi + +if [ -z "${win32_sys_path:-}" ] && [ -z "${win64_sys_path:-}" ]; then + echo 'Failed to resolve C:\windows\system32.' >&2 + exit 1 +fi + +## Utility functions + +install_file() { + $do_symlink && file_cmd="ln -sv" || file_cmd="install -m 755 -v" + + srcfile=$1 + dstfile=$2 + + if [ -f "${srcfile}.so" ]; then + srcfile="${srcfile}.so" + fi + + if ! [ -f "${srcfile}" ]; then + echo "${srcfile}: File not found. Skipping." >&2 + return 1 + fi + + if [ -n "$1" ]; then + if [ -f "${dstfile}" ] || [ -h "${dstfile}" ]; then + if ! [ -f "${dstfile}.old" ]; then + mv -v "${dstfile}" "${dstfile}.old" + else + rm -v "${dstfile}" + fi + fi + $file_cmd "${srcfile}" "${dstfile}" + else + echo "${dstfile}: File not found in wine prefix" >&2 + return 1 + fi +} + +uninstall_file() { + srcfile=$1 + dstfile=$2 + + if [ -f "${srcfile}.so" ]; then + srcfile="${srcfile}.so" + fi + + if ! [ -f "${srcfile}" ]; then + echo "${srcfile}: File not found. Skipping." >&2 + return 1 + fi + + if ! [ -f "${dstfile}" ] && ! [ -h "${dstfile}" ]; then + echo "${dstfile}: File not found. Skipping." >&2 + return 1 + fi + + if [ -f "${dstfile}.old" ]; then + rm -v "${dstfile}" + mv -v "${dstfile}.old" "${dstfile}" + return 0 + else + return 1 + fi +} + +install_override() { + dll=$(basename "$1") + $wine reg add 'HKEY_CURRENT_USER\Software\Wine\DllOverrides' /v "$dll" /d native /f >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo -e "Failed to add override for $dll" + exit 1 + fi +} + +uninstall_override() { + dll=$(basename "$1") + $wine reg delete 'HKEY_CURRENT_USER\Software\Wine\DllOverrides' /v "$dll" /f > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Failed to remove override for $dll" + fi +} + +## Perform the requested command + +declare -A paths + +for target in "${!targets[@]}"; do + [ ${targets[$target]} -eq 1 ] || continue + for dll in ${dlls[$target]}; do + dllname=$(basename "$dll") + basedir=$(dirname "$dll") + + if [ ! -z "${win32_sys_path:-}" ]; then + basedir32=${basedir}32_dir + paths["${!basedir32}/$dllname"]="$win32_sys_path/$dllname" + fi + if [ ! -z "${win64_sys_path:-}" ]; then + basedir64=${basedir}64_dir + paths["${!basedir64}/$dllname"]="$win64_sys_path/$dllname" + fi + done +done + +for srcpath in "${!paths[@]}"; do + ${action}_file "$srcpath" "${paths["$srcpath"]}" + ${action}_override "$(basename srcpath)" +done diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 9a4bc93bc252..d533dc1113f9 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -37332,6 +37332,8 @@ with pkgs; dump = callPackage ../tools/backup/dump { }; dxvk = callPackage ../misc/dxvk { }; + dxvk_1 = callPackage ../misc/dxvk/dxvk.nix { dxvkVersion = "1.10"; }; + dxvk_2 = callPackage ../misc/dxvk/dxvk.nix { dxvkVersion = "2.1"; }; ecdsatool = callPackage ../tools/security/ecdsatool { };