Skip to content

perf(agc): do not store a compute fill a multisampled target takes as its clear - #5313

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
Raghav314:perf/agc-msaa-fill-host-only
Oct 14, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
Raghav314:perf/agc-msaa-fill-host-only

Conversation

@Raghav314

@Raghav314 Raghav314 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What

A multisampled color target keeps its samples only in its host image, and the driver refuses every guest read of its color memory that it checks (RequireNoMultisampleTarget: CPU reads, texture and storage image reads, DMA copies). Since #2132 a uniform fill over that memory is noted as the target's clear (NoteColorMetadataFill). BufferFill still stored the fill into the host import as well, so the GPU wrote bytes over PCIe that only reads the guard does not check could see.

  • MultisampledColorFillAbsorbs(address, bytes, pattern): whether a live (not retired, fix(agc): retire fully unmapped multisample targets #4474) multisampled target takes the fill as its clear: it starts at the target's address, is exactly its color footprint (MultisampledColorBytes), and the value has an exact clear color in the format (MultisampledFillClearColor).
  • BufferFill does not store such a fill (and skips the pre-store flush for it) when it is uniform and no storage image or DCC keys cover the range. Every other fill is stored as before, including a fill over part of the color memory, one reaching past it, and one with no exact clear value. The clear is noted as before.
  • The [fill] line (APS5_PROFILE_DRAW) counts the fills not stored.
  • The multisampled color fills entry in docs/dev/debt/libSceAgcDriver.md notes what is not covered: a target is retired only when its whole range is unmapped or its allocation removed, so a title that reuses a target's memory for other data while it stays mapped and reads it through a path the guard does not check (a V# buffer or a pointer) sees the bytes from before the fill.

PPSA36082

Hades II clears its two 4x targets with compute fills (0x2400000 bytes over a 1536x1536 sRGB 8_8_8_8 target and 0xff0000 bytes over a 960x540 16_16_16_16 float target, as in #2132), the smaller one about 7 times a frame. Standing in the hub, that was 10 fills and ~134 MiB per frame written into the import at ~25 GB/s, 5.5 ms of GPU time per frame. With this change the GPU is busy 2.9 ms per frame instead of 9.1. On main the queue worker is the limit in the hub, so the frame time barely moves there; on a local stack whose worker is faster the same change took the hub from about 75 to about 80 fps, with the GPU idle for most of the frame. The picture in the hub is unchanged.

Tested

Linux (CachyOS), x86-64, GCC, 7800X3D / RTX 4090, NVIDIA 615.78.08.

  • New agc_driver_multisample_fill_host_only, through the driver's compute fill path on a 4x 64x64 target: a fill of 0 over the whole color memory leaves the guest bytes as they were, a fill over half of it is stored, a fill over plain memory is stored before and after the target exists, on an sRGB target a fill with no exact clear value (0x80808080) is stored, and once the target's allocation is removed (retired) a fill over its old color memory is stored. It also checks the footprint match (half, offset, reaching past). Reports a skip when the device has no 4x color targets or does not store compute fills. Fails with the absorb disabled, with >= instead of an exact footprint, with the clear value check dropped, and with the retired check dropped.
  • The linux job of current build.yml run locally on this head (main 016db92): configure with SPIRV tools on, test registration check, build, libs, ctest 1092/1093, check_skips.py clean (7 expected skips). The one failure, agc_driver_bc_block_copy (BC7 through 32x4 uint blocks), fails the same way with this change's files reverted to main's, on this NVIDIA driver.
  • tools/pr_overlap.py --branch: no overlap with open pull requests.
  • Performance, hub standing still, same machine, APS5_HOST_IMPORT_MIB=6784, timing log off (traces attached). The main line is from main 91ed4ce built this morning (dirty because it was built from a local branch with its one commit reverted):
    • main: {"commit": "b9d3c9268562", "dirty": true, "window": {"spec": "seconds 75:15"}, "presents": 485, "frame_ms": {"p50": 31.468, "p90": 32.506, "p99": 33.869, "max": 38.167}, "gpu_busy_ms_per_present": 9.146, "worker_busy_pct": {"queue worker 0x0": 98.915}}
    • this PR: {"commit": "5d0a4b219d48", "dirty": false, "window": {"spec": "seconds 120:15"}, "presents": 510, "frame_ms": {"p50": 29.537, "p90": 31.009, "p99": 32.247, "max": 33.134}, "gpu_busy_ms_per_present": 2.868, "worker_busy_pct": {"queue worker 0x0": 99.069}}

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 4090, 615.78.08, Linux 7.2.9 (CachyOS)
  • AI-assisted: yes

@Raghav314

Copy link
Copy Markdown
Contributor Author

Traces for the two summary lines in the description, hub standing still on an RTX 4090 (open in ui.perfetto.dev). The main one is 91ed4ce with the timing log off; the PR one is the head before the rebase (5d0a4b219), same code.

pr-5313-hub.json.gz
main-91ed4ce62-hub.json.gz

LLM assistance used.

… its clear

A multisampled color target keeps its samples only in its host image, and every guest read of its
color memory that the driver checks is refused (RequireNoMultisampleTarget). A uniform compute fill
over exactly its color memory with an exact clear value becomes the target's clear through
NoteColorMetadataFill, so BufferFill no longer stores it into the host import as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Raghav314
Raghav314 force-pushed the perf/agc-msaa-fill-host-only branch from 2981939 to 5acd68f Compare October 14, 2026 02:14
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 14, 2026
@oneandonlydean
oneandonlydean merged commit d000959 into boykopovar:main Oct 14, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants