You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AFMF_PRESENT_MODE (auto): a swapchain created in FIFO is created in MAILBOX when the surface
offers it, the allowed per-present modes (VK_EXT_swapchain_maintenance1) get MAILBOX added,
and a per-present switch back to FIFO is rewritten. In FIFO the doubled presents each took a
refresh slot: vkcube at 165 Hz got 2 companions in 1196 presents, now 595 in 596. keep
leaves the game's mode alone.
AFMF_STATIC_BLOCK_SAD (128): the block search skips blocks that did not change between the
two frames (their SAD at rest, which the SDK already computed for its level-0 fallback, is taken
first); still parts of the picture cost nothing to search. One marked edit in the vendored
search shader, listed in shaders/fidelityfx/NOTICE.md.
The scene change detector's histogram runs alongside the luma pyramid and its divergence
alongside the coarsest search, with no barrier in between (both only read the level-0 luma;
the coarsest search reads the detector's output without waiting, which every finer level and
the interpolator still do), and the block search checks a group's four predictions at once
before any of them searches.
AFMF_SAD_INT16 (on): the block search's sum of absolute differences runs on packed 16-bit
byte pairs (v_pk_* on RDNA) instead of one byte at a time, from a second build of the SDK's
search pass; the layer enables shaderInt16 at device creation when the game did not and the
device offers it. Test headless_pan_scalar_sad checks the SDK's sum gives the same field.
AFMF_DIRECT_INGEST (on): the game's frame is read once, from its swapchain image, into the
colour ring and the flow's luma by one pass, instead of copied and then read again by the
SDK's luma pass. Not on sRGB swapchains.
AFMF_DIRECT_OUTPUT (off): the interpolator writes the swapchain image itself instead of an
internal image copied there; opt-in because it needs storage usage on the game's swapchain
images, whose cost to the game's rendering only a game measurement can tell. Test headless_direct_output.
AFMF_HUD_DETECT (on): a pixel unchanged between the two frames on a moving block is kept as
it is instead of warped, so a HUD, crosshair or subtitle over motion stays whole in the
generated frame. Tests headless_hud and its negative control headless_hud_negative.
Defaults now aim at quality: flow at display resolution with all seven pyramid levels
(AFMF_PERFORMANCE_MODE=quality, AFMF_SEARCH_MODE=high), AFMF_FAST_MOTION_RESPONSE=blend, AFMF_LOG=0. The block search skips every block whose vector from the coarser level already
matches (AFMF_STATIC_BLOCK_SAD), which is what keeps the cost of the full search near the
previous release's half-resolution one.
AFMF_GOVERNOR (on by default): under GPU contention, when the generated frame is ready later
than a frame and a half thirty frames in a row, generation steps down (five search levels, then
one companion in two, then one in three) and steps back up after 15 frames ready within three
quarters of a frame; each step is logged. AFMF_MIN_FPS (30): no companions below that real frame rate.
Present ids (VK_KHR_present_id and present_id2, what DXVK attaches) are carried on the real
frame by the presentation thread instead of forcing the present inline; tests headless_present_id1
and headless_present_id2.
Changed
The present hook no longer records or submits: it consumes the game's wait semaphores with
an empty submission (they must be waited before the game signals them again) and queues the
frame to a work thread, which waits the slot, takes the companion's image, records, submits and
hands the presents to the presentation thread. The profile line splits the three: in the hook, work thread, presentation thread. Test headless_async_drain destroys the swapchain
with frames still in both threads.
The layer's pipelines compile on a thread of their own from vkCreateDevice; the first
swapchain only waits for what is left instead of compiling everything on the first present.
The optical flow and the interpolation are recorded once per (slot, parity, companion) into
secondary command buffers and executed from then on; the per-frame primary keeps only the
copies from and to the swapchain images. Host time recording a frame in the present hook:
170-190 us to 80-117 us in the headless test under the validation layer.
Pacing measures the half-frame hold from the moment the generated frame is ready on the GPU, not
from the present call, capped at one frame after it; the profile line shows the delay as gpu done.
Fixed
The headless golden test looked at the companions of real frames 1 and 2, which the optical
flow's scene change detector zeroes during its six-frame warm-up: what it measured was a
motionless blend of the two frames, whose centre is the same. Dumps now start at frame 8 and
the test also checks the flow vectors on the square (afmf_flow_<frame>.txt); a failed check
now fails the test (FAIL_REGULAR_EXPRESSION matched a ^ that CMake does not treat as a
line start).
The application's vkGetSwapchainImagesKHR is serialised with the presentation thread's presents
(a thread-safety validation error when both ran at once).
The presentation thread could starve on the swapchain lock behind an application spinning in vkAcquireNextImageKHR (a glibc mutex is not fair): presents stalled for seconds and no image
ever came free. The lock is now taken in turn, and the spare's release fence is waited on outside
it.
The pacing hold ends when the next real frame arrives, and a single hitch (a 100 ms frame) no
longer inflates the frame-time estimate: after one, the real frames were held up to 20 ms each,
images ran out and AFMF_MIN_FPS withheld companions for a while.
AFMF_ACQUIRE_TIMEOUT_US also bounds the acquire of the companion's image, not only its release
fence; frames withheld by AFMF_MIN_FPS are counted in the swapchain's report.