Skip to content

feat(agc): support uniform custom MSAA sample locations - #2169

Merged
oneandonlydean merged 6 commits into
boykopovar:mainfrom
authurtabo-byte:feat/agc-uniform-sample-locations
Oct 12, 2026
Merged

oneandonlydean merged 6 commits into
boykopovar:mainfrom
authurtabo-byte:feat/agc-uniform-sample-locations

Conversation

@authurtabo-byte

@authurtabo-byte authurtabo-byte commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

What

Depends on #419. Its prerequisite commits are included; the follow-up is feat(agc): support uniform custom MSAA sample locations.

After multisampled targets are supported, 3D MiniGolf (PPSA03647) aborts while loading its first course because its four PA_SC_AA_SAMPLE_LOCS_PIXEL registers contain 0x22eea66a, rather than Vulkan's standard four-sample pattern. Preserve the guest's sample indices and signed sixteenth-pixel offsets through VK_EXT_sample_locations for uniform 2x, 4x and 8x patterns.

Query the device's sample counts, coordinate range, subpixel precision and grid support before enabling the extension. Include the pattern in pipeline and render-pass continuation keys, check the actual depth format and sample count with vkGetPhysicalDeviceImageFormatProperties, create compatible depth images, and supply sample locations at pipeline creation and render-pass begin. Depth attachments retain GENERAL throughout their use. Spatially varying 2x2 patterns and unsupported devices throw. CB resolves validate sample counts independently of raster sample locations.

Vulkan behavior follows the official sample-location pipeline state, render-pass state, and depth-attachment requirement. The guest coordinate interpretation is unchanged from #419; PS5 coverage and interpolation equivalence remain unmeasured and are recorded in TechnicalDebt.

Tested

Rebased onto main c9da0f93. Preserved upstream depth-surface extent/format checks while retaining the prerequisite HTILE fast-clear handling. Windows, MinGW-w64 GCC 15.2.0, Release, NVIDIA GeForce RTX 3050 6GB Laptop GPU.

  • Independent build of this stacked contribution branch: production libSceAgcDriver, agc_driver_graphics_tests, and both depth fast-clear test targets build successfully. All three focused tests pass: agc_driver_graphics (6.25 s), agc_driver_depth_fast_clear (1.23 s), and agc_driver_depth_fast_clear_submit (0.47 s).
  • Fixed a missing closing brace between the existing unsigned-color export tests and sample-location capability test helpers; the rebuilt graphics tests include upstream depth-surface reuse regressions.
  • Regression cases cover custom coordinates and sample indices, signed endpoints for 2x/8x, the normalized standard 4x coordinates, spatially varying pattern refusal, missing extension/count support, unsupported depth formats and depth sample counts, exact image-query flags and usage, and standard-pattern fallback. Unexpected Vulkan query errors propagate. Capability queries run at pipeline creation, rather than on each draw.
  • tools/check_conventions.py --base origin/main passes.
  • Earlier MiniGolf (PPSA03647) integration test: course loading changes from nonstandard sample locations are unsupported to a rendered course and HUD. The separate unwritten-pixel-program blocker is covered by fix(agc): read an unwritten pixel program address as unset #2022. A completed shot is not confirmed; this PR alone does not provide all title startup fixes.
  • Raghav314 independently tested the previous revision on Linux/RTX 4090 with Hades II (PPSA36082), stacked with feat(agc): multisampled color and depth targets with CB resolves #419, fix(agc): take a CB resolve's sample count from its source target #2121 and fix(agc): clear a multisampled target on a uniform fill of its color memory #2132: custom 0x444cc4cc locations rendered correctly in gameplay. His overlapping feat(agc): pass custom sample locations through VK_EXT_sample_locations #2183 was closed in favor of this PR. The depth-format capability check and standard-coordinate regression above address his feedback.

Linux was not rerun locally. Validation layers and console coverage/interpolation equivalence were not tested. Guest coordinate interpretation remains documented as inferred in TechnicalDebt.

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; no silent stubs added
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source: none added
  • Generic behaviour, not specific to one title
  • Depends on: feat(agc): multisampled color and depth targets with CB resolves #419
  • AI-assisted: yes, Codex

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#1316 core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp L173
#1368 core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp L15
#2121 docs/dev/TechnicalDebt.md L559
#3846 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp L189
#4106 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp L1153
#4199 docs/dev/TechnicalDebt.md L559

@Raghav314

Copy link
Copy Markdown
Contributor

Tested this with Hades II (PPSA36082) on Linux / RTX 4090. It needs the same thing with a different pattern: PA_SC_AA_SAMPLE_LOCS is 0x444cc4cc for all four pixels, an ordered (±4, ±4)/16 grid on its 4x targets. With this commit in place of my own version, it renders correctly in gameplay with no refusals in the log. (Stack: #419 plus my #2121 and #2132.)

One thing I ran into doing the same change: vkCreateImage needs SAMPLE_LOCATIONS_COMPATIBLE_DEPTH to be supported for the depth format and sample count, and the extension's sample counts alone don't guarantee that. I checked it with vkGetPhysicalDeviceImageFormatProperties (the flag plus the image's usage) before setting it, and refused a custom-location draw whose depth format the device can't support. Every depth format passes on the 4090, so it doesn't change anything there, but it might matter on other drivers.

If it's useful as a test: the console's standard 4x offsets {-2,-6}, {6,-2}, {-6,2}, {2,6} should come out as Vulkan's standard 4x positions (0.375, 0.125), (0.875, 0.375), (0.125, 0.625), (0.625, 0.875). That checks both the 1/16 scale and the y direction in one go.

I opened #2183 before I saw this one. I'll close it, since this came first and covers more (render-pass begin, devices without variable locations).

@JAB-dev

JAB-dev commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Tested this at 0485363 on Seeker: My Shadow (PPSA12500, Unity), Windows 11, RTX 4070 SUPER. It renders into 4x MSAA targets (PA_SC_AA_CONFIG 0x0020c002) with nonstandard sample positions. Without it the title stops at multisampling or coverage conversion is unsupported, with #419 alone at nonstandard sample locations are unsupported, and with this PR it gets past both.

@authurtabo-byte

Copy link
Copy Markdown
Contributor Author

Thanks @Raghav314 and @JAB-dev for testing across Hades II (Linux/NVIDIA) and Seeker: My Shadow (Windows/NVIDIA).

Pushed \d92a665f:

  • Validates \SAMPLE_LOCATIONS_COMPATIBLE_DEPTH\ via \�kGetPhysicalDeviceImageFormatProperties\ before attaching the flag, ensuring incompatible depth formats fall back safely.
  • Added regression coverage in \Graphics.cpp\ for depth format compatibility and verified that standard 4x sample offsets {-2,-6}, {6,-2}, {-6,2}, {2,6}\ map to Vulkan positions (0.375, 0.125), (0.875, 0.375), (0.125, 0.625), (0.625, 0.875).
  • \�gc_driver_graphics\ passes cleanly.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the sample count and pattern to the fragment keys; that covers the earlier request. Built the PR merged onto main and ran the libSceAgcDriver ctest scope (391/391 pass, including agc_driver_graphics and agc_driver_prepared_graphics).

One thing left, also reported by @cookie42073-cmd:

  • libraryKeys (Graphics/src/Pipeline.cpp:197-205): the resolved sampleLocationsEnabled from ValidateSampleLocations (Pipeline.cpp:110-115) depends on the depth format, but isn't part of keys.fragmentShader / keys.fragmentOutput. Two draws with the same pattern and sample count but a compatible vs. incompatible depth format can reuse a library built with the other enablement, which links different multisample states (VUID 06635). Append the resolved value to both keys and add a case with the same pattern and two depth formats.

Still stacked on #419; this will wait for it to land, then rebase so it only carries its own commit.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Can you rebase this please?

authurtabo-byte and others added 6 commits October 11, 2026 20:36
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Vulkan's standard 8x sample 7 is (0.9375, 0.0625), (7, -7) in signed sixteenths; the table had (7, -8), so the
standard pattern (PPSA99902's PA_SC_AA_SAMPLE_LOCS words 0xbd153fd1 / 0x9773f95b) was refused as nonstandard.
Regression row with those words.

Reported by @Amoenus.

Co-Authored-By: Amoenus <5391396+Amoenus@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9a1a067)
@authurtabo-byte
authurtabo-byte force-pushed the feat/agc-uniform-sample-locations branch from 589d42b to 605741d Compare October 12, 2026 03:43
@authurtabo-byte

Copy link
Copy Markdown
Contributor Author

Thanks everyone for the review and title testing. I?ve pushed the rebased update; it is now based on current main and no longer includes the #419 commits.

  • GPL cache reuse (adriadam10, cookie42073-cmd): both fragment library keys now include sample count, the custom-pattern flag and active sample bytes, plus the resolved sample-locations-enabled value. That last value depends on depth-format compatibility, so compatible and incompatible depth states cannot reuse the wrong library. Recorder coverage checks pattern changes and, when this device exposes both cases, changes between compatible and incompatible depth formats.
  • Depth support and sample conversion (Raghav314): custom locations are still rejected when SAMPLE_LOCATIONS_COMPATIBLE_DEPTH is unavailable for the selected depth format and sample count. The standard 4? coordinate checks remain in Graphics tests.
  • Standard 8? table (Amoenus): corrected sample 7 from (7, -8) to (7, -7), avoiding treating that standard pattern as custom. The captured 8? pattern remains a useful independent regression report.
  • Title testing: the reports for Hades II (Raghav314) and Seeker: My Shadow (JAB-dev), plus the other shared title reports, are helpful confirmation of the original gameplay blocker and custom patterns. I did not reproduce Hades II here. I tried MiniGolf 3D as requested, but its packaged runtime modules are ABI-incompatible with the freshly built libraries (AgcDriver import, then libc import after rebuilding VideoOut), so it did not reach gameplay and is not claimed as a passing test.
  • Coverage/centroid observation (Amoenus): this change does not alter the existing refusal for the separate covered-centroid/coverage state. The register observation is useful, but changing that behavior needs its own equivalence validation.

Locally on Windows / AMD Radeon 780M, agc_driver_recorder_tests.exe --pipeline-library-only passes, including the new cache checks, and agc_driver_graphics_tests.exe passes. No PS5 hardware run is claimed.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 12, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 12, 2026
@oneandonlydean
oneandonlydean merged commit 2ccbd37 into boykopovar:main Oct 12, 2026
12 checks passed
@cookie42073-cmd

Copy link
Copy Markdown
Contributor

Hi, Blazing Cook here. Following up on the earlier Ping Pong testing: we completed a full one-player match in Middle Ages Ping Pong on unmodified upstream 2a5eca11cd1bf583db39ce67034e8453842ac244, with restart and menu transitions working in the same run.

Tested STL1te's Middle Ages Ping Pong, PPSA28319 / 01.000.000, on Windows with an RTX 4070 SUPER. This was a fresh Release build with MinGW-w64 GCC 15.2.0 and a fresh relink, without local production patches or a diagnostic library overlay. Relink inputs were reconstructed from the release; packaged ELF headers and PT_LOAD payloads were independently matched. Original full-ELF equivalence is not claimed.

Using upstream tools/pad_input.py / APS5_PAD_INPUT_FILE, the saved frames show:

  • A one-player match starts at 0:0.
  • The match finishes 0:10, showing Defeat / Computer wins. I moved the player paddle aside to reach the end screen.
  • Restart resets the score to 0:0 and returns to the Serve prompt.
  • Options opens pause; selecting Main Menu returns to the title menu.
  • Starting another one-player match returns to 0:0.

The capture ran for 317.624 seconds, saving 314 raw GPU frames. It ended with a requested recorder stop after those checks. The recorded game exit code 1 is from that deliberate process termination; it is not a spontaneous crash or a graceful in-game exit. Neither game log contains the fatal, unsupported, assertion or Vulkan-error signatures checked by the analysis script.

The full default build and libs completed, and 12 selected memory, input and graphics tests passed, with Vulkan required and no skips. The full test suite was not run. FFmpeg used the existing upstream prebuilt package, with its recipe and file hashes recorded. A second Codex chat independently checked all 11 selected images against the original BMPs, the logs, build receipts and file hashes.

This is a compatibility follow-up after the upstream work in #419 and #2169, not an isolated before/after result for either change. Thanks to MichonGoddijn231849, authurtabo-byte and everyone who reviewed and tested them. STL1te is the homebrew author. There is no new code fix from this run.

Victory, two-player mode, physical input, fullscreen, audio quality, performance and PS5 pixel equivalence remain untested. Frame readback and disabled caches make this unsuitable as a performance benchmark. These results also do not establish any commercial-title memory failure.

If anyone reproduces a failure in this title, please share the exact AnyPS5 commit, title version, OS/GPU, reproduction steps and runtime log so we can compare it with this baseline.

AI-assisted: yes, Codex. The attached evidence contains logs, frames, scripts and verification receipts, with no game binaries or assets.

Evidence ZIP — SHA-256: d7aeda6e33b29c5b6fbace77c2fa7fc4be3eaa4806e5eb7eac4faf8090c3567a

Completed match, restart, main menu and fresh match

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants