The D3D12 PipelineBlendFactor enum had no constant-alpha entry, so the Xenos
CONSTANT_ALPHA and ONE_MINUS_CONSTANT_ALPHA blend factors (14, 15) were mapped
onto the constant-COLOR kBlendFactor / kInvBlendFactor - i.e. D3D12 BLEND_FACTOR
/ INV_BLEND_FACTOR, which use the blend constant's RGB rather than its alpha.
Aircraft ground shadow blends with dst = ONE_MINUS_CONSTANT_ALPHA and aSTANT_ALPHA blend factors collapsing onto
blend constant of (0.03, 0.04, 0.04, 0.30): it wants 1 - 0.30 = 0.70 (scale the
background down -> darken), but got 1 - (0.03,0.04,0.04) ~= 0.97 (barely scaled)
with the white source added on top, so the shadow BRIGHTENED instead of
darkening - the "white shadow" bug. Vulkan has the distinct
ONE_MINUS_CONSTANT_ALPHA factor and renders it correctly.
Add kBlendFactorAlpha / kInvBlendFactorAlpha to the enum, route factors 14/15 to
them in both the colour and alpha maps, and map them to D3D12 ALPHA_FACTOR /
INV_ALPHA_FACTOR. Verified fixed on both the RTV and ROV render-target paths.
Extract the build watermark into its own BuildStampOverlay (rex/ui/overlay/build_stamp_overlay.*), a non-interactive drawer in the lower-left corner - independent of the F3 debug overlay. It stamps the short git commit hash (REXGLUE_GIT_HASH, captured by CMake via git rev-parse --short HEAD -> version.h; re-run cmake to refresh) via REXGLUE_BUILD_HASH_STAMP, instead of the build date. Drawing is gated by the show_build_stamp cvar (category UI, default true) so players can hide it; registered next to the other built-in overlays in rex_app.
Guest swap thread blocks on real GPU delivery (NotifyGuestPresent feeds the delivery counter) + an absolute-deadline limiter at ac6_fps_target, not the vblank grid (no sub-harmonic staircase). dt-snap locks the sim delta to the exact target at steady rate (kills the shake). Guest vblank forced to free-run during gameplay so pacing needs zero config. ac6_unlock_fps is the single master switch, ON by default (folded in timing-hooks/vblank-auto/delta-precision/dt-snap-tolerance AND the flight-model framerate-independence fix).
FPS/frametime counters (avg 0.5s), two fixed-time-interval frametime graphs (fps-independent, spikes preserved), present-wait metric (rex/ui/present_stats.h). Guest stats provider wired in OnCreateDialogs. Removed the old inline F3-only build watermark (moves to a standalone always-on drawer in a later commit).
With the unlock forcing single-vblank presents, frame-locked content (menus,
hangar, in-engine cutscenes) free-runs far too fast while only gameplay should.
Pace the guest vblank dynamically: free-run only while the 3D world is being
rendered, otherwise force the native 60Hz.
"World is rendering" is detected from the GPU side - the command processor
stamps a heartbeat (NotifyWorldCompositorDraw) whenever a draw uses the
world/effects compositor pixel shader (ucode 17e5e4ac3e713245), which runs
every frame of 3D but never in the 2D front-end. The present timing hook then
sets a guest-vblank Hz override via the new GraphicsSystem hook. Only engages
under the unlock; ac6_dynamic_vblank=false restores the plain always-on unlock.
The sun lens-flare draw (VS ADF9AFC4C10921B9 emits two billboards:
V0-V3 = the visible glow quad, V4-V7 = a malformed quad that mis-renders
in the emulator as a faint bright rectangle in the sky (the "square").
Cull it in the vertex shader using the translator's existing kill-vertex
mechanism: in CompleteVertexOrDomainShader, for this ucode hash
(plain host VS only), vertices with SV_VertexID >= ac6_flare_drop_index_min
(default 4) get a NaN output position, so the rasterizer discards the primitive.
The real glow (V0-V3) is untouched.
cvars: ac6_flare_drop_quad2 (bool, default true), ac6_flare_drop_index_min
(int32, default 4). Baked at shader translation.
Missile/jet trail position history is a fixed guest-address ring, so its
vertex fetch constants never change and the command processor's
vertex_buffer_states_ address cache skipped RequestRange forever, the GPU
copy of the trail history froze at zero (trails invisible) while CPU memory was
correct.
Register a physical-memory invalidation callback that flags when the CPU writes
watched GPU-visible memory, and drop the cached vertex-buffer states at the next
draw so the ring's pages get re-uploaded. Also notify those callbacks from the
access-violation page-recovery path (xmemory), since a recovered page becomes
read-write and would otherwise never fault again to report the write. Gated by
ac6_fix_trails (default ON).
Upscale mosaic. At draw-resolution scale > 1, AC6's deferred
EDRAM restore passes do integer pixel-address math on the PsParamGen
position. Its leftover sub-guest-pixel fraction scrambles into an 8x8
mosaic. Floor the param-gen position (param_gen_integer_guest_position)
and re-add the host sub-pixel at the fetch (param_gen_host_subpixel_restore).
Inert at 1x.
De-swizzle scramble. Some AC6 restore/resample passes
manually de-swizzle the Xenos EDRAM sub-tile layout of their source, which
is only correct on tiled data. The emulator detiles everything to linear,
so the de-swizzle always scrambles, streaking the cloud/effects pipeline.
For allowlisted shader hashes (ac6_neutralize_deswizzle_hashes) the sample
coordinate is replaced with the identity host-texel UV (a 1:1 copy).
Suspend the FPS unlock while a demo-manager Exec (DD sub_82184460 / EM sub_821856F8) ticks, so the frame-locked IngameCinematics Sequencer plays at native ~30fps instead of double speed. Adds ac6_cutscene_clamp CVar (default on).
D3D12 previously assumed native point-list + geometry-shader expansion; that path can drop or rasterize points incorrectly (invisible missile trails). Default to the shared triangle-strip VS expansion path with an init-time CVar override.
Vulkan: default vulkan_force_expand_point_sprites_in_vs to true for the same behavior on non-D3D12 hosts.
Made-with: Cursor
Add a native SDL3 audio driver for non-Windows hosts and gate WASAPI to Windows-only builds, so Linux builds no longer depend on Windows headers while keeping runtime telemetry and queue behavior intact.
Made-with: Cursor