Commit Graph
7963 Commits
Author SHA1 Message Date
hypermistandClaude Opus 5.5 0d62d4ee1a feat(libc): implement the compiler-rt integer builtins
Shifts, bit counts, comparisons, negation, multiplication, division and
remainder, __udivmodti4, the overflow-reporting __mulo* and the overflow
checking __addv*/__subv*/__mulv*/__negv*/__absv* families. Where the libc.prx
bundled with PPSA08427 differs from compiler-rt it is followed: __addv* and
__subv* wrap, and the 32-bit unsigned division returns 0 for a zero divisor.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Q8tinbP1MUpUaDsbNWnGnu
2026-10-16 00:30:58 +13:00
Adrià 5e7d09aafe Merge pull request #5538 from JJenkx/fix/ngs2-render-capacity
fix(ngs2): limit render writes to the configured grain
2026-10-15 13:29:33 +02:00
Adrià 821c69e504 Merge pull request #5509 from billythemenace2/fix/shader-cube-tsharp-2d-access
fix(shader): read cube T#s through DIM 2D image_sample and image_load as face 0
2026-10-15 13:25:34 +02:00
Adrià 39d3ae13eb Merge pull request #5304 from tv7/fix/stencil-ref-export-unused
fix(agc): drop an unused stencil test value export from draws without a stencil test
2026-10-15 13:24:56 +02:00
CapibaraandClaude Sonnet 5 efd5596008 docs(libSceRegMgr): record signature provenance in technical debt
Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-10-15 08:14:37 -03:00
hypermistandClaude Opus 5.5 7d7515b632 docs(debt): drop the call tracing entry that --trace-imports superseded
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-16 00:14:25 +13:00
Adrià FranchandClaude 91878f51f9 docs(debt): describe the TYPE=0 null image scope as implemented
Co-Authored-By: Claude <[email protected]>
2026-10-15 13:12:00 +02:00
Yunus Shaikh a34ba0c7c7 Merge branch 'main' into perf/shader-direct-cpu-evaluable-images 2026-10-15 03:54:08 -07:00
Adrià Franch 6f0aa97f6c docs(debt): describe the unused stencil export drop next to the stencil replay 2026-10-15 12:51:37 +02:00
NikoandClaude Opus 5.5 c434467f6c fix(agc): form reversed-order blend factors from copies of the export
The reversed-order blend computed the factors Vulkan cannot apply per
channel in the pixel shader (1 - x in fp32, a clamp for UNORM targets
and, when both positions needed it, a premultiplied export) and passed
them to the blend as a dual-source second color. A plain blend converts
the export once and forms 1 - x and the products from that converted
value, so the two paths can round differently. On UNORM8 the difference
reaches one step per substituted factor: an Intel iGPU stored 161 where
the exact blend is 159.75 for SRC_COLOR + ONE_MINUS_SRC_COLOR with an
export of 0.5 over 192 (160 through SWAP_STD), and on an RTX 5080 and
lavapipe the split path differed from the same draw into a SWAP_STD
target by up to 2 steps on other inputs.

The pixel shader now only copies values. Each channel of the second
color is the exported alpha, the channel's own export or the constant 0
or 1, and a channel of the first color whose source factor is ONE may
become 1 with its export moved into the factor. Every factor, 1 - x and
product comes from the blend through SRC1_COLOR, SRC1_ALPHA and their
ONE_MINUS forms, applied to copies of the same export values that the
first color carries. TranslateReversedBlend searches for Vulkan factors
and copy routes that reproduce each channel's guest factors and throws
for combinations no routing reproduces, such as ONE_MINUS_SRC_ALPHA in
the alpha equation next to SRC_COLOR in the color equation: of the 1995
factor combinations the shader used to compute, 932 are routed and the
others throw again, as on main. GT7's 0x65010504 is among the routed
ones. The code is now four 2-bit routes for each color, the same for
every format, and the post-pass emits no arithmetic.

agc_driver_reversed_order_blend also draws each case into a SWAP_STD
target, which Vulkan blends alone, and requires identical stored bits;
the comparison with the exact blend keeps its 1-step tolerance.
agc_driver_graphics checks every factor combination TranslateReversedBlend
accepts against the guest equations and that the post-pass adds no
arithmetic instructions.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 12:51:27 +02:00
NikoandClaude Opus 5.5 16ea32c97d feat(agc): blend into color targets with a reversed component order
8_8_8_8 and 16_16_16_16 targets with COMP_SWAP 2 or 3 keep the exported
alpha in their first channel and red or blue in their fourth, so a plain
Vulkan blend would run the alpha equation on a color channel. Such draws
threw "blending into a color target with a reversed component order is
not implemented" (Gran Turismo 7, #4782).

The AMD SI and CIK register references describe CB_TARGET_MASK in the
order of components after blending and before COMP_SWAP is applied, and
RADV programs CB_BLENDn_CONTROL without regard to the swap while it
renders R4G4B4A4, B4G4R4A4, R5G5B5A1 and B5G5R5A1 through SWAP_STD_REV
and SWAP_ALT_REV and passes the CTS blend tests on Navi10. The color
block is therefore taken to blend in export order: the alpha equation
and source-alpha factors use the exported alpha and the destination
alpha is the first channel.

TranslateReversedBlend keeps the factor pairs Vulkan applies per channel
in the pipeline. Other source factors are computed by the pixel shader
from its MRT0 export (clamped for UNORM targets, as BLEND_CLAMP says)
and handed to the blend as a dual-source second color, which the
fragment output post-pass adds at location 0 index 1; when both
positions need it, the export is premultiplied by its source factor.
The code is a pipeline specialization, serialized in request version
26, and stays out of the prepared shader key.

sRGB, SNORM and integer targets, constant and second-source factors,
destination alpha in the color equation, destination factors the two
equations do not share, different color and alpha operations, MIN or
MAX with factors other than ONE, other color exports when the shader
computes factors, and devices without dualSrcBlend still throw, now
with the blend control, mapping and format in the message.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 12:51:27 +02:00
Yunus Shaikh 0b099964f0 Merge branch 'main' into perf/shader-direct-cpu-evaluable-images 2026-10-15 03:19:52 -07:00
Adrià FranchandClaude 03401459f9 perf(agc): pipelined draws and exact draw write ranges on by default
Queue 0 now pipelines draw commits unless APS5_PIPELINED_DRAWS=0, and draw write ranges use the exact
color, DCC, CMASK, depth and stencil sizes unless APS5_EXACT_DRAW_WRITES=0. The base tests now run the
pipeline; agc_driver_pm4_failure_inline and agc_driver_draw_cache_reuse_inline keep the inline path
covered.

Co-Authored-By: Claude <[email protected]>
2026-10-15 12:13:26 +02:00
Romans Pokrovskis da9fe3c708 fix(agc): retire fully released native depth owners
Track successful releases cumulatively across the complete depth and HTILE ownership ranges. Preserve color retirement and share its single callback; keep retired image contents alive through sampled views and recorded work. Add registry, partial/failure/protection, remap and mixed teardown regressions. Depends on native depth sampling in PR5496 and its descriptor prerequisite PR4820.
2026-10-15 13:08:13 +03:00
Parth Bhanti c9d3ff87d9 fix(libkernel_sys): handle AT_SYMLINK_NOFOLLOW natively on macOS and document silent stub 2026-10-15 03:04:18 -07:00
Adrià FranchandClaude 4051ee19c5 docs(architecture): describe the queue-0 draw pipeline
Co-Authored-By: Claude <[email protected]>
2026-10-15 11:34:29 +02:00
Yunus Shaikh 896b737700 fix(libSceNet): keep one receive timeout across the wait for a local address
When the address came during the wait, the host receive that followed
waited its whole SO_RCVTIMEO again, so a receive could take up to twice
the timeout. FreeBSD's soreceive_dgram sleeps once per timeout. Now the
receive waits for a datagram with WSAPoll only for what is left of the
timeout, and fails with EAGAIN when it runs out, as before. Nothing
changes when the socket already had an address or has no timeout.
2026-10-15 02:34:12 -07:00
Santhosh Kumar 27b196bee0 fix(shader): preserve pixel helper lanes in EXEC copies
Expand the host active-lane mask to whole quads for pixel-stage EXEC value reads so saving and restoring WQM does not drop derivative inputs. Keep the existing host-lane mask in other stages. Add a GPU regression for implicit mip selection after an EXEC save/restore, across wave32/wave64 and native/emulated barycentrics.
2026-10-15 14:42:26 +05:30
eljackjoestar-cmd 6575aa217d fix(audio): retain completed AudioOut2 grains until pushed 2026-10-15 13:06:45 +04:00
SP4C3B4R-8andClaude Opus 5.5 626cff7d26 fix(libSceAgcDriver): retire a depth surface once another writer covers its memory
A depth surface lives only in its Vulkan image, so a view of its memory
with another layout could only throw, and a matching view kept reading
the image after other writes over its memory. Retire the surface when a
color target or a written storage image it does not serve overlaps its
planes, or when a view it cannot serve finds guest memory over the planes
written since the surface was last bound; lookups then skip it and the
view reads the memory like any texture. Binding the target again brings
the surface back.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 11:00:36 +02:00
Adrià 0afa6a607e Merge pull request #6060 from parl0v/feat/watched-private-imports
perf(agc): keep Windows host imports of write-watched private memory watched
2026-10-15 10:54:43 +02:00
Adrià c4f03522a7 Merge pull request #5496 from Amoenus/codex/native-msaa-depth
feat(agc): sample native multisampled depth attachments
2026-10-15 10:54:18 +02:00
Yunus Shaikh a9c2717fd0 fix(libSceNet): return 0 from an unbound datagram receive after shutdown or for zero bytes
On Windows a receive on a datagram socket with no local address waits
for one. A sceNetShutdown of the receive side now ends that wait, and
later receives return 0 at once; a zero-length receive returns 0 without
waiting. FreeBSD's soreceive_dgram returns 0 in both cases. Before, a
thread blocked in such a receive kept waiting after the socket was shut
down.
2026-10-15 01:54:10 -07:00
Yunus Shaikh fe56f60561 fix(shader): bind a T# whose record the CPU evaluates directly when a table cannot express its operation
An image table cannot store, update atomically or read PCK and BY2/BY4
through its records (#757): those operations fault and read zeros. #6243
turns a heap T# whose words and record offset the SRT walker evaluates
into a selected one-record table, which kept that limitation although
such a T# is one known descriptor, as #5188's direct images were.

PlanTableColumns now binds such a T# directly, for every operation of the
shader on it, when any of them is a store, an atomic, a packed or a
BY2/BY4 access. A T# keyed per lane, or by a value the walker cannot
evaluate, keeps its table and its unsupported-operation fault. The disk
format moves to 37 so that plans cached by #6243's builds are not reused.
2026-10-15 08:50:15 +00:00
Yunus Shaikh 17ccfc497c perf(shader): walk a changed table column from the words its compare read
A kept column the runtime cannot vouch for is read and compared with its kept words. When they
differ, the fresh walk read the same runs again, so a capture that follows every change to a table
read each word twice: 1,048,576 words per capture for a 65,536-record column, 12% slower than
before the reuse with the write watch and 16% slower outside it.

The compare now leaves its words with the snapshotter, and the fresh walk takes them instead of
reading when its plan has the same runs: words the capture has already read read the same again.
Such a capture reads each word once, as before the reuse, and the 65,536-record column costs 7%
(12% outside the write watch) more than before the reuse; the rest is keeping the column. With 16
distinct T#s it costs 5 to 8% less. agc_shader_table_snapshot_reuse expects a changed table to be
read exactly once per capture.
2026-10-15 08:10:51 +00:00
Yunus Shaikh 0431419d16 fix(agc): store pending GPU results before vouching for an unwritten table column
Every read and store through GuestMemory calls the flush hook first. Recorder's FlushForAccess waits
for recorded GPU work over the range, records a queued label that writes it, publishes the unit
shadows over it and stores the storage image results kept on the GPU for it. A storage image result
is stamped only when it is stored (its write-back's MarkWritten), so ShaderMemory's stamp and check,
which never read the column, could vouch for words a read would have replaced: the column skipped
its read and the snapshot kept the T#s from before the result.

stampWrites and unchangedSince now call GuestMemory::FlushGpuWrites over the range after the pending
write query and before the tracker, as a read does, and as the dispatch cache stores pending images
before it validates an entry. The stamp then covers what the flush stored, so the capture after it
skips the read again.

agc_shader_table_snapshot_reuse installs a flush hook that stores a new T# into the table on its first
call over it. Without the flush in unchangedSince the reused snapshot keeps the old T#; without the
one in stampWrites the next capture compares the table instead of skipping its read.
2026-10-15 08:10:51 +00:00
Yunus Shaikh b02c442bbb perf(shader): reuse an image table column's snapshot while its memory is unwritten
Every capture of a shader with an image table read every record of each column and looked each
record up among the snapshot's distinct descriptors. A 32,768-record column of distinct T#s cost
6.1 ms per capture here (2.3 ms with 16 distinct T#s), and Resident Evil Village's title captures
such columns on nearly every draw.

TableSnapshotter now keeps the last 16 column snapshots per thread (at most 4 Mi words in all,
least recently used first out), keyed by heap base and size, record shape and key count: the runs
it read, their words, each record's state and code, and the distinct T#s. A narrowed, selected or
pointer-indirect column, or one with an unmapped record, is not kept. A capture of a kept column
takes the codes and the distinct T#s from it with no per-record work. When they are the snapshot's
first words they are taken as they are, and the words index is built only if a later column needs
it, so the result is the snapshot a fresh walk would produce, codes and words order included.

The runtime gets three optional callbacks: stampWrites gives a stamp for a range before any of it is
read, unchangedSince tells whether nothing wrote the range since, and supplyWords hands words that
equal guest memory to the capture as read, so they stay in the captured regions the draw cache
compares. ShaderMemory implements them with the write tracker. The stamp is CollectWrites's
generation, refused when this ShaderMemory already fetched a page of the range or recorded GPU work
writes it. A range is unchanged while no block of it is stamped after the stamp (collected CPU
stores, the driver's Write, WriteChanged and StoreOwnBytes, MarkWritten for GPU writes into
imports), no recorded GPU work writes it and the guest allocation generation is the stamp's. When
every run is vouched for, the column is not read at all; otherwise its runs are read and the
snapshot is reused only when they are equal word for word.

The 32,768-record column now costs 0.48 ms per capture with no word read when unwritten, and about
0.9 ms outside the write watch. APS5_NO_TABLE_SNAPSHOT_REUSE=1 turns the reuse off. The [image-table]
profile line counts the reuses, and ResourceMaterializer::TableReuse returns them with the words the
snapshotter read.
2026-10-15 08:10:46 +00:00
LeandroLP23andClaude Opus 5.5 79d72b6836 fix(shader): kill demoted quad-mask pixels when the pixel program returns
A pixel that PA_SC_AA_MASK leaves uncovered is demoted to a helper
invocation so the covered pixels keep their derivatives. When the guest
exports under an EXEC mask that clears that lane, the colour output is
never written. On the Radeon 860M (Windows driver 32.0.13058.8001) such
a demoted invocation still writes undefined colour to the target, so
agc_driver_quad_pixel_mask fails at its first implicit-LOD sample under a
partial mask (2). Killing the uncovered invocations at the return, after every
derivative is taken, discards them on every driver.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 10:09:52 +02:00
Adrià db81992c55 Merge pull request #5238 from MarcZX100/fix/trace-draw-program-addresses-5166
feat(agc): trace shader addresses for each draw
2026-10-15 10:06:31 +02:00
Adrià FranchandClaude 290be56265 test(agc): skip the dma-buf import probe when /dev/udmabuf can't be opened
Co-Authored-By: Claude <[email protected]>
2026-10-15 10:05:09 +02:00
Yossi Yadgar 39575d66e9 docs(debt): note which register-defaults table and type layout libSceAgc returns 2026-10-15 11:04:54 +03:00
Adrià FranchandClaude 23fccd7632 fix(agc): settle only imports of 1 MiB or more
Co-Authored-By: Claude <[email protected]>
2026-10-15 09:58:21 +02:00
Josip Parlov 295b1c55f4 fix(agc): drop the import-watch environment switches
The second queue that settles imports is always created on Windows, and a device without one keeps
the comparisons. The other-family settle path is tested through the recorder test device built
with its settle queue on another family (agc_import_watch_other_family) instead of
APS5_SETTLE_OTHER_FAMILY.
2026-10-15 09:46:48 +02:00
Josip Parlov 42178b494d test(agc): a store from another thread within an import window
The settle read keeps a private import's window open for one round trip on the settle queue, so a
store from another thread can land inside it. CheckImportWindowOtherThread: a store of new bytes from
another thread within the window counts as written, and a same-value one keeps its possible CPU
touch. The debt entry notes the longer window.
2026-10-15 09:46:48 +02:00
Adrià FranchandClaude 1ff6ca7a67 docs(architecture): describe settled watched imports of private memory on Windows
Co-Authored-By: Claude <[email protected]>
2026-10-15 09:46:48 +02:00
Josip Parlov 9ba58c2a60 perf(agc): keep Windows host imports of write-watched private memory watched
On Windows a host import without a section alias left guest write tracking, and its changes were
found by comparison. Since resident direct memory became private MEM_WRITE_WATCH memory, its
imports take that path, and every storage-texture refresh over it compares its whole snapshot.

ProbeImportWriteProtection gets a Windows body on MEM_WRITE_WATCH scratch memory, and
decideImportWatch keeps direct imports of private read-write memory watched when GetWriteWatch
stays honest after an import's first GPU use. The driver marks every imported page written until
that use completes, so each such import is settled inside ImportWatched's window by a 4-byte read on
a second queue of the graphics family (the imports lock comes after GpuMutex, so the main queue
cannot be used there). APS5_NO_WATCHED_PRIVATE_IMPORTS=1 keeps the comparisons.
2026-10-15 09:46:48 +02:00
fogydes e088fd8741 fix(libScePlayGo): let users answer unlisted chunks 2026-10-15 11:48:51 +05:30
akkadbakkad89andDevin a7da412a71 fix(libkernel): follow kqueue_register for EV_FORCEONESHOT and modify flags
On a new knote EV_FORCEONESHOT is dropped from the flags; on an
existing one it sets EV_ONESHOT and fires the knote, as
kqueue_register does at l.1339-1341. A modify no longer ORs
EV_ONESHOT, EV_CLEAR or EV_DISPATCH into the knote.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-15 06:01:06 +00:00
akkadbakkad89andDevin b32c5a50cd feat(libkernel): implement kevent EV_DISABLE, EV_DISPATCH and EV_FORCEONESHOT
A knote registered or modified with EV_DISABLE stays registered but is
not polled, fired or reported until an EV_ENABLE change re-arms it, as
kern_event.c does with KN_DISABLED. EV_DISPATCH reports an event once
and then disables the knote, and EV_FORCEONESHOT registers as oneshot.
A negative nevents fails with EINVAL instead of throwing.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-15 06:00:43 +00:00
alfalfa-starandClaude Opus 5.5 56d8b4f68d feat(npmanager): implement sceNpGetUserIdByAccountId
Account id 0 or a null output returns SCE_NP_ERROR_INVALID_ARGUMENT;
otherwise the always signed-out NP returns SCE_NP_ERROR_SIGNED_OUT, as
sceNpGetAccountIdA does. PPSA14632 imports it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 08:00:31 +02:00
JJenkx d94000a096 fix(relinker): load guest providers used by executable imports 2026-10-15 01:40:33 -04:00
Rujul Talekar 3dffc8ca9e fix(libc): give collate<wchar_t> its own 16-bit vtable 2026-10-15 11:07:58 +05:30
David 03c09c4598 docs(debt): record where the uname sysctl strings come from 2026-10-15 08:38:54 +04:00
Celegans12 625525de79 fix(libSceNetCtl): answer the DHCP host name, PPPoE name and proxy server as empty strings
Since #5056, sceNetCtlGetInfo throws for every info code it does not
model. Ghost of Yotei (PPSA26344) asks for code 12, the DHCP host name,
during boot and now aborts one second in.

The configuration #5056 reports (wired, DHCP, HTTP proxy off) sets no
DHCP host name, no PPPoE user name and no proxy server, so codes 12, 13
and 20 now return 0 with an empty string. The Wi-Fi codes (5-10) and
the proxy port (21) still throw. GuestNetCtl checks the three empty
answers and keeps the throw check for the rest; the libSceNetCtl debt
line says the same.
2026-10-15 06:00:49 +02:00
hypermist a4639ad2fb Merge upstream main into perf/vector-window-unindexed-slots 2026-10-15 16:02:16 +13:00
hypermistandClaude Opus 5.5 16914b8fa5 docs(debt): describe the narrowed vector window and its measurement
The relative vector addressing entry still said every window register
lives in one function-scope array. It now describes the array of the
bounded slots, the per-slot variables, the OpSwitch fallback and
APS5_NO_WINDOW_NARROWING, with the RTX 3060 measurement.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uzy15wqYTt6iWyxYXEzUWo
2026-10-15 16:01:41 +13:00
Yunus Shaikh d4b33b0ae8 perf(shader): select the record of a T# whose offset the CPU evaluates
Since #757, a T# loaded from a buffer heap at a runtime offset is an
image table column, and every capture snapshots the whole heap, up to
65,536 records, even when user data or an SRT read fixes the offset.
When the T#'s eight dwords and its offset are runtime values the SRT
walker evaluates, the column is now selected: the offset is kept as a
descriptor source, the shader indexes entry 0, and the snapshot reads
only the record at the evaluated offset, with the heap base moved to
that record.

The column keeps a table's semantics. An invalid T#, an unmapped record
or an offset that carries past 32 bits is poison that faults only when a
lane selects it; an offset the walker cannot read faults the table
instead of throwing; the record's mode is picked per entry, so no
pipeline variant is added; and a dispatch that writes the record faults
it as written by its dispatch. Dwords past the heap read zeros, as the
scalar loads would, and a record past the key cap is read rather than
poisoned.

A column stays a whole table when its offset is chosen per lane, or when
the shader may write the memory the offset is read from at run time: the
buffer it is read from (by V#), or any memory when the read or a write
goes through a pointer or a GPU-only descriptor. Samplers are unchanged:
an S# the walker evaluates is already a direct sampler. The plan stores
the selection, so the disk cache format is 36.

Five agc_shader_memory and agc_shader_bindless checks asserted the old
planning and now assert the selected record:
- "image table SRT key": a key read through the SRT narrowed a 4-key
  table to records 0 and 2. It now selects record 2 alone, captures no
  other record, and a changed key moves the capture without changing the
  module or its disk key.
- "image table key union" and "image table late key": two keys of one
  heap shared one column with two value key domains. Each key now
  selects its own record, as two one-record tables.
- "image table unkeyed access": a read keyed through the SRT shared a
  whole column with a read keyed per lane. The first now selects its
  record; the second keeps the whole, unnarrowed table.
- "uniform table image": the T# at a user data offset was one key of a
  full table. It is now the one selected record, and the record the user
  data does not select is not read.
A value key domain only arises for a key the walker evaluates, so it no
longer narrows an image column; key buffer domains (keys loaded per
lane) still do.
2026-10-15 02:48:55 +00:00
Dean a077a88df5 Merge pull request #5139 from Kikoarl/feat/ngs2-custom-module-user-fx
feat(ngs2): support custom submixer rack UserFx module 0x1d
2026-10-15 15:34:22 +13:00
Bruce Blake b6c9bd7f33 feat(libkernel): implement getdtablesize
Return the RLIMIT_NOFILE soft limit that getrlimit reports, capped at INT_MAX: FreeBSD sys_getdtablesize returns the smaller of that limit and maxfilesperproc, and the guest limit never exceeds the hard limit that bounds it here. The guest test now asserts the value instead of the throw, and the debt entry records the semantics.
2026-10-14 22:24:10 -04:00
SandstromPLandClaude Opus 5.5 4ef2af62ea fix(agc): rasterize a multisampled depth target without MSAA_ENABLE at the pixel center
A draw with PA_SC_AA_CONFIG.MSAA_NUM_SAMPLES 2 (4x) and MSAA_ENABLE
clear into a 4x depth/stencil and color pair threw "multisampled
targets rasterized without MSAA_ENABLE are unsupported for points,
lines, a depth target or alpha-to-coverage", which stops METAL GEAR
SOLID: Peace Walker (PPSA18216) at its first presentation (draw B on
#5268). A depth target with the same sample count now gets the same
pixel center samples as the color targets, so each depth and stencil
sample is tested and written with the depth at the pixel center, as GL
allows when multisampling is disabled.

DB_EQAA Z interpolation or overrasterization and a sample-mask export
with a depth target throw on this path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 07:11:46 +05:30