diff options
| author | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2026-06-26 11:54:58 -0400 |
|---|---|---|
| committer | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2026-06-26 11:54:58 -0400 |
| commit | fd5d2de4144ee165e4985bd65dd9037361c730d3 (patch) | |
| tree | 997d2df36d8c68c5a7cc123b794808477597b0b3 | |
| parent | fd29203c37b7febe2a2713e62c141bf38ea3ae27 (diff) | |
| download | Decky-Framegen-fd5d2de4144ee165e4985bd65dd9037361c730d3.tar.gz Decky-Framegen-fd5d2de4144ee165e4985bd65dd9037361c730d3.zip | |
fix: complete RDNA2 pre10 4.1.1 variantv0.16.3-prefeat/opti-pre10-variant
| -rwxr-xr-x | defaults/assets/fgmod.sh | 99 | ||||
| -rw-r--r-- | main.py | 120 | ||||
| -rw-r--r-- | package.json | 7 | ||||
| -rw-r--r-- | src/utils/constants.ts | 2 |
4 files changed, 189 insertions, 39 deletions
diff --git a/defaults/assets/fgmod.sh b/defaults/assets/fgmod.sh index ad8059e..e0ee1d2 100755 --- a/defaults/assets/fgmod.sh +++ b/defaults/assets/fgmod.sh @@ -112,6 +112,7 @@ cleanup_files=( "${proxy_backup_files[@]}" "OptiScaler.dll" "amdxcffx64.dll" + "amdxc64.dll" "nvngx.dll" "_nvngx.dll" "nvngx-wrapper.dll" @@ -181,19 +182,18 @@ case "$selected_fsr4_variant" in variant_dir="$fgmod_path/fsr4-rdna3-4-official-411" fsr4_upscaler_src="$variant_dir/amd_fidelityfx_upscaler_dx12.dll" variant_extra_files+=("amdxcffx64.dll") - variant_ini_overrides+=("Fsr4ForceModel=2") ;; rdna2-valve-411-pre10) variant_dir="$fgmod_path/fsr4-rdna2-valve-411-pre10" fsr4_upscaler_src="$variant_dir/amd_fidelityfx_upscaler_dx12.dll" - variant_extra_files+=("amdxcffx64.dll") - variant_ini_overrides+=("Fsr4ForceModel=2") + variant_extra_files+=("amdxcffx64.dll" "amdxc64.dll") + variant_ini_overrides+=("FSR.Fsr4ForceModel=2") + variant_ini_overrides+=("Plugins.LoadCustomAmdxc64OnRdna2=true") ;; *) selected_fsr4_variant="rdna23-int8" variant_dir="$fgmod_path/fsr4-rdna2-3" fsr4_upscaler_src="$variant_dir/amd_fidelityfx_upscaler_dx12.dll" - variant_ini_overrides+=("Fsr4ForceModel=2") ;; esac [[ -f "$fsr4_upscaler_src" ]] || fsr4_upscaler_src="$fgmod_path/amd_fidelityfx_upscaler_dx12.dll" @@ -224,6 +224,13 @@ is_managed_support_file() { done return 1 fi + if [[ "$filename" == "amdxc64.dll" ]]; then + for candidate in \ + "$fgmod_path/fsr4-rdna2-valve-411-pre10/amdxc64.dll"; do + [[ -f "$candidate" && -f "$existing_file" ]] && cmp -s "$existing_file" "$candidate" && return 0 + done + return 1 + fi candidate="$fgmod_path/$filename" [[ -f "$candidate" && -f "$existing_file" ]] && cmp -s "$existing_file" "$candidate" } @@ -251,7 +258,7 @@ done unset cleanup_file # === Optional: Backup Original DLLs === -original_dlls=("d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_framegeneration_dx12.dll" "amd_fidelityfx_upscaler_dx12.dll" "amdxcffx64.dll" "amd_fidelityfx_vk.dll") +original_dlls=("d3dcompiler_47.dll" "amd_fidelityfx_dx12.dll" "amd_fidelityfx_framegeneration_dx12.dll" "amd_fidelityfx_upscaler_dx12.dll" "amdxcffx64.dll" "amdxc64.dll" "amd_fidelityfx_vk.dll") for dll in "${original_dlls[@]}"; do existing_path="$exe_folder_path/$dll" backup_path="$exe_folder_path/$dll.b" @@ -305,17 +312,77 @@ fi # an external TTF that is not present. Only normalize the default auto value. sed -i 's/^UseHQFont[[:space:]]*=[[:space:]]*auto$/UseHQFont=false/' "$exe_folder_path/OptiScaler.ini" || true -for override in "${variant_ini_overrides[@]}"; do - key="${override%%=*}" - value="${override#*=}" - if [[ -n "$key" ]]; then - if grep -q "^${key}[[:space:]]*=" "$exe_folder_path/OptiScaler.ini" 2>/dev/null; then - sed -i "s/^${key}[[:space:]]*=.*/${key}=${value}/" "$exe_folder_path/OptiScaler.ini" || true - else - printf '\n%s=%s\n' "$key" "$value" >> "$exe_folder_path/OptiScaler.ini" || true - fi - fi -done +if [[ ${#variant_ini_overrides[@]} -gt 0 && -n "$python_bin" ]]; then + "$python_bin" - "$exe_folder_path/OptiScaler.ini" "${variant_ini_overrides[@]}" <<'PY' +import re +import sys +from pathlib import Path + +path = Path(sys.argv[1]) +overrides = sys.argv[2:] +content = path.read_text(encoding='utf-8', errors='replace') +newline = '\r\n' if '\r\n' in content else '\n' +lines = content.splitlines(keepends=True) +section_pattern = re.compile(r'^\s*\[(?P<section>[^\]]+)\]\s*$') + +def ensure_trailing_newline(): + if lines and not lines[-1].endswith(('\n', '\r')): + lines[-1] += newline + +def upsert(section, key, value): + replacement = f'{key}={value}' + key_pattern = re.compile(rf'^(\s*{re.escape(key)}\s*)=.*$') + if section is None: + for idx, line in enumerate(lines): + if key_pattern.match(line): + line_ending = '\r\n' if line.endswith('\r\n') else ('\n' if line.endswith('\n') else newline) + lines[idx] = f'{replacement}{line_ending}' + return + ensure_trailing_newline() + lines.append(f'{replacement}{newline}') + return + + in_section = False + insert_at = None + for idx, line in enumerate(lines): + match = section_pattern.match(line.strip()) + if match: + if in_section: + insert_at = idx + break + if match.group('section') == section: + in_section = True + continue + if in_section and key_pattern.match(line): + line_ending = '\r\n' if line.endswith('\r\n') else ('\n' if line.endswith('\n') else newline) + lines[idx] = f'{replacement}{line_ending}' + return + + if in_section: + if insert_at is None: + ensure_trailing_newline() + insert_at = len(lines) + lines.insert(insert_at, f'{replacement}{newline}') + return + + ensure_trailing_newline() + if lines and lines[-1].strip(): + lines.append(newline) + lines.append(f'[{section}]{newline}') + lines.append(f'{replacement}{newline}') + +for override in overrides: + key_part, value = override.split('=', 1) + if '.' in key_part: + section, key = key_part.split('.', 1) + else: + section, key = None, key_part + if key: + upsert(section.strip() if section else None, key.strip(), value.strip()) + +path.write_text(''.join(lines), encoding='utf-8') +PY +fi # === Migrate FGType → FGInput/FGOutput (pre-v0.9-final INIs) === # v0.9-final split the single FGType key into FGInput + FGOutput. Games that were @@ -33,6 +33,12 @@ FSR4_VALVE_411_ASSET = { "version": "4.1.1-valve-2.3.0.2913", } +AMDXC64_RDNA2_ASSET = { + "name": "amdxc64.dll", + "sha256": "a0a0af61d475e30a70966b3459f3793df772faf8f26ae3261d10554ff592cbd5", + "version": "8.18.10.0474", +} + OPTISCALER_PRE10_ASSET = { "name": "OptiScaler_0.10.0-pre1.20260622_135940.dll", "sha256": "b374b19081cc066365d0c6da4808d768e16469b0cbdfc478b6e95999947d5364", @@ -60,9 +66,6 @@ FSR4_VARIANTS = { "source_version": FSR4_INT8_ASSET["version"], "uses_archive_native": False, "extra_files": [], - "config_overrides": { - "Fsr4ForceModel": "2", - }, }, "rdna4-native": { "label": "Native bundle / RDNA4", @@ -88,9 +91,7 @@ FSR4_VARIANTS = { "source_version": FSR4_OFFICIAL_411_ASSET["version"], } ], - "config_overrides": { - "Fsr4ForceModel": "2", - }, + "config_overrides": {}, }, "rdna2-valve-411-pre10": { "label": "4.1.1 Valve RDNA2 compatibility", @@ -111,10 +112,17 @@ FSR4_VARIANTS = { "sha256": FSR4_VALVE_411_ASSET["sha256"], "source_asset_name": FSR4_VALVE_411_ASSET["name"], "source_version": FSR4_VALVE_411_ASSET["version"], + }, + { + "name": "amdxc64.dll", + "sha256": AMDXC64_RDNA2_ASSET["sha256"], + "source_asset_name": AMDXC64_RDNA2_ASSET["name"], + "source_version": AMDXC64_RDNA2_ASSET["version"], } ], "config_overrides": { - "Fsr4ForceModel": "2", + "FSR.Fsr4ForceModel": "2", + "Plugins.LoadCustomAmdxc64OnRdna2": "true", }, }, } @@ -175,6 +183,7 @@ ORIGINAL_DLL_BACKUPS = [ "amd_fidelityfx_framegeneration_dx12.dll", FSR4_UPSCALER_FILENAME, FSR4_DRIVER_OVERRIDE_FILENAME, + "amdxc64.dll", "amd_fidelityfx_vk.dll", ] @@ -439,25 +448,79 @@ class Plugin: overrides = variant.get("config_overrides") or {} return dict(overrides) if isinstance(overrides, dict) else {} + def _split_ini_override_key(self, raw_key: str) -> tuple[str | None, str]: + key = str(raw_key).strip() + if "." in key: + section, section_key = key.split(".", 1) + section = section.strip() + section_key = section_key.strip() + if section and section_key: + return section, section_key + return None, key + def _apply_optiscaler_ini_overrides(self, ini_file: Path, overrides: dict) -> bool: if not overrides: return True try: content = ini_file.read_text(encoding="utf-8", errors="replace") - for key, value in overrides.items(): - key = str(key).strip() - value = str(value).strip() - if not key: - continue - pattern = re.compile(rf"^{re.escape(key)}\s*=.*$", re.MULTILINE) + newline = "\r\n" if "\r\n" in content else "\n" + lines = content.splitlines(keepends=True) + section_pattern = re.compile(r"^\s*\[(?P<section>[^\]]+)\]\s*$") + + def ensure_trailing_newline() -> None: + if lines and not lines[-1].endswith(("\n", "\r")): + lines[-1] += newline + + def upsert(section: str | None, key: str, value: str) -> None: replacement = f"{key}={value}" - if pattern.search(content): - content = pattern.sub(replacement, content) - else: - if content and not content.endswith("\n"): - content += "\n" - content += f"{replacement}\n" - ini_file.write_text(content, encoding="utf-8") + key_pattern = re.compile(rf"^(\s*{re.escape(key)}\s*)=.*$") + + if section is None: + for idx, line in enumerate(lines): + if key_pattern.match(line): + line_ending = "\r\n" if line.endswith("\r\n") else ("\n" if line.endswith("\n") else newline) + lines[idx] = f"{replacement}{line_ending}" + return + ensure_trailing_newline() + lines.append(f"{replacement}{newline}") + return + + in_section = False + insert_at = None + for idx, line in enumerate(lines): + match = section_pattern.match(line.strip()) + if match: + if in_section: + insert_at = idx + break + if match.group("section") == section: + in_section = True + continue + if in_section and key_pattern.match(line): + line_ending = "\r\n" if line.endswith("\r\n") else ("\n" if line.endswith("\n") else newline) + lines[idx] = f"{replacement}{line_ending}" + return + + if in_section: + if insert_at is None: + ensure_trailing_newline() + insert_at = len(lines) + lines.insert(insert_at, f"{replacement}{newline}") + return + + ensure_trailing_newline() + if lines and lines[-1].strip(): + lines.append(newline) + lines.append(f"[{section}]{newline}") + lines.append(f"{replacement}{newline}") + + for raw_key, raw_value in overrides.items(): + section, key = self._split_ini_override_key(str(raw_key)) + value = str(raw_value).strip() + if key: + upsert(section, key, value) + + ini_file.write_text("".join(lines), encoding="utf-8") return True except Exception as exc: decky.logger.error(f"Failed to apply OptiScaler.ini overrides to {ini_file}: {exc}") @@ -669,6 +732,7 @@ class Plugin: fsr4_int8_src = bin_path / FSR4_INT8_ASSET["name"] fsr4_official_411_src = bin_path / FSR4_OFFICIAL_411_ASSET["name"] fsr4_valve_411_src = bin_path / FSR4_VALVE_411_ASSET["name"] + amdxc64_rdna2_src = bin_path / AMDXC64_RDNA2_ASSET["name"] optiscaler_pre10_src = bin_path / OPTISCALER_PRE10_ASSET["name"] optipatcher_src = bin_path / OPTIPATCHER_ASSET["name"] for required_path, asset in [ @@ -676,6 +740,7 @@ class Plugin: (fsr4_int8_src, FSR4_INT8_ASSET), (fsr4_official_411_src, FSR4_OFFICIAL_411_ASSET), (fsr4_valve_411_src, FSR4_VALVE_411_ASSET), + (amdxc64_rdna2_src, AMDXC64_RDNA2_ASSET), (optiscaler_pre10_src, OPTISCALER_PRE10_ASSET), (optipatcher_src, OPTIPATCHER_ASSET), ]: @@ -774,6 +839,18 @@ class Plugin: "Prepared rdna2-valve-411-pre10 driver override", ) self._verify_bundled_asset( + amdxc64_rdna2_src, + AMDXC64_RDNA2_ASSET["sha256"], + "Bundled rdna2-valve-411-pre10 amdxc64 override", + ) + rdna2_valve_amdxc64 = rdna2_valve_dir / "amdxc64.dll" + shutil.copy2(amdxc64_rdna2_src, rdna2_valve_amdxc64) + self._verify_bundled_asset( + rdna2_valve_amdxc64, + AMDXC64_RDNA2_ASSET["sha256"], + "Prepared rdna2-valve-411-pre10 amdxc64 override", + ) + self._verify_bundled_asset( optiscaler_pre10_src, OPTISCALER_PRE10_ASSET["sha256"], "Bundled rdna2-valve-411-pre10 OptiScaler injector", @@ -1069,7 +1146,8 @@ class Plugin: selected_variant_info = FSR4_VARIANTS[selected_variant] selected_config_overrides = self._fsr4_variant_config_overrides(selected_variant) if previous_variant == "rdna2-valve-411-pre10" and selected_variant != previous_variant: - selected_config_overrides.setdefault("Fsr4ForceModel", "auto") + selected_config_overrides.setdefault("FSR.Fsr4ForceModel", "auto") + selected_config_overrides.setdefault("Plugins.LoadCustomAmdxc64OnRdna2", "false") selected_upscaler_src = self._fsr4_variant_path(fgmod_path, selected_variant) if not selected_upscaler_src.exists(): selected_upscaler_src = fgmod_path / FSR4_UPSCALER_FILENAME diff --git a/package.json b/package.json index e349c66..663b43b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decky-framegen", - "version": "0.16.2-pre", + "version": "0.16.3-pre", "description": "This plugin installs and manages OptiScaler, a tool that enhances upscaling and enables frame generation in a range of DirectX 12 games.", "type": "module", "scripts": { @@ -69,6 +69,11 @@ "name": "amdxcffx64.dll" }, { + "sha256hash": "a0a0af61d475e30a70966b3459f3793df772faf8f26ae3261d10554ff592cbd5", + "url": "https://github.com/xXJSONDeruloXx/OptiScaler-Bleeding-Edge/releases/download/fsr-4-1-1-rdna2/amdxc64.dll", + "name": "amdxc64.dll" + }, + { "sha256hash": "4e7dc37aebea3a90e3d3cc43e24cb2b54176b2535315f20dbe63b3b7cfc56b1e", "url": "https://github.com/xXJSONDeruloXx/OptiScaler-Bleeding-Edge/releases/download/fsr-4-1-1-rdna2/amdxcffx64.dll", "name": "amdxcffx64_valve_2.3.0.2913.dll" diff --git a/src/utils/constants.ts b/src/utils/constants.ts index d35aaad..13bf505 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -78,7 +78,7 @@ export const FSR4_VARIANT_OPTIONS = [ { value: "rdna2-valve-411-pre10", label: "4.1.1 | RDNA2 Mod", - hint: "Uses the pre10 OptiScaler injector, 4.1.0 native upscaler, Valve 4.1.1 amdxcffx64.dll, and forces FSR4 model 2.", + hint: "Uses the pre10 OptiScaler injector, 4.1.0 native upscaler, Valve 4.1.1 amdxcffx64.dll, old amdxc64.dll, and RDNA2-specific INI overrides.", }, ] as const; |
