Files
AnyPS5/docs/dev
thuanquangandClaude 175d986c28 perf(agc): create the host import of a linear color target in registered memory
A linear color target got a resident image only when its memory already
had a host import (#6892). Every other draw into it was synchronous:
copied in, drawn, waited for on the CPU and copied back. #6892 only
looked the import up because a first version that made it broke
agc_driver_pixel_ancillary_word and agc_driver_pixel_fixed_point_position:
the import over a short-lived block was compared, and the next block
allocated at the same address stayed outside the write watch. A page
committed again inside an excluded block is watched again since #6759.

On a lookup miss the draw now makes the import itself, with the new
ColorTarget requester, when its registered ranges are writable, the
whole import run is write-watched and the import keeps it watched: a
separate alias of shared memory, a direct import of private memory that
settles on Windows (1 MiB or more, when the import probe keeps the
watch and a settle queue exists), or an import the probe keeps watched
on other systems, where a dma-buf import must stay watched too if the
range has shared backing. Private pages that the write watch armed
read-only count as writable when their guest protection is, because the
import opens them (a resident direct-memory run the CPU has not stored
to since its last collect). The gate's scan stops at the first page
that decides a refusal, and a run of private memory whose direct import
would be compared is refused after one page query. A refusal is
remembered for its run until the registry, the committed pages
(Windows) or the write watch change, or a shared alias is mapped over
the run, so a target that stays synchronous costs a lookup per draw.
importRunAt checks this after its remembered failures and refusals and
before it retires or evicts anything, through the helpers its own
decision now uses: importWatching (settled, watched host-pointer and
dma-buf imports) and importPages (the Windows page scan). A target whose
import would be compared stays synchronous, because a compared import
makes every refresh of the resident image compare the whole target. A
target over an import that already exists is resident as before, with
ExistingHostImportFor as the fast path, and APS5_NO_RESIDENT_LINEAR=1
still keeps every linear target synchronous.

This is the case draft #1191 (MichonGoddijn231849) was to bring back
on top of #6892 once partial-block write-watch coverage existed.

agc_driver_linear_target_import_creation covers a target in freshly
registered, write-watched memory (the draw is recorded, the target is
imported and stays watched), a block freed and allocated again at the
same address (it is watched, and the next draw starts from the CPU's
bytes), a resident direct-memory run armed read-only by the write watch
(the draw is recorded and the target imported; Windows), the gate over
armed and read-only private memory (a compared import of an armed run is
refused without opening it, memory committed read-only behind a writable
registry range is refused without a count, an armed run is imported
where imports stay watched; Windows), a 64 KiB block whose import would
be compared (no import, a synchronous draw, the block stays watched), a
1 MiB block the guest registered read-only (no import, a synchronous
draw), a 1 MiB run with one 64 KiB block outside the write watch
(refused, the target stays watched), and the same run once that block is
committed again (the refused run is imported; Windows).
On other systems the test forces ImportWatch::Watch, so the watched
cases also run where imports are compared (lavapipe in CI). The import
requester tests count the new requester and check that it makes no
compared import, no import of a range the guest cannot write and no
import of memory outside the write watch.

Co-Authored-By: Claude <[email protected]>
2026-10-23 16:54:49 +07:00
..