Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 77ed24e68a | |||
| 26dea2e586 | |||
| 8f22c90401 | |||
| 6570829e27 | |||
| ef6c4d08c1 | |||
| d6c53ed634 | |||
| 2a51ab6030 | |||
| 1969bb83bd | |||
| d6b191a4c4 | |||
| 5c09056d7c | |||
| fa9dd1c730 | |||
| 6ddc2c5df9 |
@@ -1,77 +0,0 @@
|
||||
name: Commit V36 Retail Soft decode
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- test/v36-retail-jfa-soft
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
commit-v36-soft:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: test/v36-retail-jfa-soft
|
||||
|
||||
- name: Apply V36 decode
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 <<'PY'
|
||||
from pathlib import Path
|
||||
p = Path('src/outline/d3d9_hook.zig')
|
||||
s = p.read_text()
|
||||
if 'V36 RETAIL-SOFT' in s:
|
||||
raise SystemExit(0)
|
||||
start = s.index('/// V32 POLISH: hard 3px outline, no feather.')
|
||||
end = s.index('/// Debug: composite silhouette RT directly.')
|
||||
lines = [
|
||||
'/// V36 RETAIL-SOFT: keep the proven V34 JFA, soften only final decode.',
|
||||
'/// c0 = (screen_width, screen_height, core_radius_px, halo_radius_px).',
|
||||
'/// Uses the same two texture reads as V34: no 17-tap full-screen morphology.',
|
||||
'const jfa_decode_src =',
|
||||
' "ps_3_0\\n" ++',
|
||||
' "def c1, 0.0, 0.22, 0.82, -0.002\\n" ++',
|
||||
' "def c2, 1.0, 0.95, 0.58, 0.0\\n" ++',
|
||||
' "dcl_2d s0\\n" ++',
|
||||
' "dcl_2d s1\\n" ++',
|
||||
' "dcl_texcoord0 v0\\n" ++',
|
||||
' "texld r0, v0, s0\\n" ++',
|
||||
' "sub r1.xy, v0.xy, r0.xy\\n" ++',
|
||||
' "mul r1.xy, r1.xy, c0.xy\\n" ++',
|
||||
' "dp2add r1.z, r1, r1, c1.x\\n" ++',
|
||||
' "mul r3.x, c0.z, c0.z\\n" ++',
|
||||
' "mul r3.y, c0.w, c0.w\\n" ++',
|
||||
' "sub r4.x, r1.z, r3.y\\n" ++',
|
||||
' "cmp r6.w, r4.x, c1.x, c1.y\\n" ++',
|
||||
' "sub r4.x, r1.z, r3.x\\n" ++',
|
||||
' "cmp r6.w, r4.x, r6.w, c1.z\\n" ++',
|
||||
' "texld r5, v0, s1\\n" ++',
|
||||
' "add r5.x, r5.a, c1.w\\n" ++',
|
||||
' "cmp r6.w, r5.x, c1.x, r6.w\\n" ++',
|
||||
' "mov r6.xyz, c2.xyz\\n" ++',
|
||||
' "mov oC0, r6\\n";',
|
||||
'',
|
||||
'',
|
||||
]
|
||||
s = s[:start] + '\n'.join(lines) + s[end:]
|
||||
old = ' // V34: hard 3px edge unchanged; JFA seed precision is now full-float.\n c0 = [4]f32{ fw, fh, 3.0, 0.0 };'
|
||||
new_cpu = ' // V36: thin 1.5px core plus a subtle 3px halo.\n c0 = [4]f32{ fw, fh, 1.5, 3.0 };'
|
||||
if old not in s:
|
||||
raise SystemExit('V34 CPU decode constants not found')
|
||||
p.write_text(s.replace(old, new_cpu))
|
||||
PY
|
||||
|
||||
- name: Commit source
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if git diff --quiet; then exit 0; fi
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add src/outline/d3d9_hook.zig
|
||||
git commit -m "V36: soft Retail-style JFA decode"
|
||||
git push origin HEAD:test/v36-retail-jfa-soft
|
||||
+8
-2
@@ -1048,11 +1048,17 @@ comptime {
|
||||
pub export fn DllMain(
|
||||
_: ?*anyopaque,
|
||||
reason: u32,
|
||||
_: ?*anyopaque,
|
||||
reserved: ?*anyopaque,
|
||||
) callconv(WINAPI) std.os.windows.BOOL {
|
||||
switch (reason) {
|
||||
1 => install(),
|
||||
0 => uninstall(),
|
||||
0 => {
|
||||
// ExitFix: when lpReserved is non-null, Windows is terminating the
|
||||
// whole process. Do not call into D3D9/COM or other DLLs from
|
||||
// DLL_PROCESS_DETACH during global teardown; the OS will reclaim
|
||||
// those resources. Keep full uninstall for explicit FreeLibrary.
|
||||
if (reserved == null) uninstall();
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return @enumFromInt(1);
|
||||
|
||||
+34
-10
@@ -57,6 +57,14 @@ var orig_reset: usize = 0;
|
||||
var d3d9_vtable: ?[*]usize = null;
|
||||
var hooks_installed: bool = false;
|
||||
|
||||
/// ExitFix: once shutdown begins, no code path may reinstall D3D9 hooks.
|
||||
var shutdown_started: bool = false;
|
||||
|
||||
pub fn beginShutdown() void {
|
||||
shutdown_started = true;
|
||||
}
|
||||
|
||||
|
||||
// Sticky diagnostics for the in-game OutlineDebug() command.
|
||||
pub var debug_endscene_seen: bool = false;
|
||||
pub var debug_dip_seen: bool = false;
|
||||
@@ -114,6 +122,7 @@ pub var debug_late_rehook_succeeded: bool = false;
|
||||
/// If the current entries are no longer ours, chain whatever is there now as
|
||||
/// the new originals, then patch the three entries again.
|
||||
pub fn lateRehookIfLost() bool {
|
||||
if (shutdown_started) return false;
|
||||
debug_late_rehook_attempted = true;
|
||||
|
||||
const cur = getD3D9VTable() orelse return false;
|
||||
@@ -732,26 +741,40 @@ const jfa_prop_src =
|
||||
"mov oC0.xy, r8.xy\n" ++
|
||||
"mov oC0.zw, c1.xx\n";
|
||||
|
||||
/// V36 RETAIL-SOFT: keep the proven V34 JFA, soften only final decode.
|
||||
/// V38 RETAIL-POLISH: keep the proven V34/V36/V37 JFA and refine only
|
||||
/// the final alpha profile. Still only two texture reads.
|
||||
/// c0 = (screen_width, screen_height, core_radius_px, halo_radius_px).
|
||||
/// Uses the same two texture reads as V34: no 17-tap full-screen morphology.
|
||||
const jfa_decode_src =
|
||||
"ps_3_0\n" ++
|
||||
"def c1, 0.0, 0.22, 0.82, -0.002\n" ++
|
||||
"def c2, 1.0, 0.95, 0.58, 0.0\n" ++
|
||||
// c1 = zero, one, halo alpha, -interior threshold
|
||||
"def c1, 0.0, 1.0, 0.17, -0.002\n" ++
|
||||
// pale Retail-like yellow-green
|
||||
"def c2, 1.0, 0.96, 0.62, 0.0\n" ++
|
||||
// core alpha
|
||||
"def c3, 0.84, 0.0, 0.0, 0.0\n" ++
|
||||
"dcl_2d s0\n" ++
|
||||
"dcl_2d s1\n" ++
|
||||
"dcl_texcoord0 v0\n" ++
|
||||
// Nearest JFA seed and pixel-space squared distance.
|
||||
"texld r0, v0, s0\n" ++
|
||||
"sub r1.xy, v0.xy, r0.xy\n" ++
|
||||
"mul r1.xy, r1.xy, c0.xy\n" ++
|
||||
"dp2add r1.z, r1, r1, c1.x\n" ++
|
||||
// Squared core and halo radii.
|
||||
"mul r3.x, c0.z, c0.z\n" ++
|
||||
"mul r3.y, c0.w, c0.w\n" ++
|
||||
"sub r4.x, r1.z, r3.y\n" ++
|
||||
"cmp r6.w, r4.x, c1.x, c1.y\n" ++
|
||||
"sub r4.x, r1.z, r3.x\n" ++
|
||||
"cmp r6.w, r4.x, r6.w, c1.z\n" ++
|
||||
// Smooth halo factor = saturate((halo² - dist²) / (halo² - core²)).
|
||||
"sub r3.z, r3.y, r3.x\n" ++
|
||||
"rcp r3.z, r3.z\n" ++
|
||||
"sub r4.x, r3.y, r1.z\n" ++
|
||||
"mul r4.x, r4.x, r3.z\n" ++
|
||||
"max r4.x, r4.x, c1.x\n" ++
|
||||
"min r4.x, r4.x, c1.y\n" ++
|
||||
"mul r6.w, r4.x, c1.z\n" ++
|
||||
// Solid-but-soft core inside the inner radius.
|
||||
"sub r4.y, r1.z, r3.x\n" ++
|
||||
"cmp r6.w, r4.y, r6.w, c3.x\n" ++
|
||||
// Never paint over the original model interior.
|
||||
"texld r5, v0, s1\n" ++
|
||||
"add r5.x, r5.a, c1.w\n" ++
|
||||
"cmp r6.w, r5.x, c1.x, r6.w\n" ++
|
||||
@@ -1414,8 +1437,8 @@ fn runJfaPipeline(device: *anyopaque) void {
|
||||
if (saved_rt0) |rt| deviceSetRenderTarget(device, 0, rt);
|
||||
deviceSetTexture(device, 0, rt_jfa_a_tex);
|
||||
deviceSetTexture(device, 1, rt_silhouette_tex);
|
||||
// V36: thin 1.5px core plus a subtle 3px halo.
|
||||
c0 = [4]f32{ fw, fh, 1.5, 3.0 };
|
||||
// V38: slightly stronger 1.5px core with a subtler 3.1px falloff.
|
||||
c0 = [4]f32{ fw, fh, 1.50, 3.10 };
|
||||
deviceSetPSConstF(device, 0, &c0);
|
||||
deviceSetPtr(device, types.VT.SetPixelShader, jfa_decode_ps.?);
|
||||
deviceSetRS(device, types.D3DRS.ALPHABLENDENABLE, 1);
|
||||
@@ -1623,6 +1646,7 @@ fn getD3D9VTable() ?[*]usize {
|
||||
|
||||
pub fn installHooks() bool {
|
||||
if (hooks_installed) return true;
|
||||
if (shutdown_started) return false;
|
||||
|
||||
const vtable_ptr = getD3D9VTable() orelse return false;
|
||||
d3d9_vtable = vtable_ptr;
|
||||
|
||||
@@ -109,8 +109,11 @@ pub fn initD3D9Deferred() void {
|
||||
/// Remove all outline hooks. Called during DLL_PROCESS_DETACH.
|
||||
pub fn cleanup() void {
|
||||
if (g_is_hook_owner) {
|
||||
d3d9_hook.removeHooks();
|
||||
// ExitFix: stop any future self-heal first, then detach the model hooks
|
||||
// that can call lateRehookIfLost(), and only then tear down D3D9.
|
||||
d3d9_hook.beginShutdown();
|
||||
model_hook.removeHooks();
|
||||
d3d9_hook.removeHooks();
|
||||
log.close();
|
||||
mod_mutex.release(&g_mutex);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user