Commit Graph
22 Commits
Author SHA1 Message Date
MarcelineVQ 0671ffce02 math_sse: SIMD optimizations for planeNormal, transformAABox, and others
Added V4 vector helpers (loadV3, storeV3, dot3) and rewrote several
functions to use @Vector(4, f32) operations instead of scalar f64:

- planeNormal: 0.7x -> 1.7x (79 -> 33 cyc) -- V4 cross + normalize
- transformAABox: 0.7x -> 1.2x (118 -> 69 cyc) -- f32 + @min/@max
- evaluatePolynomial: 0.4x -> 0.6x (24 -> 16 cyc) -- drop f64 promotion
- vec3MulScalar: 0.7x -> 0.8x -- V4 splat multiply
- dotProduct/squaredMagnitude: rewritten with dot3 helper

crossProduct reverted from shuffle-SIMD back to scalar -- shuffles added
latency that the x87 pipeline doesn't have (16 vs 13 cyc).

Remaining losers (dotProduct 0.4x, evalPoly 0.6x) are at the function
call overhead floor -- the original x87 is 5-11 cycles, which is close
to bare call/ret cost.
2026-03-14 21:57:14 -07:00
MarcelineVQ 8307e525d9 math_sse: fix calling conventions from Ghidra disassembly verification
Hooks 1,3 (vecMulMat4, quatMulMat4): thiscall->fastcall. Assembly
confirms EDX is read as a parameter (FMUL [EDX+...]) before any write.
Detour types TC2r->FC3r, AB wrappers abTC2r->abFC3r.

Hook 15 (0x699330): removed entirely. Was misidentified as vectorNormalize
but Ghidra shows it's a vec3 componentwise >= comparison returning u32.
Silicon-only function (not UnitXP), stub already in silicon.zig. Our
normalize implementation would have silently corrupted comparison results.

Also fixed comment accuracy: hook 8 RET 0x4 (not plain RET), hook 14
__thiscall (not __fastcall). Bitmask selection replaces MATH_TEST_HOOK
single-select with proper bit flags. 17 hooks total, mask 0x77FFE.
2026-03-14 18:44:22 -07:00
MarcelineVQ 2018ca45fa bone_sse: fix IsParticleBufferEmpty calling convention
Was __stdcall with stack param — would corrupt stack for every visible
particle emitter. Fixed to __fastcall(ECX=ptr) matching assembly at
0x717EB8: MOV ECX,[EBP-0x10]; CALL 0x7B5F60. Plain RET, no stack cleanup.

Bug #14 found during final verification pass.
2026-03-14 17:45:46 -07:00
MarcelineVQ c060f0d469 bone_sse: verify remaining particle sections from assembly
Section 12c (model_hdr+0x134): visibility byte animation pattern verified
from assembly at 0x7176C2-0x717774. Byte array indexing, crossfade output
at +0xCC (not +0xBC). Position track at entry+0x24 with 12-byte keyframes.

Section 12e (model_hdr+0x13C): all 10 tracks verified. Tracks 1-6 use
scalar float interpolation (findInterpIdx + 4-byte keyframes). Tracks 7-10
use getInterpolatedFloat (0x71AF20). Track offsets, gate checks, and output
positions all confirmed from assembly.

SSE dispatch remains disabled pending final testing.
2026-03-14 17:40:50 -07:00
MarcelineVQ 2b9b5bc043 bone_sse: assembly-verified reimplementation of transformMatrix4x4
13 bugs fixed by comparing against full assembly dump (5317 instructions):
- Emitter check: this+0x188 -> this+0x1D8
- Animation time: added FILD*time_scale pattern for both primary (+0xB0)
  and secondary (+0xDC) slots
- Conditional multiply: bone_local *= *(bone_rt+0xF0) was missing
- Billboard post-processing: 4 switch cases (types 8/16/32/64) implemented
- Color animation loop bound: model_hdr+0x64 -> +0x6C
- Bone keyframe data stride: 0x24 -> 0x54
- Ribbon emitter output stride: 0x15C -> 0x170
- Particle data/output strides: 0x1FC/0x17C -> 0x1F8/0x16C
- Child SceneObject offsets: attach_idx +0x184->+0x1D4, next +0x190->+0x1E4
- Root bone parent: identity -> this+0xFC

New files:
- BONE_SSE_PROGRESS.md: section-by-section verification status
- t44_full_asm.txt: complete function assembly (ground truth)
- t44_helpers_asm.txt: all 12 helper function assemblies
- math_sse.zig: 18 x87->SSE polyfill stubs (VanillaFixes integration)

Also: OnWorldUpdate hook for true per-frame counting, DUMP_FRAMES=450.
SSE dispatch currently disabled while particle sections are being verified.
2026-03-14 17:34:37 -07:00
MarcelineVQ 692a02ed2c Move file cache to standalone module, add timer fix, fix refcount crashes
File cache (filecache module):
- Moved from transform44 sub-module to standalone src/filecache/
- 2-way set-associative cache (32768 sets x 2 ways) with FNV-1a hash + finalizer
- Fixed negative cache hit crash: zero output params before returning 0
  (FindFileInArchive reuses filename slot for out_outer_archive)
- Fixed path 2 crash: set out_outer_archive on all cache hit paths
- Fixed stale block_entry crash: cache block index instead of raw pointer,
  recompute from archive+0x290 on each hit
- Fixed archive-freed crash: use game's FindAndIncrementResourceReference
  (0x650780) instead of manual +0x38 increment -- validates archive is alive
- Periodic stats dump with projected time savings (hit=~1000cy vs miss=~30000cy)

Timer fix (transform44 sub-module, ported from VanillaFixes):
- TSC calibration via QPC reference over 500ms
- Enables TSC mode if game was using GetTickCount fallback
- NtSetTimerResolution for 0.5ms OS timer granularity
- SetProcessInformation to disable Windows 11 power throttling
- Always-on (no A/B toggle -- no measurable impact on Wine/Linux)
2026-03-14 14:57:58 -07:00
MarcelineVQ 0833d23e28 WIP: bone_sse SSE reimplementation of transformMatrix4x4 + OnWorldUpdate frame counter
bone_sse.zig: Full standalone SSE reimplementation of the 17703-byte bone
transform engine (0x714260). All helper functions reimplemented inline
(findInterpolationIndices, interpolateAnimationKeyframes, scaleMatrix3x3,
ApplyTranslation, rotateByQuaternion). Currently disabled (A/B dispatch
commented out) due to NULL ofsValues crash under investigation.

transform44.zig: Add OnWorldUpdate (0x482EA0) hook for true per-frame
counting. Previous frame counter used executeSceneRenderPass which fires
multiple times per frame (shadows, reflections, spell effects), causing
A/B periods to be as short as 0.5s during combat instead of ~30s.

SCENEOBJECT_OFFSETS.md: Complete assembly-verified field offset map
(51 offsets) extracted from [EBX+N] patterns in transformMatrix4x4.
Corrects bone_runtime_base from +0x80 to +0x090.
2026-03-14 00:22:36 -07:00
MarcelineVQ 55735d7b9e Add MPQ archive file cache: skip redundant chain walks on repeat file opens
Hook File_FindInArchive (0x6549a0) with a direct-mapped filename-verified
cache. First open does the full MPQ chain walk (~60K cycles), subsequent
opens hit the cache (~300 cycles). 80% hit rate in gameplay testing.

Cache design: 16384 entries, FNV-1a hash for slot index, raw filename
comparison (128 bytes) for collision safety. Stores outer_archive,
inner_archive, and block_entry per file. Negative cache for not-found files.
Refcount at +0x38 incremented on all output archives to match original
File_FindInArchive behavior (verified via Ghidra: FindAndIncrementResourceReference
at 0x650780, DecrementResourceReference at 0x6507e0).

Also: default build changed to ReleaseFast (works around Zig fastcall inreg
bug in Debug mode), logging gate changed to != ReleaseSmall, file cache
integrated as transform44 sub-module with A/B comparison timing in readout.
2026-03-13 23:05:38 -07:00
MarcelineVQ d9701c528d Add glyph shadow cache: direct-mapped O(1) bypass for game's 4-bucket hash table
GetOrCreateCharacterGlyph (0x5ca2d0) is the #2 CPU hotspot at 3.65%.
The game's glyph cache uses only 4 hash buckets for ~95 ASCII chars,
causing ~24-entry chain walks with pointer chasing on every lookup.
Text measurement (99.8% of calls) re-walks these chains per character,
thousands of times per frame during UI updates.

Shadow cache: 4096-entry direct-mapped array with Murmur2 hash,
keyed on (FontObject*, charCode, param2). Cache hit returns the
cached float width via FPU ST(0) inline asm, skipping the chain
walk entirely. Gated behind ab_use_custom for A/B benchmarking.
2026-03-13 11:55:17 -07:00
MarcelineVQ 0807612699 Add ReleaseFast SSE build unit, weather override Lua API, and research notes
build.zig: add clip_sse.zig as separate ReleaseFast compilation unit,
enable SSE/SSE2 target features, disable dpslog default.
main.zig: register SetWeatherOverride Lua func, call transform44.lateInit
for blit_hub hook capture.
RESEARCH.md: document GxDevice wrappers, weather control, RTQ batching.
2026-03-12 18:46:54 -07:00
MarcelineVQ fc7f6d637b Add SSE multiplyMatrix4x4 hook (0x7bc6a0) with A/B benchmark — 4.3x speedup
Standalone SSE 4x4 matrix multiply replacing 542 bytes of x87 FPU.
Refactored rotateMatrixByAxisAngle to call the new function (with temp
buffer to avoid aliasing). All 5 SSE replacements now confirmed winners:
clip (4x), triplane (10x), rotmat (4.3x), raytri (1.3x), matmul (4.3x).
2026-03-12 18:44:02 -07:00
MarcelineVQ 53fb100368 Fix bone count: model container is at this+0x30 not this+0x2C
Ghidra decompiler swapped the two fields. Assembly verification shows:
  +0x2C = animation_context_ptr (sync check at +0x10)
  +0x30 = model_container_ptr (+0x130 = M2 model header)
Bone count chain: *(*(*(this+0x30) + 0x130) + 0x34)
2026-03-12 11:45:35 -07:00
MarcelineVQ 484a988c77 Update RESEARCH.md with corrected SceneObject->M2 pointer chain 2026-03-12 11:35:12 -07:00
MarcelineVQ f46e5d07f4 Fix bone count read: add missing +0x130 indirection to M2 header 2026-03-12 11:29:42 -07:00
MarcelineVQ 83a55150b9 Fix overflow panic: all profiling counters to u64 with saturating ops 2026-03-12 11:19:48 -07:00
MarcelineVQ 1f4f2b03c4 Increase profiling dump interval to 600 frames (~10s) 2026-03-12 11:10:15 -07:00
MarcelineVQ 67ffaa7315 Add frame time percentages to render pipeline profiling
Track frame-to-frame wall time via rdtsc delta at executeSceneRenderPass.
Stats dump now shows each function's cycles as % of total frame time,
plus rough ms estimate at 3GHz. Helps identify which functions dominate.
2026-03-12 11:06:58 -07:00
MarcelineVQ cfc252f161 Add render pipeline profiling: 5 hooks across render/movement path
Hooks executeSceneRenderPass (0x708900), renderFrame (0x707680),
transformMatrix4x4 (0x714260), RenderTextureQuads (0x76FB00), and
CMovement::ProcessUnitMovementUpdate (0x616620).

Unified stats dump every 180 render passes shows per-frame call counts,
cycle costs, bone counts, recursion depth, and quad item counts.
2026-03-12 11:03:23 -07:00
MarcelineVQ b771d7a982 Save decompiled inner functions for transform44 reference
Ghidra decompilation of all inner functions called by transformMatrix4x4,
plus the full 2263-line main function decompilation.
2026-03-12 10:55:19 -07:00
MarcelineVQ 572635dd9f Add transform44 profiling hook and inner function analysis
Phase 1 profiling: hooks transformMatrix4x4 (0x714260) to measure call
frequency, early-exit rate, cycle cost, bone counts, and recursion depth.
Dumps stats every 500 calls.

Decompiled and analyzed all 11 inner functions. Key findings:
- findInterpolationIndices already has good temporal coherence (linear scan)
- Matrix math (scale, translate) uses x87 FPU — SSE candidates
- Game already has SSE matrix multiply used by rotateMatrixByQuaternion
- interpolateAnimationKeyframes does 4-component lerp — textbook SSE
2026-03-12 10:49:27 -07:00
MarcelineVQ c7a293bec4 Add research notes for SuperWoW events and transformMatrix4x4 analysis 2026-03-12 10:38:11 -07:00
MarcelineVQ 9965a50aab Add transform44 module stub for M2 bone transform optimization
Wires transform44 into build system and main.zig module table.
Module skeleton with mutex/logger, no hooks yet — analysis in progress.
2026-03-12 10:36:36 -07:00