From 52f7c04cfffa9a44f74c8e378e9068d5a60c441d Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Sun, 31 May 2026 10:55:39 +0500 Subject: [PATCH 1/2] feat: add SpecialK injection support Signed-off-by: Boris Yumankulov --- .../share/portproton/scripts/functions_helper | 96 ++++++++++++- build-aux/share/portproton/scripts/var | 2 + meson.build | 4 +- portprotonqt/meson.build | 1 + .../scripts_utils/graphics_detector.py | 133 ++++++++++++++++++ portprotonqt/settings_manager.py | 1 + 6 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 portprotonqt/scripts_utils/graphics_detector.py diff --git a/build-aux/share/portproton/scripts/functions_helper b/build-aux/share/portproton/scripts/functions_helper index 07e92e66..04404f20 100755 --- a/build-aux/share/portproton/scripts/functions_helper +++ b/build-aux/share/portproton/scripts/functions_helper @@ -2402,7 +2402,7 @@ pw_optiscaler_sync_files () { fi done - if [[ "${PW_USE_OPTISCALER}" != "1" ]] ; then + if [[ "${PW_USE_OPTISCALER}" != "1" ]] || [[ "${PW_USE_SPECIALK}" == "1" ]] ; then if [[ -f "$PATH_TO_GAME/dlssg_to_fsr3_amd_is_better.dll" ]] ; then for dll in $OPTISCALER_FILES ; do rm -fr "$PATH_TO_GAME/$dll"; done for dll in $ORIGINAL_GAME_DLLS ; do [[ -e "$PATH_TO_GAME/${dll}.b" ]] && mv -f "$PATH_TO_GAME/${dll}.b" "$PATH_TO_GAME/${dll}" 2>/dev/null; done @@ -2432,6 +2432,91 @@ pw_optiscaler_sync_files () { set_to_dxvk_conf nvidia_new } +pw_specialk_set_ini_value () { + local ini_file section key value + ini_file="$1" + section="$2" + key="$3" + value="$4" + + [[ -f "$ini_file" ]] && sed -i '/./,$!d' "$ini_file" + + if grep -q "^\[$section\]" "$ini_file" ; then + if sed -n "/^\[$section\]/,/^\[/{p}" "$ini_file" | grep -q "^$key=" ; then + sed -i "/^\[$section\]/,/^\[/{s/^$key=.*/$key=$value/}" "$ini_file" + else + sed -i "/^\[$section\]/a $key=$value" "$ini_file" + fi + else + [[ -s "$ini_file" ]] && printf '\n' >> "$ini_file" + printf '[%s]\n%s=%s\n' "$section" "$key" "$value" >> "$ini_file" + fi +} + +pw_specialk_sync_files () { + local SPECIALK_PATH SPECIALK_DLLS dll PW_SK_DLL_NAME PW_SK_ARCH_DLL PW_SK_INI_FILE PW_SK_VERSION_FILE + + SPECIALK_PATH="${PW_PLUGINS_PATH}/specialk/specialk-${PW_SPECIALK_VER}" + SPECIALK_DLLS="d3d9.dll d3d11.dll dinput8.dll dxgi.dll opengl32.dll" + PW_SK_VERSION_FILE="$PATH_TO_GAME/specialk_version" + + if [[ "${PW_USE_SPECIALK}" != "1" ]] ; then + if [[ -f "$PW_SK_VERSION_FILE" ]] ; then + for dll in $SPECIALK_DLLS ; do rm -fr "$PATH_TO_GAME/$dll"; done + for dll in $SPECIALK_DLLS ; do [[ -e "$PATH_TO_GAME/${dll}.b" ]] && mv -f "$PATH_TO_GAME/${dll}.b" "$PATH_TO_GAME/${dll}" 2>/dev/null; done + for dll in $SPECIALK_DLLS ; do try_remove_file "$PATH_TO_GAME/${dll%.*}.ini"; done + for dll in $SPECIALK_DLLS ; do try_remove_file "$PATH_TO_GAME/custom_${dll%.*}.ini"; done + try_remove_file "$PW_SK_VERSION_FILE" + fi + return 0 + fi + + if [[ ! -d "$SPECIALK_PATH" ]] && try_download "github.com/SpecialKO/SpecialK/releases/download/${PW_SPECIALK_VER}/SpecialK.7z" "${PORT_DATA_PATH}/data/tmp/SpecialK.7z" ; then + create_new_dir "$SPECIALK_PATH" + if [[ -z "$pw_7z" ]] ; then + if command -v 7z &>/dev/null ; then pw_7z="7z"; else pw_7z="${PW_PLUGINS_PATH}/portable/lib/p7zip/7z"; fi + fi + $pw_7z x "${PORT_DATA_PATH}/data/tmp/SpecialK.7z" -o"$SPECIALK_PATH" >/dev/null + try_remove_file "${PORT_DATA_PATH}/data/tmp/SpecialK.7z" + fi + + if [[ -d "$SPECIALK_PATH" ]] ; then + local DETECT_OUT HIGHEST_DX USES_OGL + DETECT_OUT=$(python_module graphics_detector "$PW_EXE_FILE") + HIGHEST_DX=$(echo "$DETECT_OUT" | grep "^HIGHEST_DX=" | cut -d'=' -f2) + USES_OGL=$(echo "$DETECT_OUT" | grep "^USES_OGL=" | cut -d'=' -f2) + + PW_SK_DLL_NAME="dxgi.dll" + case "$HIGHEST_DX" in + "DirectX 12") PW_SK_DLL_NAME="dxgi.dll" ;; + "DirectX 11") PW_SK_DLL_NAME="d3d11.dll" ;; + "DirectX 9") PW_SK_DLL_NAME="d3d9.dll" ;; + "DirectX 8"|"DirectDraw") return 0 ;; + *) [[ "$USES_OGL" == "true" ]] && PW_SK_DLL_NAME="opengl32.dll" || PW_SK_DLL_NAME="dxgi.dll" ;; + esac + if file "$PW_EXE_FILE" | grep -q "x86-64" ; then + PW_SK_ARCH_DLL="SpecialK64.dll" + else + PW_SK_ARCH_DLL="SpecialK32.dll" + fi + + if [[ -f "$SPECIALK_PATH/$PW_SK_ARCH_DLL" ]] ; then + PW_SK_INI_FILE="$PATH_TO_GAME/custom_${PW_SK_DLL_NAME%.*}.ini" + if [[ ! -f "$PW_SK_VERSION_FILE" ]] && [[ -f "$PATH_TO_GAME/$PW_SK_DLL_NAME" ]] && [[ ! -f "$PATH_TO_GAME/${PW_SK_DLL_NAME}.b" ]] ; then + mv -f "$PATH_TO_GAME/$PW_SK_DLL_NAME" "$PATH_TO_GAME/${PW_SK_DLL_NAME}.b" + fi + if [[ ! -f "$PW_SK_VERSION_FILE" ]] || ! grep -q "$PW_SPECIALK_VER" "$PW_SK_VERSION_FILE" ; then + cp -f "$SPECIALK_PATH/$PW_SK_ARCH_DLL" "$PATH_TO_GAME/$PW_SK_DLL_NAME" + echo "$PW_SPECIALK_VER" > "$PW_SK_VERSION_FILE" + fi + var_winedlloverride_update "${PW_SK_DLL_NAME%.*}=n,b" + pw_specialk_set_ini_value "$PW_SK_INI_FILE" "Compatibility.General" "UsingWINE" "true" + pw_specialk_set_ini_value "$PW_SK_INI_FILE" "Steam.Log" "Silent" "true" + fi + fi + +} + pw_prepare_gamescope_launch () { local gpu_vendor local gamescope_available="0" @@ -2855,6 +2940,7 @@ start_portproton () { fi pw_optiscaler_sync_files + pw_specialk_sync_files if [[ "${PW_USE_RAY_TRACING}" == "1" ]] ; then var_vkd3d_config_update dxr @@ -3154,7 +3240,7 @@ start_portproton () { fi # DGVOODOO2 enable: - if [[ "${PW_DGVOODOO2}" == "1" ]] ; then + if [[ "${PW_DGVOODOO2}" == "1" ]] && [[ "${PW_USE_SPECIALK}" != "1" ]] ; then if [[ ! -f "${PW_VULKAN_DIR}/dgvoodoo2-${DGV2_VER}/dgVoodoo.conf" ]] ; then print_info "Download and install DGVOODOO2 v.${DGV2_VER}" if try_download "https://github.com/Castro-Fidel/vulkan/releases/download/dgvoodoo2-${DGV2_VER}/dgvoodoo2-${DGV2_VER}.tar.xz" \ @@ -3401,7 +3487,7 @@ start_portproton () { try_force_link_file "${PATH_TO_DXVK_FILES}/x32/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_dxvk_dll}.dll" try_force_link_file "${PATH_TO_DXVK_FILES}/x64/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_dxvk_dll}.dll" ;; esac - if [[ $PW_USE_OPTISCALER == "1" ]] && [[ $wine_dxvk_dll == "dxgi" ]] + if [[ $PW_USE_OPTISCALER == "1" ]] && [[ $PW_USE_SPECIALK != "1" ]] && [[ $wine_dxvk_dll == "dxgi" ]] then var_winedlloverride_update "dxgi=n,b" else var_winedlloverride_update "${wine_dxvk_dll}=n" fi @@ -3878,6 +3964,7 @@ steamplay_launch () { fi pw_optiscaler_sync_files + pw_specialk_sync_files PORT_WINE_PREFIX="$STEAM_COMPAT_DATA_PATH/pfx" @@ -4122,7 +4209,7 @@ export -f gui_proton_downloader gui_edit_db () { KEY_EDIT_DB_GUI=$RANDOM DISABLE_EDIT_DB_LIST="" - PW_EDIT_DB_LIST=(PW_MANGOHUD PW_MANGOHUD_USER_CONF PW_VKBASALT PW_VKBASALT_USER_CONF PW_DGVOODOO2 + PW_EDIT_DB_LIST=(PW_MANGOHUD PW_MANGOHUD_USER_CONF PW_VKBASALT PW_VKBASALT_USER_CONF PW_DGVOODOO2 PW_USE_SPECIALK PW_USE_ESYNC PW_USE_FSYNC PW_USE_NTSYNC PW_USE_RAY_TRACING PW_USE_NVAPI_AND_DLSS PW_USE_OPTISCALER PW_USE_LS_FRAME_GEN PW_WINE_FULLSCREEN_FSR PW_HIDE_NVIDIA_GPU PW_VIRTUAL_DESKTOP PW_USE_TERMINAL PW_USE_GAMEMODE PW_USE_INHIBIT_SLEEP PW_USE_D3D_EXTRAS PW_FIX_VIDEO_IN_GAME PW_REDUCE_PULSE_LATENCY @@ -4155,6 +4242,7 @@ gui_edit_db () { if [[ "$PW_VULKAN_USE" == "0" ]] ; then DISABLE_EDIT_DB_LIST+=" PW_VKBASALT PW_VKBASALT_USER_CONF PW_USE_RAY_TRACING PW_USE_OBS_VKCAPTURE PW_USE_GALLIUM_ZINK PW_USE_WINED3D_VULKAN" fi + [[ "${PW_USE_SPECIALK}" == "1" ]] && DISABLE_EDIT_DB_LIST+=" PW_DGVOODOO2 PW_USE_OPTISCALER" [[ ! -e "/dev/ntsync" ]] && DISABLE_EDIT_DB_LIST+=" PW_USE_NTSYNC" diff --git a/build-aux/share/portproton/scripts/var b/build-aux/share/portproton/scripts/var index a36ffabd..b288e2a9 100755 --- a/build-aux/share/portproton/scripts/var +++ b/build-aux/share/portproton/scripts/var @@ -14,6 +14,7 @@ export VKD3D_OLD_VER="2.14.1" export VKD3D_SAREK_VER="sarek-2.6.0" export PW_LSFG_VK_VER="2.0.0-dev25-p11" export PW_OPTISCALER_VER="v03-0.9.0-pre8" +export PW_SPECIALK_VER="SK_26_5_15" export PW_GALLIUM_NINE_VER="0.10" export DOTPFX_VER="48v9" export DEFPFX_VER="v1" @@ -29,6 +30,7 @@ export PW_RT_MOUNT_RW=("/media" "/mnt" "/run/media/${USER}" "${PORT_DATA_PATH}") check_variables PW_WINE_USE "PROTON_LG" check_variables PROTON_USE_XALIA "0" check_variables PW_USE_RUNTIME "1" +check_variables PW_USE_SPECIALK "0" check_variables PW_USE_ESYNC "0" check_variables PW_USE_FSYNC "0" check_variables PW_USE_NTSYNC "0" diff --git a/meson.build b/meson.build index e630616b..de5eacb9 100644 --- a/meson.build +++ b/meson.build @@ -33,7 +33,7 @@ bindir = prefix / get_option('bindir') # Use custom purelibdir if specified, otherwise use default purelibdir_opt = get_option('python_purelibdir') -pythondir = purelibdir_opt != '' ? purelibdir_opt : python3.get_install_dir(pure: true) +pythondir = purelibdir_opt != '' ? purelibdir_opt: python3.get_install_dir(pure: true) pkgdatadir = pythondir / meson.project_name() # C compiler for vk_gpu_info @@ -133,7 +133,7 @@ install_subdir( # Install udev rules udev_rulesdir_opt = get_option('udev_rulesdir') -udevdir = udev_rulesdir_opt != '' ? udev_rulesdir_opt : prefix / 'lib' / 'udev' / 'rules.d' +udevdir = udev_rulesdir_opt != '' ? udev_rulesdir_opt: prefix / 'lib' / 'udev' / 'rules.d' install_data( 'build-aux/lib/udev/rules.d/60-portprotonqt.rules', diff --git a/portprotonqt/meson.build b/portprotonqt/meson.build index 5bee4e35..37f17340 100644 --- a/portprotonqt/meson.build +++ b/portprotonqt/meson.build @@ -123,6 +123,7 @@ install_data( ['scripts_utils/__init__.py', 'scripts_utils/dbus_tools.py', 'scripts_utils/easyterm.py', + 'scripts_utils/graphics_detector.py', 'scripts_utils/idle_inhibit.py', 'scripts_utils/mount_points.py', 'scripts_utils/prefix_backup.py', diff --git a/portprotonqt/scripts_utils/graphics_detector.py b/portprotonqt/scripts_utils/graphics_detector.py new file mode 100644 index 00000000..197e9ae1 --- /dev/null +++ b/portprotonqt/scripts_utils/graphics_detector.py @@ -0,0 +1,133 @@ +import sys +from pathlib import Path +from typing import Any + +DIRECTX_IMPORTS = { + "ddraw.dll": "DirectDraw", + "d3d8.dll": "DirectX 8", + "d3d9.dll": "DirectX 9", + "d3d10.dll": "DirectX 10", + "d3d10_1.dll": "DirectX 10", + "d3d11.dll": "DirectX 11", + "d3d12.dll": "DirectX 12", +} + +DIRECTX_SIGNATURES = { + "DirectDraw": (b"ddraw.dll", b"DirectDrawCreate"), + "DirectX 8": (b"d3d8.dll", b"Direct3DCreate8"), + "DirectX 9": (b"d3d9.dll", b"Direct3DCreate9"), + "DirectX 10": (b"d3d10.dll", b"D3D10CreateDevice"), + "DirectX 11": (b"d3d11.dll", b"D3D11CreateDevice"), + "DirectX 12": (b"d3d12.dll", b"D3D12CreateDevice", b"D3D12Core.dll"), +} + +DIRECTX_ORDER = { + "DirectDraw": 7, + "DirectX 8": 8, + "DirectX 9": 9, + "DirectX 10": 10, + "DirectX 11": 11, + "DirectX 12": 12, +} + +OPENGL_IMPORTS = { + "opengl32.dll": "OpenGL", + "glu32.dll": "OpenGL Utility Library", +} + +OPENGL_SIGNATURES = { + "OpenGL": ( + b"opengl32.dll", + b"wglCreateContext", + b"wglGetProcAddress", + b"glGetString", + b"OpenGL context", + b"OpenGL Error", + ), + "OpenGL Utility Library": (b"glu32.dll", b"gluPerspective", b"gluLookAt"), +} + + +def analyze_executable(file_path: str) -> dict[str, Any]: + """Detect graphics API usage in a Windows executable.""" + path = Path(file_path).expanduser().resolve() + if not path.is_file(): + raise FileNotFoundError(f"File not found: {path}") + + directx = set() + opengl = set() + + if path.suffix.lower() in {".exe", ".dll"}: + _add_pe_imports(path, directx, opengl) + _add_file_signatures(path, directx, opengl) + + return { + "highest_directx": _highest_directx(list(directx)), + "uses_opengl": bool(opengl), + } + + +def _add_pe_imports(path: Path, directx: set[str], opengl: set[str]) -> None: + try: + import pefile + except ImportError: + return + + try: + pe = pefile.PE(str(path), fast_load=True) + pe.parse_data_directories( + directories=[ + pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_IMPORT"], + pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT"], + ] + ) + for attr_name in ["DIRECTORY_ENTRY_IMPORT", "DIRECTORY_ENTRY_DELAY_IMPORT"]: + for entry in getattr(pe, attr_name, []): + dll = entry.dll.decode("utf-8", errors="ignore").lower() + if dll in DIRECTX_IMPORTS: + directx.add(DIRECTX_IMPORTS[dll]) + elif dll in OPENGL_IMPORTS: + opengl.add(OPENGL_IMPORTS[dll]) + except (pefile.PEFormatError, ValueError): + return + + +def _add_file_signatures(path: Path, directx: set[str], opengl: set[str]) -> None: + try: + with path.open("rb") as f: + data = f.read(67108864).lower() + except OSError: + return + + for name, patterns in DIRECTX_SIGNATURES.items(): + if any(p.lower() in data for p in patterns): + directx.add(name) + + for name, patterns in OPENGL_SIGNATURES.items(): + if any(p.lower() in data for p in patterns): + opengl.add(name) + + +def _highest_directx(directx: list[str]) -> str: + if not directx: + return "None" + return max(directx, key=lambda n: DIRECTX_ORDER[n]) + + +def _main(argv: list[str]) -> int: + if len(argv) != 2: + print("Usage: python3 -m portprotonqt.graphics_detector FILE") + return 2 + + try: + result = analyze_executable(argv[1]) + print(f"HIGHEST_DX={result['highest_directx']}") + print(f"USES_OGL={'true' if result['uses_opengl'] else 'false'}") + return 0 + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(_main(sys.argv)) diff --git a/portprotonqt/settings_manager.py b/portprotonqt/settings_manager.py index 839e5d2a..ff7722d2 100644 --- a/portprotonqt/settings_manager.py +++ b/portprotonqt/settings_manager.py @@ -89,6 +89,7 @@ def get_toggle_settings(): 'PW_VKBASALT': _("Enable vkBasalt by default to improve graphics in games running on Vulkan. (The HOME hotkey disables vkbasalt)"), 'PW_VKBASALT_USER_CONF': _("Forced use of VKBASALT system settings (GOverlay, etc.)"), 'PW_DGVOODOO2': _("Enable dgVoodoo2. Forced use all dgVoodoo2 libs (Glide 2.11-3.1, DirectDraw 1-7, Direct3D 2-9) on all 3D API."), + 'PW_USE_SPECIALK': _("Enable SpecialK (injection library for fixing graphics, latency and more)"), # Upscalers and Frame Generation 'PW_USE_OPTISCALER': _("Enable OptiScaler (replacement upscaler / frame generator)"), 'PW_USE_LS_FRAME_GEN': _("Enable Lossless Scaling frame generation (experimental)"), -- 2.54.0 From 08ec0773faa29de81d675811469e141b8f6c7007 Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Tue, 2 Jun 2026 21:40:07 +0500 Subject: [PATCH 2/2] feat: support Special K with OptiScaler Signed-off-by: Boris Yumankulov --- .../share/portproton/scripts/functions_helper | 54 +++++++++++++++---- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/build-aux/share/portproton/scripts/functions_helper b/build-aux/share/portproton/scripts/functions_helper index 04404f20..3b2bb90a 100755 --- a/build-aux/share/portproton/scripts/functions_helper +++ b/build-aux/share/portproton/scripts/functions_helper @@ -2402,8 +2402,9 @@ pw_optiscaler_sync_files () { fi done - if [[ "${PW_USE_OPTISCALER}" != "1" ]] || [[ "${PW_USE_SPECIALK}" == "1" ]] ; then - if [[ -f "$PATH_TO_GAME/dlssg_to_fsr3_amd_is_better.dll" ]] ; then + if [[ "${PW_USE_OPTISCALER}" != "1" ]] ; then + if [[ -f "$PATH_TO_GAME/optiscaler_version" ]] + then for dll in $OPTISCALER_FILES ; do rm -fr "$PATH_TO_GAME/$dll"; done for dll in $ORIGINAL_GAME_DLLS ; do [[ -e "$PATH_TO_GAME/${dll}.b" ]] && mv -f "$PATH_TO_GAME/${dll}.b" "$PATH_TO_GAME/${dll}" 2>/dev/null; done try_remove_file "$PATH_TO_GAME/optiscaler_version" @@ -2420,10 +2421,19 @@ pw_optiscaler_sync_files () { check_variables OPTISCALER_FG_TYPE "Nukems" sed -i "s|FGType =.*|FGType = $OPTISCALER_FG_TYPE|g" "$OPTISCALER_PATH/OptiScaler.ini" echo "" > "$PATH_TO_GAME/dxvk.conf" + if [[ -f "$PATH_TO_GAME/dxgi.dll" ]] \ + && [[ -f "$PATH_TO_GAME/specialk_version" ]] + then + create_new_dir "$PATH_TO_GAME/plugins" + mv -f "$PATH_TO_GAME/dxgi.dll" "$PATH_TO_GAME/plugins/dxgi.dll" + mv -f "$PATH_TO_GAME/specialk_version" "$PATH_TO_GAME/plugins/specialk_version" + fi if [[ ! -f "$PATH_TO_GAME/dlssg_to_fsr3_amd_is_better.dll" && -f "$PATH_TO_GAME/dxgi.dll" ]] ; then fatal 'dxgi.dll is already present in the game folder!\nThis script uses dxgi.dll to load required files.\nRemove the mod using dxgi.dll.' fi - for dll in $ORIGINAL_GAME_DLLS ; do [[ -e "$PATH_TO_GAME/$dll" && ! -e "$PATH_TO_GAME/${dll}.b" ]] && mv -f "$PATH_TO_GAME/$dll" "$PATH_TO_GAME/${dll}.b" 2>/dev/null; done + if [[ ! -f "$PATH_TO_GAME/optiscaler_version" ]] ; then + for dll in $ORIGINAL_GAME_DLLS ; do [[ -e "$PATH_TO_GAME/$dll" && ! -e "$PATH_TO_GAME/${dll}.b" ]] && mv -f "$PATH_TO_GAME/$dll" "$PATH_TO_GAME/${dll}.b" 2>/dev/null; done + fi if [[ ! -f "$PATH_TO_GAME/optiscaler_version" ]] || ! grep -q "$PW_OPTISCALER_VER" "$PATH_TO_GAME/optiscaler_version" ; then for dll in $OPTISCALER_FILES ; do cp -fr "$OPTISCALER_PATH/$dll" "$PATH_TO_GAME/$dll" || print_error "$OPTISCALER_PATH/$dll not found for copy!"; done echo "$PW_OPTISCALER_VER" > "$PATH_TO_GAME/optiscaler_version" @@ -2468,6 +2478,12 @@ pw_specialk_sync_files () { for dll in $SPECIALK_DLLS ; do try_remove_file "$PATH_TO_GAME/custom_${dll%.*}.ini"; done try_remove_file "$PW_SK_VERSION_FILE" fi + if [[ -f "$PATH_TO_GAME/plugins/specialk_version" ]] ; then + try_remove_file "$PATH_TO_GAME/plugins/dxgi.dll" + try_remove_file "$PATH_TO_GAME/plugins/specialk_version" + try_remove_file "$PATH_TO_GAME/dxgi.ini" + try_remove_file "$PATH_TO_GAME/custom_dxgi.ini" + fi return 0 fi @@ -2481,6 +2497,24 @@ pw_specialk_sync_files () { fi if [[ -d "$SPECIALK_PATH" ]] ; then + if file "$PW_EXE_FILE" | grep -q "x86-64" ; then + PW_SK_ARCH_DLL="SpecialK64.dll" + else + PW_SK_ARCH_DLL="SpecialK32.dll" + fi + + if [[ "${PW_USE_OPTISCALER}" == "1" ]] && [[ -f "$SPECIALK_PATH/$PW_SK_ARCH_DLL" ]] ; then + create_new_dir "$PATH_TO_GAME/plugins" + if [[ ! -f "$PATH_TO_GAME/plugins/specialk_version" ]] || ! grep -q "$PW_SPECIALK_VER" "$PATH_TO_GAME/plugins/specialk_version" ; then + cp -f "$SPECIALK_PATH/$PW_SK_ARCH_DLL" "$PATH_TO_GAME/plugins/dxgi.dll" + echo "$PW_SPECIALK_VER" > "$PATH_TO_GAME/plugins/specialk_version" + fi + PW_SK_INI_FILE="$PATH_TO_GAME/custom_dxgi.ini" + pw_specialk_set_ini_value "$PW_SK_INI_FILE" "Compatibility.General" "UsingWINE" "true" + pw_specialk_set_ini_value "$PW_SK_INI_FILE" "Steam.Log" "Silent" "true" + return 0 + fi + local DETECT_OUT HIGHEST_DX USES_OGL DETECT_OUT=$(python_module graphics_detector "$PW_EXE_FILE") HIGHEST_DX=$(echo "$DETECT_OUT" | grep "^HIGHEST_DX=" | cut -d'=' -f2) @@ -2494,15 +2528,13 @@ pw_specialk_sync_files () { "DirectX 8"|"DirectDraw") return 0 ;; *) [[ "$USES_OGL" == "true" ]] && PW_SK_DLL_NAME="opengl32.dll" || PW_SK_DLL_NAME="dxgi.dll" ;; esac - if file "$PW_EXE_FILE" | grep -q "x86-64" ; then - PW_SK_ARCH_DLL="SpecialK64.dll" - else - PW_SK_ARCH_DLL="SpecialK32.dll" - fi if [[ -f "$SPECIALK_PATH/$PW_SK_ARCH_DLL" ]] ; then PW_SK_INI_FILE="$PATH_TO_GAME/custom_${PW_SK_DLL_NAME%.*}.ini" - if [[ ! -f "$PW_SK_VERSION_FILE" ]] && [[ -f "$PATH_TO_GAME/$PW_SK_DLL_NAME" ]] && [[ ! -f "$PATH_TO_GAME/${PW_SK_DLL_NAME}.b" ]] ; then + if [[ ! -f "$PW_SK_VERSION_FILE" ]] \ + && [[ -f "$PATH_TO_GAME/$PW_SK_DLL_NAME" ]] \ + && [[ ! -f "$PATH_TO_GAME/${PW_SK_DLL_NAME}.b" ]] + then mv -f "$PATH_TO_GAME/$PW_SK_DLL_NAME" "$PATH_TO_GAME/${PW_SK_DLL_NAME}.b" fi if [[ ! -f "$PW_SK_VERSION_FILE" ]] || ! grep -q "$PW_SPECIALK_VER" "$PW_SK_VERSION_FILE" ; then @@ -3487,7 +3519,7 @@ start_portproton () { try_force_link_file "${PATH_TO_DXVK_FILES}/x32/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/syswow64/${wine_dxvk_dll}.dll" try_force_link_file "${PATH_TO_DXVK_FILES}/x64/${wine_dxvk_dll}.dll" "${WINEPREFIX}/drive_c/windows/system32/${wine_dxvk_dll}.dll" ;; esac - if [[ $PW_USE_OPTISCALER == "1" ]] && [[ $PW_USE_SPECIALK != "1" ]] && [[ $wine_dxvk_dll == "dxgi" ]] + if [[ $PW_USE_OPTISCALER == "1" ]] && [[ $wine_dxvk_dll == "dxgi" ]] then var_winedlloverride_update "dxgi=n,b" else var_winedlloverride_update "${wine_dxvk_dll}=n" fi @@ -4242,7 +4274,7 @@ gui_edit_db () { if [[ "$PW_VULKAN_USE" == "0" ]] ; then DISABLE_EDIT_DB_LIST+=" PW_VKBASALT PW_VKBASALT_USER_CONF PW_USE_RAY_TRACING PW_USE_OBS_VKCAPTURE PW_USE_GALLIUM_ZINK PW_USE_WINED3D_VULKAN" fi - [[ "${PW_USE_SPECIALK}" == "1" ]] && DISABLE_EDIT_DB_LIST+=" PW_DGVOODOO2 PW_USE_OPTISCALER" + [[ "${PW_USE_SPECIALK}" == "1" ]] && DISABLE_EDIT_DB_LIST+=" PW_DGVOODOO2" [[ ! -e "/dev/ntsync" ]] && DISABLE_EDIT_DB_LIST+=" PW_USE_NTSYNC" -- 2.54.0